Index: include/sanitizer/common_interface_defs.h =================================================================== --- include/sanitizer/common_interface_defs.h +++ include/sanitizer/common_interface_defs.h @@ -182,6 +182,13 @@ void __sanitizer_finish_switch_fiber(void *fake_stack_save, const void **bottom_old, size_t *size_old); + + // Get full module name and calculate pc offset within it. + // Returns 1 if pc belongs to some module, 0 if module was not found. + int __sanitizer_get_module_and_offset_for_pc(void *pc, char *module_path, + size_t module_path_len, + void **pc_offset); + #ifdef __cplusplus } // extern "C" #endif Index: lib/asan/asan_win_dll_thunk.cc =================================================================== --- lib/asan/asan_win_dll_thunk.cc +++ lib/asan/asan_win_dll_thunk.cc @@ -366,6 +366,7 @@ INTERFACE_FUNCTION(__sanitizer_install_malloc_and_free_hooks) INTERFACE_FUNCTION(__sanitizer_start_switch_fiber) INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber) +INTERFACE_FUNCTION(__sanitizer_get_module_and_offset_for_pc) // TODO(timurrrr): Add more interface functions on the as-needed basis. Index: lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc +++ lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc @@ -82,6 +82,22 @@ } } +static int GetModuleAndOffsetForPc(uptr pc, char *module_name, + uptr module_name_len, uptr *pc_offset) { + const char *found_module_name = nullptr; + bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC( + pc, &found_module_name, pc_offset); + + if (!ok) return false; + + if (module_name && module_name_len) { + internal_strncpy(module_name, found_module_name, module_name_len); + module_name[module_name_len - 1] = '\x00'; + } + return true; +} + + } // namespace __sanitizer using namespace __sanitizer; @@ -117,4 +133,14 @@ internal_strncpy(out_buf, data_desc.data(), out_buf_size); out_buf[out_buf_size - 1] = 0; } + +SANITIZER_INTERFACE_ATTRIBUTE int +__sanitizer_get_module_and_offset_for_pc(void *pc, // NOLINT + char *module_name, + uptr module_name_len, + void **pc_offset) { + return __sanitizer::GetModuleAndOffsetForPc( + reinterpret_cast(pc), module_name, module_name_len, + reinterpret_cast(pc_offset)); +} } // extern "C" Index: lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -55,7 +55,7 @@ // own demangler (libc++abi's implementation could be adapted so that // it does not allocate). For now, we just call it anyway, and we leak // the returned value. - if (__cxxabiv1::__cxa_demangle) + if (&__cxxabiv1::__cxa_demangle) if (const char *demangled_name = __cxxabiv1::__cxa_demangle(name, 0, 0, 0)) return demangled_name; Index: test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc =================================================================== --- /dev/null +++ test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc @@ -0,0 +1,63 @@ +// RUN: %clangxx -DSHARED %s -shared -o %T/get_module_and_offset_for_pc.so -fPIC +// RUN: %clangxx -DSO_DIR=\"%T\" -O0 %s -ldl -o %t +// RUN: %run %t 2>&1 | FileCheck %s +// UNSUPPORTED: i386-darwin +// +// Tests __sanitizer_get_module_and_offset_for_pc. + +#include +#include +#include +#include + +#ifdef SHARED +extern "C" { +int foo() { return 1; } +} +#else + +void Test(void *pc, const char *name) { + char module_name[1024]; + void *offset; + int ok = __sanitizer_get_module_and_offset_for_pc( + pc, module_name, sizeof(module_name), &offset); + if (!ok) { + printf("NOT FOUND %s: %p\n", name, pc); + } else { + printf("FOUND %s: %s %p\n", name, module_name, offset); + } +} + +void TestCallerPc() { Test(__builtin_return_address(0), "callerpc"); } + +void TestDlsym() { + void *handle = dlopen(SO_DIR "/get_module_and_offset_for_pc.so", RTLD_LAZY); + assert(handle); + void *foo = dlsym(handle, "foo"); + assert(foo); + Test(foo, "foo"); + dlclose(handle); +} + +// Call __sanitizer_get_module_and_offset_for_pc lots of times +// to make sure it is not too slow. +void TestLoop() { + void *pc = __builtin_return_address(0); + char module_name[1024]; + void *offset; + for (int i = 0; i < 1000000; ++i) { + __sanitizer_get_module_and_offset_for_pc(pc, module_name, + sizeof(module_name), &offset); + } +} + +int main() { + Test(0, "null"); + TestCallerPc(); + TestDlsym(); + TestLoop(); +} +#endif +// CHECK: NOT FOUND null: (nil) +// CHECK-NEXT: FOUND callerpc: {{.*}}/get_module_and_offset_for_pc.cc.tmp {{.*}} +// CHECK-NEXT: FOUND foo: {{.*}}/get_module_and_offset_for_pc.so {{.*}}