diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -248,6 +248,7 @@ // OS uptr ReadBinaryName(/*out*/char *buf, uptr buf_len); uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len); +uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len); uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len); const char *GetProcessName(); void UpdateProcessName(); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp @@ -274,6 +274,14 @@ return name_len; } +uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len) { + ReadBinaryNameCached(buf, buf_len); + const char *exec_name_pos = StripModuleName(buf); + uptr name_len = exec_name_pos - buf; + buf[name_len] = '\0'; + return name_len; +} + #if !SANITIZER_GO void PrintCmdline() { char **argv = GetArgv(); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_flags.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.cpp @@ -35,6 +35,7 @@ // Copy the string from "s" to "out", making the following substitutions: // %b = binary basename // %p = pid +// %d = binary directory void SubstituteForFlagValue(const char *s, char *out, uptr out_size) { char *out_end = out + out_size; while (*s && out < out_end - 1) { @@ -64,6 +65,17 @@ s += 2; // skip "%p" break; } + case 'd': { + InternalScopedString buf(kMaxPathLength); + uptr len = ReadBinaryDir(buf.data(), kMaxPathLength); + uptr i = 0; + while (i < len - 1 && out < out_end - 1) { + *out++ = buf[i]; + ++i; + } + s += 2; // skip "%d" + break; + } default: *out++ = *s++; break; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp @@ -400,6 +400,13 @@ static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) { const char *path = common_flags()->external_symbolizer_path; + + if (path && path[0] == '%') { + InternalScopedString buf(kMaxPathLength); + SubstituteForFlagValue(path, buf.data(), kMaxPathLength); + path = internal_strdup(buf.data()); + } + const char *binary_name = path ? StripModuleName(path) : ""; if (path && path[0] == '\0') { VReport(2, "External symbolizer is explicitly disabled.\n"); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp @@ -288,8 +288,15 @@ return; } - // Add llvm-symbolizer in case the binary has dwarf. + // Add llvm-symbolizer. const char *user_path = common_flags()->external_symbolizer_path; + + if (path && path[0] == '%') { + InternalScopedString buf(kMaxPathLength); + SubstituteForFlagValue(path, buf.data(), kMaxPathLength); + path = internal_strdup(buf.data()); + } + const char *path = user_path ? user_path : FindPathToBinary("llvm-symbolizer.exe"); if (path) { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp @@ -1049,10 +1049,16 @@ } uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { - // FIXME: Actually implement this function. - CHECK_GT(buf_len, 0); - buf[0] = 0; - return 0; + // Get the UTF-16 path and convert to UTF-8. + wchar_t binname_utf16[kMaxPathLength]; + int binname_utf16_len = + GetModuleFileNameW(NULL, binname_utf16, kMaxPathLength); + if (binname_utf16_len == 0) + binname_utf16[0] = '\0'; + int binary_name_len = + ::WideCharToMultiByte(CP_UTF8, 0, binname_utf16, binname_utf16_len + 1, + &buf[0], kMaxPathLength, NULL, NULL); + return binary_name_len; } uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_common_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_common_test.cpp --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_common_test.cpp +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_common_test.cpp @@ -461,12 +461,9 @@ EXPECT_DEATH(address_range.Unmap(base_addr + (PageSize * 2), PageSize), ".*"); } -// Windows has no working ReadBinaryName. -#if !SANITIZER_WINDOWS TEST(SanitizerCommon, ReadBinaryNameCached) { char buf[256]; EXPECT_NE((uptr)0, ReadBinaryNameCached(buf, sizeof(buf))); } -#endif } // namespace __sanitizer diff --git a/compiler-rt/test/sanitizer_common/TestCases/external_symbolizer_path.cpp b/compiler-rt/test/sanitizer_common/TestCases/external_symbolizer_path.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/external_symbolizer_path.cpp @@ -0,0 +1,30 @@ +// REQUIRES: shell +// RUN: rm -rf %t.bin +// RUN: mkdir %t.bin +// RUN: cp $(which llvm-symbolizer) %t.bin +// RUN: rm -rf %t.dir +// RUN: mkdir %t.dir +// RUN: %clangxx -O0 %s -o %t && cd %t.dir +// RUN: %env_tool_opts=external_symbolizer_path=%d/external_symbolizer_path.cpp.tmp.bin/llvm-symbolizer \ +// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=FOUND +// RUN: rm -rf %t.bin/llvm-symbolizer +// RUN: cd .. +// RUN: %clangxx -O0 %s -o %t && cd %t.dir +// RUN: %env_tool_opts=external_symbolizer_path=%d/external_symbolizer_path.cpp.tmp.bin/llvm-symbolizer \ +// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=NOT-FOUND + +#include +#include + +static void Symbolize() { + char buffer[100]; + __sanitizer_symbolize_pc(__builtin_return_address(0), "%p %F %L", buffer, + sizeof(buffer)); + printf("%s\n", buffer); +} + +int main() { + // FOUND: {{0x.* in main}} + // NOT-FOUND: WARNING: invalid path to external symbolizer! + Symbolize(); +}