[sanitizers] include build ids in stacks on linux.
Reviewed By: eugenis Differential Revision: https://reviews.llvm.org/D114294
This commit is contained in:
parent
dcd6162b7f
commit
2a31b240df
|
|
@ -138,9 +138,17 @@ void LoadedModule::set(const char *module_name, uptr base_address,
|
||||||
set(module_name, base_address);
|
set(module_name, base_address);
|
||||||
arch_ = arch;
|
arch_ = arch;
|
||||||
internal_memcpy(uuid_, uuid, sizeof(uuid_));
|
internal_memcpy(uuid_, uuid, sizeof(uuid_));
|
||||||
|
uuid_size_ = kModuleUUIDSize;
|
||||||
instrumented_ = instrumented;
|
instrumented_ = instrumented;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LoadedModule::setUuid(const char *uuid, uptr size) {
|
||||||
|
if (size > kModuleUUIDSize)
|
||||||
|
size = kModuleUUIDSize;
|
||||||
|
internal_memcpy(uuid_, uuid, size);
|
||||||
|
uuid_size_ = size;
|
||||||
|
}
|
||||||
|
|
||||||
void LoadedModule::clear() {
|
void LoadedModule::clear() {
|
||||||
InternalFree(full_name_);
|
InternalFree(full_name_);
|
||||||
base_address_ = 0;
|
base_address_ = 0;
|
||||||
|
|
|
||||||
|
|
@ -770,7 +770,7 @@ inline const char *ModuleArchToString(ModuleArch arch) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
const uptr kModuleUUIDSize = 16;
|
const uptr kModuleUUIDSize = 32;
|
||||||
const uptr kMaxSegName = 16;
|
const uptr kMaxSegName = 16;
|
||||||
|
|
||||||
// Represents a binary loaded into virtual memory (e.g. this can be an
|
// Represents a binary loaded into virtual memory (e.g. this can be an
|
||||||
|
|
@ -782,6 +782,7 @@ class LoadedModule {
|
||||||
base_address_(0),
|
base_address_(0),
|
||||||
max_executable_address_(0),
|
max_executable_address_(0),
|
||||||
arch_(kModuleArchUnknown),
|
arch_(kModuleArchUnknown),
|
||||||
|
uuid_size_(0),
|
||||||
instrumented_(false) {
|
instrumented_(false) {
|
||||||
internal_memset(uuid_, 0, kModuleUUIDSize);
|
internal_memset(uuid_, 0, kModuleUUIDSize);
|
||||||
ranges_.clear();
|
ranges_.clear();
|
||||||
|
|
@ -789,6 +790,7 @@ class LoadedModule {
|
||||||
void set(const char *module_name, uptr base_address);
|
void set(const char *module_name, uptr base_address);
|
||||||
void set(const char *module_name, uptr base_address, ModuleArch arch,
|
void set(const char *module_name, uptr base_address, ModuleArch arch,
|
||||||
u8 uuid[kModuleUUIDSize], bool instrumented);
|
u8 uuid[kModuleUUIDSize], bool instrumented);
|
||||||
|
void setUuid(const char *uuid, uptr size);
|
||||||
void clear();
|
void clear();
|
||||||
void addAddressRange(uptr beg, uptr end, bool executable, bool writable,
|
void addAddressRange(uptr beg, uptr end, bool executable, bool writable,
|
||||||
const char *name = nullptr);
|
const char *name = nullptr);
|
||||||
|
|
@ -799,6 +801,7 @@ class LoadedModule {
|
||||||
uptr max_executable_address() const { return max_executable_address_; }
|
uptr max_executable_address() const { return max_executable_address_; }
|
||||||
ModuleArch arch() const { return arch_; }
|
ModuleArch arch() const { return arch_; }
|
||||||
const u8 *uuid() const { return uuid_; }
|
const u8 *uuid() const { return uuid_; }
|
||||||
|
uptr uuid_size() const { return uuid_size_; }
|
||||||
bool instrumented() const { return instrumented_; }
|
bool instrumented() const { return instrumented_; }
|
||||||
|
|
||||||
struct AddressRange {
|
struct AddressRange {
|
||||||
|
|
@ -827,6 +830,7 @@ class LoadedModule {
|
||||||
uptr base_address_;
|
uptr base_address_;
|
||||||
uptr max_executable_address_;
|
uptr max_executable_address_;
|
||||||
ModuleArch arch_;
|
ModuleArch arch_;
|
||||||
|
uptr uuid_size_;
|
||||||
u8 uuid_[kModuleUUIDSize];
|
u8 uuid_[kModuleUUIDSize];
|
||||||
bool instrumented_;
|
bool instrumented_;
|
||||||
IntrusiveList<AddressRange> ranges_;
|
IntrusiveList<AddressRange> ranges_;
|
||||||
|
|
|
||||||
|
|
@ -603,6 +603,32 @@ static int AddModuleSegments(const char *module_name, dl_phdr_info *info,
|
||||||
bool writable = phdr->p_flags & PF_W;
|
bool writable = phdr->p_flags & PF_W;
|
||||||
cur_module.addAddressRange(cur_beg, cur_end, executable,
|
cur_module.addAddressRange(cur_beg, cur_end, executable,
|
||||||
writable);
|
writable);
|
||||||
|
} else if (phdr->p_type == PT_NOTE) {
|
||||||
|
uptr off = 0;
|
||||||
|
while (off < phdr->p_memsz - sizeof(ElfW(Nhdr))) {
|
||||||
|
auto *nhdr = reinterpret_cast<const ElfW(Nhdr) *>(info->dlpi_addr +
|
||||||
|
phdr->p_vaddr + off);
|
||||||
|
constexpr auto kGnuNamesz = 4; // "GNU" with NUL-byte.
|
||||||
|
static_assert(kGnuNamesz % 4 == 0, "kGnuNameSize is aligned to 4.");
|
||||||
|
if (nhdr->n_type == NT_GNU_BUILD_ID && nhdr->n_namesz == kGnuNamesz) {
|
||||||
|
if (off + sizeof(ElfW(Nhdr)) + nhdr->n_namesz + nhdr->n_descsz >
|
||||||
|
phdr->p_memsz) {
|
||||||
|
// Something is very wrong, bail out instead of reading potentially
|
||||||
|
// arbitrary memory.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const char *name =
|
||||||
|
reinterpret_cast<const char *>(nhdr) + sizeof(*nhdr);
|
||||||
|
if (internal_memcmp(name, "GNU", 3) == 0) {
|
||||||
|
const char *value = reinterpret_cast<const char *>(nhdr) +
|
||||||
|
sizeof(*nhdr) + kGnuNamesz;
|
||||||
|
cur_module.setUuid(value, nhdr->n_descsz);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
off += sizeof(*nhdr) + RoundUpTo(nhdr->n_namesz, 4) +
|
||||||
|
RoundUpTo(nhdr->n_descsz, 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
modules->push_back(cur_module);
|
modules->push_back(cur_module);
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,19 @@ static const char *DemangleFunctionName(const char *function) {
|
||||||
return function;
|
return function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void MaybeBuildIdToBuffer(const AddressInfo &info, bool PrefixSpace,
|
||||||
|
InternalScopedString *buffer) {
|
||||||
|
if (info.uuid_size) {
|
||||||
|
if (PrefixSpace)
|
||||||
|
buffer->append(" ");
|
||||||
|
buffer->append("(BuildId: ");
|
||||||
|
for (uptr i = 0; i < info.uuid_size; ++i) {
|
||||||
|
buffer->append("%02x", info.uuid[i]);
|
||||||
|
}
|
||||||
|
buffer->append(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const char kDefaultFormat[] = " #%n %p %F %L";
|
static const char kDefaultFormat[] = " #%n %p %F %L";
|
||||||
|
|
||||||
void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
|
void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
|
||||||
|
|
@ -140,6 +153,9 @@ void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
|
||||||
case 'o':
|
case 'o':
|
||||||
buffer->append("0x%zx", info->module_offset);
|
buffer->append("0x%zx", info->module_offset);
|
||||||
break;
|
break;
|
||||||
|
case 'b':
|
||||||
|
MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/false, buffer);
|
||||||
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
buffer->append("%s", DemangleFunctionName(StripFunctionName(
|
buffer->append("%s", DemangleFunctionName(StripFunctionName(
|
||||||
info->function, strip_func_prefix)));
|
info->function, strip_func_prefix)));
|
||||||
|
|
@ -181,6 +197,8 @@ void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
|
||||||
} else if (info->module) {
|
} else if (info->module) {
|
||||||
RenderModuleLocation(buffer, info->module, info->module_offset,
|
RenderModuleLocation(buffer, info->module, info->module_offset,
|
||||||
info->module_arch, strip_path_prefix);
|
info->module_arch, strip_path_prefix);
|
||||||
|
|
||||||
|
MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/true, buffer);
|
||||||
} else {
|
} else {
|
||||||
buffer->append("(<unknown module>)");
|
buffer->append("(<unknown module>)");
|
||||||
}
|
}
|
||||||
|
|
@ -193,6 +211,7 @@ void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
|
||||||
// Always strip the module name for %M.
|
// Always strip the module name for %M.
|
||||||
RenderModuleLocation(buffer, StripModuleName(info->module),
|
RenderModuleLocation(buffer, StripModuleName(info->module),
|
||||||
info->module_offset, info->module_arch, "");
|
info->module_offset, info->module_arch, "");
|
||||||
|
MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/true, buffer);
|
||||||
} else {
|
} else {
|
||||||
buffer->append("(%p)", (void *)address);
|
buffer->append("(%p)", (void *)address);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,11 @@
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "sanitizer_allocator_internal.h"
|
#include "sanitizer_allocator_internal.h"
|
||||||
#include "sanitizer_platform.h"
|
#include "sanitizer_common.h"
|
||||||
#include "sanitizer_internal_defs.h"
|
#include "sanitizer_internal_defs.h"
|
||||||
#include "sanitizer_libc.h"
|
#include "sanitizer_libc.h"
|
||||||
#include "sanitizer_placement_new.h"
|
#include "sanitizer_placement_new.h"
|
||||||
|
#include "sanitizer_platform.h"
|
||||||
#include "sanitizer_symbolizer_internal.h"
|
#include "sanitizer_symbolizer_internal.h"
|
||||||
|
|
||||||
namespace __sanitizer {
|
namespace __sanitizer {
|
||||||
|
|
@ -30,6 +31,7 @@ void AddressInfo::Clear() {
|
||||||
InternalFree(file);
|
InternalFree(file);
|
||||||
internal_memset(this, 0, sizeof(AddressInfo));
|
internal_memset(this, 0, sizeof(AddressInfo));
|
||||||
function_offset = kUnknown;
|
function_offset = kUnknown;
|
||||||
|
uuid_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddressInfo::FillModuleInfo(const char *mod_name, uptr mod_offset,
|
void AddressInfo::FillModuleInfo(const char *mod_name, uptr mod_offset,
|
||||||
|
|
@ -37,6 +39,16 @@ void AddressInfo::FillModuleInfo(const char *mod_name, uptr mod_offset,
|
||||||
module = internal_strdup(mod_name);
|
module = internal_strdup(mod_name);
|
||||||
module_offset = mod_offset;
|
module_offset = mod_offset;
|
||||||
module_arch = mod_arch;
|
module_arch = mod_arch;
|
||||||
|
uuid_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressInfo::FillModuleInfo(const LoadedModule &mod) {
|
||||||
|
module = internal_strdup(mod.full_name());
|
||||||
|
module_offset = address - mod.base_address();
|
||||||
|
module_arch = mod.arch();
|
||||||
|
if (mod.uuid_size())
|
||||||
|
internal_memcpy(uuid, mod.uuid(), mod.uuid_size());
|
||||||
|
uuid_size = mod.uuid_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolizedStack::SymbolizedStack() : next(nullptr), info() {}
|
SymbolizedStack::SymbolizedStack() : next(nullptr), info() {}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ struct AddressInfo {
|
||||||
char *module;
|
char *module;
|
||||||
uptr module_offset;
|
uptr module_offset;
|
||||||
ModuleArch module_arch;
|
ModuleArch module_arch;
|
||||||
|
u8 uuid[kModuleUUIDSize];
|
||||||
|
uptr uuid_size;
|
||||||
|
|
||||||
static const uptr kUnknown = ~(uptr)0;
|
static const uptr kUnknown = ~(uptr)0;
|
||||||
char *function;
|
char *function;
|
||||||
|
|
@ -45,6 +47,8 @@ struct AddressInfo {
|
||||||
// Deletes all strings and resets all fields.
|
// Deletes all strings and resets all fields.
|
||||||
void Clear();
|
void Clear();
|
||||||
void FillModuleInfo(const char *mod_name, uptr mod_offset, ModuleArch arch);
|
void FillModuleInfo(const char *mod_name, uptr mod_offset, ModuleArch arch);
|
||||||
|
void FillModuleInfo(const LoadedModule &mod);
|
||||||
|
uptr module_base() const { return address - module_offset; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Linked list of symbolized frames (each frame is described by AddressInfo).
|
// Linked list of symbolized frames (each frame is described by AddressInfo).
|
||||||
|
|
|
||||||
|
|
@ -84,15 +84,12 @@ const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter,
|
||||||
|
|
||||||
SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
|
SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
|
||||||
Lock l(&mu_);
|
Lock l(&mu_);
|
||||||
const char *module_name = nullptr;
|
|
||||||
uptr module_offset;
|
|
||||||
ModuleArch arch;
|
|
||||||
SymbolizedStack *res = SymbolizedStack::New(addr);
|
SymbolizedStack *res = SymbolizedStack::New(addr);
|
||||||
if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset,
|
auto *mod = FindModuleForAddress(addr);
|
||||||
&arch))
|
if (!mod)
|
||||||
return res;
|
return res;
|
||||||
// Always fill data about module name and offset.
|
// Always fill data about module name and offset.
|
||||||
res->info.FillModuleInfo(module_name, module_offset, arch);
|
res->info.FillModuleInfo(*mod);
|
||||||
for (auto &tool : tools_) {
|
for (auto &tool : tools_) {
|
||||||
SymbolizerScope sym_scope(this);
|
SymbolizerScope sym_scope(this);
|
||||||
if (tool.SymbolizePC(addr, res)) {
|
if (tool.SymbolizePC(addr, res)) {
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,28 @@ TEST(SanitizerStacktracePrinter, RenderFrame) {
|
||||||
EXPECT_STREQ("(/path/to/module+0x200)", str.data());
|
EXPECT_STREQ("(/path/to/module+0x200)", str.data());
|
||||||
str.clear();
|
str.clear();
|
||||||
|
|
||||||
|
RenderFrame(&str, "%b", frame_no, info.address, &info, false);
|
||||||
|
EXPECT_STREQ("", str.data());
|
||||||
|
str.clear();
|
||||||
|
|
||||||
|
info.uuid_size = 2;
|
||||||
|
info.uuid[0] = 0x55;
|
||||||
|
info.uuid[1] = 0x66;
|
||||||
|
|
||||||
|
RenderFrame(&str, "%M", frame_no, info.address, &info, false);
|
||||||
|
EXPECT_NE(nullptr, internal_strstr(str.data(), "(module+0x"));
|
||||||
|
EXPECT_NE(nullptr, internal_strstr(str.data(), "200"));
|
||||||
|
EXPECT_NE(nullptr, internal_strstr(str.data(), "BuildId: 5566"));
|
||||||
|
str.clear();
|
||||||
|
|
||||||
|
RenderFrame(&str, "%L", frame_no, info.address, &info, false);
|
||||||
|
EXPECT_STREQ("(/path/to/module+0x200) (BuildId: 5566)", str.data());
|
||||||
|
str.clear();
|
||||||
|
|
||||||
|
RenderFrame(&str, "%b", frame_no, info.address, &info, false);
|
||||||
|
EXPECT_STREQ("(BuildId: 5566)", str.data());
|
||||||
|
str.clear();
|
||||||
|
|
||||||
info.function = internal_strdup("my_function");
|
info.function = internal_strdup("my_function");
|
||||||
RenderFrame(&str, "%F", frame_no, info.address, &info, false);
|
RenderFrame(&str, "%F", frame_no, info.address, &info, false);
|
||||||
EXPECT_STREQ("in my_function", str.data());
|
EXPECT_STREQ("in my_function", str.data());
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
// RUN: %clang_hwasan -Wl,--build-id=0xaba493998257fbdd %s -o %t
|
||||||
|
// RUN: %env_hwasan_opts=symbolize=0 not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,NOSYM
|
||||||
|
// RUN: not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,SYM
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <sanitizer/hwasan_interface.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
__hwasan_enable_allocator_tagging();
|
||||||
|
char *buf = (char *)malloc(1);
|
||||||
|
buf[32] = 'x';
|
||||||
|
// CHECK: ERROR: HWAddressSanitizer: tag-mismatch
|
||||||
|
// NOSYM: #0 0x{{.*}} {{.*}}build-ids.c{{.*}} (BuildId: aba493998257fbdd)
|
||||||
|
// SYM: #0 0x{{.*}} in main {{.*}}build-ids.c:[[@LINE-3]]:{{[0-9]+}}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue