Index: include/sanitizer/common_interface_defs.h =================================================================== --- include/sanitizer/common_interface_defs.h +++ include/sanitizer/common_interface_defs.h @@ -182,6 +182,12 @@ 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_common.h =================================================================== --- lib/sanitizer_common/sanitizer_common.h +++ lib/sanitizer_common/sanitizer_common.h @@ -709,6 +709,8 @@ static const uptr kInitialCapacity = 1 << 14; }; + + // Callback type for iterating over a set of memory ranges. typedef void (*RangeIteratorCallback)(uptr begin, uptr end, void *arg); Index: lib/sanitizer_common/sanitizer_common_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_common_libcdep.cc +++ lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -169,6 +169,23 @@ #endif } +static int GetModuleAndOffsetForPc(uptr pc, char *module_name, + uptr module_name_len, uptr* pc_offset) { + ListOfModules modules; + modules.init(); + + const char *found_module_name = nullptr; + bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC( + pc, &found_module_name, pc_offset); + + if (!ok) + return false; + + internal_strncpy(module_name, found_module_name, module_name_len); + return true; +} + + } // namespace __sanitizer void NOINLINE @@ -177,3 +194,12 @@ if (__sanitizer::sandboxing_callback) __sanitizer::sandboxing_callback(); } + +extern "C" 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)); +} + 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,30 @@ +// RUN: %clangxx -v -O0 %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s +// UNSUPPORTED: i386-darwin +// +// Tests __sanitizer_get_module_and_offset_for_pc. +#include +#include + +void Test(void* pc) { + 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: %p\n", pc); + } else { + printf("FOUND: %s %p\n", module_name, offset); + } +} + +void TestCallerPc() { + Test(__builtin_return_address(0)); +} + +int main() { + Test(0); + TestCallerPc(); +} +// CHECK: NOT FOUND: (nil) +// CHECK-NEXT: FOUND: {{.*}}/get_module_and_offset_for_pc.cc.tmp