[asan] Add %d variable to external_symbolizer_path option, so that user can specify paths relative to the location of the binary.

We want way to set a path to llvm-symbolizer that isn't relative
to the current working directory; this change adds a variable that
expands to the path relative to the current binary.
This approach came from comments in https://reviews.llvm.org/D93070

Differential Revision: https://reviews.llvm.org/D94563
This commit is contained in:
Amy Huang 2021-01-12 15:06:19 -08:00
parent e21adfa32d
commit 9ba623c655
8 changed files with 78 additions and 8 deletions

View File

@ -274,6 +274,14 @@ uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
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();

View File

@ -248,6 +248,7 @@ const char *StripModuleName(const char *module);
// 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();

View File

@ -35,6 +35,7 @@ void CommonFlags::CopyFrom(const CommonFlags &other) {
// 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,12 @@ void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
s += 2; // skip "%p"
break;
}
case 'd': {
uptr len = ReadBinaryDir(out, out_end - out);
out += len;
s += 2; // skip "%d"
break;
}
default:
*out++ = *s++;
break;

View File

@ -400,6 +400,13 @@ const char *Symbolizer::PlatformDemangle(const char *name) {
static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
const char *path = common_flags()->external_symbolizer_path;
if (path && internal_strchr(path, '%')) {
char *new_path = (char *)InternalAlloc(kMaxPathLength);
SubstituteForFlagValue(path, new_path, kMaxPathLength);
path = new_path;
}
const char *binary_name = path ? StripModuleName(path) : "";
if (path && path[0] == '\0') {
VReport(2, "External symbolizer is explicitly disabled.\n");

View File

@ -288,8 +288,15 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
return;
}
// Add llvm-symbolizer in case the binary has dwarf.
// Add llvm-symbolizer.
const char *user_path = common_flags()->external_symbolizer_path;
if (user_path && internal_strchr(user_path, '%')) {
char *new_path = (char *)InternalAlloc(kMaxPathLength);
SubstituteForFlagValue(user_path, new_path, kMaxPathLength);
user_path = new_path;
}
const char *path =
user_path ? user_path : FindPathToBinary("llvm-symbolizer.exe");
if (path) {

View File

@ -1049,10 +1049,23 @@ const char *SignalContext::Describe() const {
}
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
// FIXME: Actually implement this function.
CHECK_GT(buf_len, 0);
buf[0] = 0;
return 0;
if (buf_len == 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, ARRAY_SIZE(binname_utf16));
if (binname_utf16_len == 0) {
buf[0] = '\0';
return 0;
}
int binary_name_len = ::WideCharToMultiByte(
CP_UTF8, 0, binname_utf16, binname_utf16_len, buf, buf_len, NULL, NULL);
if ((unsigned)binary_name_len == buf_len)
--binary_name_len;
buf[binary_name_len] = '\0';
return binary_name_len;
}
uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) {

View File

@ -461,12 +461,9 @@ TEST(SanitizerCommon, ReservedAddressRangeUnmap) {
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

View File

@ -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 <sanitizer/common_interface_defs.h>
#include <stdio.h>
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();
}