forked from OSchip/llvm-project
[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:
parent
a2c1c7a78e
commit
e29c6731aa
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue