[Sanitizer/ASan] Simplify the code that prints and symbolizes stack traces. Fall back to module+offset if user-provided symbolizer failed. Use weak function __asan_symbolize instead of __asan_set_symbolize_callback in ASan interface, so that we're able to symbolize reports for errors that happen before the main() is called, for example, during module initialization.

llvm-svn: 165000
This commit is contained in:
Alexey Samsonov 2012-10-02 12:11:17 +00:00
parent a2c1c7a78e
commit e29c6731aa
7 changed files with 109 additions and 92 deletions

View File

@ -135,15 +135,13 @@ extern "C" {
void __asan_set_on_error_callback(void (*callback)(void))
SANITIZER_INTERFACE_ATTRIBUTE;
// User may register its own symbolization function. It should print
// the description of instruction at address "pc" to "out_buffer".
// Description should be at most "out_size" bytes long.
// User may provide its own implementation for symbolization function.
// It should print the description of instruction at address "pc" to
// "out_buffer". Description should be at most "out_size" bytes long.
// User-specified function should return true if symbolization was
// successful.
typedef bool (*__asan_symbolize_callback)(const void *pc, char *out_buffer,
int out_size);
void __asan_set_symbolize_callback(__asan_symbolize_callback callback)
SANITIZER_INTERFACE_ATTRIBUTE;
bool __asan_symbolize(const void *pc, char *out_buffer, int out_size)
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
// Returns the estimated number of bytes that will be reserved by allocator
// for request of "size" bytes. If ASan allocator can't allocate that much

View File

@ -149,10 +149,6 @@ extern int asan_inited;
extern bool asan_init_is_running;
extern void (*death_callback)(void);
#ifdef _WIN32
bool WinSymbolize(const void *addr, char *out_buffer, int buffer_size);
#endif // _WIN32
// These magic values are written to shadow for better error reporting.
const int kAsanHeapLeftRedzoneMagic = 0xfa;
const int kAsanHeapRightRedzoneMagic = 0xfb;

View File

@ -247,7 +247,7 @@ static NOINLINE void force_interface_symbols() {
case 33: __asan_after_dynamic_init(); break;
case 34: __asan_malloc_hook(0, 0); break;
case 35: __asan_free_hook(0); break;
case 36: __asan_set_symbolize_callback(0); break;
case 36: __asan_symbolize(0, 0, 0); break;
}
}
@ -376,9 +376,6 @@ void __asan_init() {
InitializeExternalSymbolizer(external_symbolizer);
}
}
#ifdef _WIN32
__asan_set_symbolize_callback(WinSymbolize);
#endif // _WIN32
// On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
// should be set to 1 prior to initializing the threads.

View File

@ -17,20 +17,21 @@
namespace __asan {
static __asan_symbolize_callback symbolize_callback;
void PrintStack(StackTrace *stack) {
stack->PrintStack(stack->trace, stack->size, flags()->symbolize,
flags()->strip_path_prefix, symbolize_callback);
flags()->strip_path_prefix, __asan_symbolize);
}
} // namespace __asan
// ------------------ Interface -------------- {{{1
using namespace __asan; // NOLINT
void NOINLINE __asan_set_symbolize_callback(
__asan_symbolize_callback callback) {
symbolize_callback = callback;
// Provide default implementation of __asan_symbolize that does nothing
// and may be overriden by user if he wants to use his own symbolization.
// ASan on Windows has its own implementation of this.
#ifndef _WIN32
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE NOINLINE
bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) {
return false;
}
#endif

View File

@ -55,47 +55,6 @@ void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp) {
stack->trace[i] = (uptr)tmp[i + offset];
}
bool WinSymbolize(const void *addr, char *out_buffer, int buffer_size) {
ScopedLock lock(&dbghelp_lock);
if (!dbghelp_initialized) {
SymSetOptions(SYMOPT_DEFERRED_LOADS |
SYMOPT_UNDNAME |
SYMOPT_LOAD_LINES);
CHECK(SymInitialize(GetCurrentProcess(), 0, TRUE));
// FIXME: We don't call SymCleanup() on exit yet - should we?
dbghelp_initialized = true;
}
// See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
DWORD64 offset = 0;
BOOL got_objname = SymFromAddr(GetCurrentProcess(),
(DWORD64)addr, &offset, symbol);
if (!got_objname)
return false;
DWORD unused;
IMAGEHLP_LINE64 info;
info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(),
(DWORD64)addr, &unused, &info);
int written = 0;
out_buffer[0] = '\0';
// FIXME: it might be useful to print out 'obj' or 'obj+offset' info too.
if (got_fileline) {
written += internal_snprintf(out_buffer + written, buffer_size - written,
" %s %s:%d", symbol->Name,
info.FileName, info.LineNumber);
} else {
written += internal_snprintf(out_buffer + written, buffer_size - written,
" %s+0x%p", symbol->Name, offset);
}
return true;
}
// ---------------------- AsanLock ---------------- {{{1
enum LockState {
LOCK_UNINITIALIZED = 0,
@ -182,4 +141,50 @@ void AsanPlatformThreadInit() {
} // namespace __asan
// ---------------------- Interface ---------------- {{{1
using namespace __asan; // NOLINT
bool __asan_symbolize(const void *addr, char *out_buffer, int buffer_size) {
ScopedLock lock(&dbghelp_lock);
if (!dbghelp_initialized) {
SymSetOptions(SYMOPT_DEFERRED_LOADS |
SYMOPT_UNDNAME |
SYMOPT_LOAD_LINES);
CHECK(SymInitialize(GetCurrentProcess(), 0, TRUE));
// FIXME: We don't call SymCleanup() on exit yet - should we?
dbghelp_initialized = true;
}
// See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
DWORD64 offset = 0;
BOOL got_objname = SymFromAddr(GetCurrentProcess(),
(DWORD64)addr, &offset, symbol);
if (!got_objname)
return false;
DWORD unused;
IMAGEHLP_LINE64 info;
info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(),
(DWORD64)addr, &unused, &info);
int written = 0;
out_buffer[0] = '\0';
// FIXME: it might be useful to print out 'obj' or 'obj+offset' info too.
if (got_fileline) {
written += internal_snprintf(out_buffer + written, buffer_size - written,
" %s %s:%d", symbol->Name,
info.FileName, info.LineNumber);
} else {
written += internal_snprintf(out_buffer + written, buffer_size - written,
" %s+0x%p", symbol->Name, offset);
}
return true;
}
#endif // _WIN32

View File

@ -3,17 +3,13 @@
#include <stdio.h>
#include <stdlib.h>
bool MySymbolizer(const void *pc, char *out_buffer, int out_size) {
extern "C"
bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) {
snprintf(out_buffer, out_size, "MySymbolizer");
return true;
}
typedef bool (*asan_symbolize_callback)(const void*, char*, int);
extern "C"
void __asan_set_symbolize_callback(asan_symbolize_callback);
int main() {
__asan_set_symbolize_callback(MySymbolizer);
char *x = (char*)malloc(10 * sizeof(char));
free(x);
return x[5];

View File

@ -36,6 +36,26 @@ static uptr patch_pc(uptr pc) {
return pc - 1;
}
static void PrintStackFramePrefix(uptr frame_num, uptr pc) {
Printf(" #%zu 0x%zx", frame_num, pc);
}
static void PrintSourceLocation(const char *file, int line, int column,
const char *strip_file_prefix) {
CHECK(file);
Printf(" %s", StripPathPrefix(file, strip_file_prefix));
if (line > 0) {
Printf(":%d", line);
if (column > 0)
Printf(":%d", column);
}
}
static void PrintModuleAndOffset(const char *module, uptr offset,
const char *strip_file_prefix) {
Printf(" (%s+0x%zx)", StripPathPrefix(module, strip_file_prefix), offset);
}
void StackTrace::PrintStack(const uptr *addr, uptr size,
bool symbolize, const char *strip_file_prefix,
SymbolizeCallback symbolize_callback ) {
@ -45,45 +65,49 @@ void StackTrace::PrintStack(const uptr *addr, uptr size,
uptr frame_num = 0;
for (uptr i = 0; i < size && addr[i]; i++) {
uptr pc = patch_pc(addr[i]);
uptr addr_frames_num = 0; // The number of stack frames for current
// instruction address.
if (symbolize_callback) {
symbolize_callback((void*)pc, buff.data(), buff.size());
// We can't know anything about the string returned by external
// symbolizer, but if it starts with filename, try to strip path prefix
// from it.
Printf(" #%zu 0x%zx %s\n", frame_num, pc,
StripPathPrefix(buff.data(), strip_file_prefix));
frame_num++;
continue;
}
uptr addr_frames_num =
symbolize ? SymbolizeCode(pc, addr_frames.data(), addr_frames.size()) : 0;
if (addr_frames_num > 0) {
if (symbolize_callback((void*)pc, buff.data(), buff.size())) {
addr_frames_num = 1;
PrintStackFramePrefix(frame_num, pc);
// We can't know anything about the string returned by external
// symbolizer, but if it starts with filename, try to strip path prefix
// from it.
Printf(" %s\n", StripPathPrefix(buff.data(), strip_file_prefix));
frame_num++;
}
} else if (symbolize) {
// Use our own (online) symbolizer, if necessary.
addr_frames_num = SymbolizeCode(pc, addr_frames.data(), addr_frames.size());
for (uptr j = 0; j < addr_frames_num; j++) {
AddressInfo &info = addr_frames[j];
Printf(" #%zu 0x%zx", frame_num, pc);
PrintStackFramePrefix(frame_num, pc);
if (info.function) {
Printf(" in %s", info.function);
}
if (info.file) {
Printf(" %s:%d:%d", StripPathPrefix(info.file, strip_file_prefix),
info.line, info.column);
PrintSourceLocation(info.file, info.line, info.column,
strip_file_prefix);
} else if (info.module) {
Printf(" (%s+0x%zx)", StripPathPrefix(info.module, strip_file_prefix),
info.module_offset);
PrintModuleAndOffset(info.module, info.module_offset,
strip_file_prefix);
}
Printf("\n");
info.Clear();
frame_num++;
}
} else {
}
if (addr_frames_num == 0) {
// If online symbolization failed, try to output at least module and
// offset for instruction.
PrintStackFramePrefix(frame_num, pc);
uptr offset;
if (proc_maps.GetObjectNameAndOffset(pc, &offset,
buff.data(), buff.size())) {
Printf(" #%zu 0x%zx (%s+0x%zx)\n", frame_num, pc,
StripPathPrefix(buff.data(), strip_file_prefix), offset);
} else {
Printf(" #%zu 0x%zx\n", frame_num, pc);
PrintModuleAndOffset(buff.data(), offset, strip_file_prefix);
}
Printf("\n");
frame_num++;
}
}