summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Samsonov <samsonov@google.com>2013-09-10 14:36:16 +0000
committerAlexey Samsonov <samsonov@google.com>2013-09-10 14:36:16 +0000
commit7847d77b246635211c3bf465421d49d7af5226c1 (patch)
tree3cfd208ba07884f253113a44fdf80f49207f9bc4
parent34e3ed1db94c5ce9784d7ffb8d66a54cf523e09c (diff)
[Sanitizer] Refactor symbolization interface: use class instead of several functions. Move some code around to get rid of extra source files
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@190410 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/asan/asan_report.cc7
-rw-r--r--lib/asan/asan_rtl.cc3
-rw-r--r--lib/lsan/lsan.cc3
-rw-r--r--lib/lsan/lsan_common.cc4
-rw-r--r--lib/msan/msan.cc3
-rw-r--r--lib/msan/msan_report.cc8
-rw-r--r--lib/sanitizer_common/CMakeLists.txt5
-rw-r--r--lib/sanitizer_common/sanitizer_common.cc21
-rw-r--r--lib/sanitizer_common/sanitizer_common.h31
-rw-r--r--lib/sanitizer_common/sanitizer_linux.cc35
-rw-r--r--lib/sanitizer_common/sanitizer_linux.h5
-rw-r--r--lib/sanitizer_common/sanitizer_linux_libcdep.cc64
-rw-r--r--lib/sanitizer_common/sanitizer_mac.cc32
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace.cc6
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer.h94
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_itanium.cc44
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc491
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_linux.cc63
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_linux_libcdep.cc100
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_mac.cc62
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc464
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_win.cc20
-rw-r--r--lib/sanitizer_common/sanitizer_win.cc5
-rw-r--r--lib/tsan/rtl/tsan_rtl.cc2
-rw-r--r--lib/tsan/rtl/tsan_symbolize.cc14
-rw-r--r--lib/ubsan/ubsan_diag.cc5
26 files changed, 725 insertions, 866 deletions
diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc
index 7717cd268..b77d265b4 100644
--- a/lib/asan/asan_report.cc
+++ b/lib/asan/asan_report.cc
@@ -180,7 +180,8 @@ static bool IsASCII(unsigned char c) {
static const char *MaybeDemangleGlobalName(const char *name) {
// We can spoil names of globals with C linkage, so use an heuristic
// approach to check if the name should be demangled.
- return (name[0] == '_' && name[1] == 'Z') ? Demangle(name) : name;
+ return (name[0] == '_' && name[1] == 'Z') ? getSymbolizer()->Demangle(name)
+ : name;
}
// Check if the global is a zero-terminated ASCII string. If so, print it.
@@ -550,12 +551,12 @@ class ScopedInErrorReport {
static void ReportSummary(const char *error_type, StackTrace *stack) {
if (!stack->size) return;
- if (IsSymbolizerAvailable()) {
+ if (getSymbolizer()->IsAvailable()) {
AddressInfo ai;
// Currently, we include the first stack frame into the report summary.
// Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
- SymbolizeCode(pc, &ai, 1);
+ getSymbolizer()->SymbolizeCode(pc, &ai, 1);
ReportErrorSummary(error_type,
StripPathPrefix(ai.file,
common_flags()->strip_path_prefix),
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index 4c3e77657..80bd59180 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -532,7 +532,8 @@ void __asan_init() {
// Start symbolizer process if necessary.
if (common_flags()->symbolize) {
- InitializeExternalSymbolizer(common_flags()->external_symbolizer_path);
+ getSymbolizer()
+ ->InitializeExternal(common_flags()->external_symbolizer_path);
}
// On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
diff --git a/lib/lsan/lsan.cc b/lib/lsan/lsan.cc
index 99b165b5d..7f37da6c3 100644
--- a/lib/lsan/lsan.cc
+++ b/lib/lsan/lsan.cc
@@ -53,7 +53,8 @@ void Init() {
// Start symbolizer process if necessary.
if (common_flags()->symbolize) {
- InitializeExternalSymbolizer(common_flags()->external_symbolizer_path);
+ getSymbolizer()
+ ->InitializeExternal(common_flags()->external_symbolizer_path);
}
InitCommonLsan();
diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc
index 1d895a3b1..7fa067522 100644
--- a/lib/lsan/lsan_common.cc
+++ b/lib/lsan/lsan_common.cc
@@ -402,8 +402,8 @@ static Suppression *GetSuppressionForAddr(uptr addr) {
static const uptr kMaxAddrFrames = 16;
InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
for (uptr i = 0; i < kMaxAddrFrames; i++) new (&addr_frames[i]) AddressInfo();
- uptr addr_frames_num = __sanitizer::SymbolizeCode(addr, addr_frames.data(),
- kMaxAddrFrames);
+ uptr addr_frames_num =
+ getSymbolizer()->SymbolizeCode(addr, addr_frames.data(), kMaxAddrFrames);
for (uptr i = 0; i < addr_frames_num; i++) {
Suppression* s;
if (suppression_ctx->Match(addr_frames[i].function, SuppressionLeak, &s) ||
diff --git a/lib/msan/msan.cc b/lib/msan/msan.cc
index afe7f8e72..8388f307f 100644
--- a/lib/msan/msan.cc
+++ b/lib/msan/msan.cc
@@ -324,7 +324,8 @@ void __msan_init() {
}
const char *external_symbolizer = common_flags()->external_symbolizer_path;
- bool symbolizer_started = InitializeExternalSymbolizer(external_symbolizer);
+ bool symbolizer_started =
+ getSymbolizer()->InitializeExternal(external_symbolizer);
if (external_symbolizer && external_symbolizer[0]) {
CHECK(symbolizer_started);
}
diff --git a/lib/msan/msan_report.cc b/lib/msan/msan_report.cc
index b1cfe87b4..2f80d68f6 100644
--- a/lib/msan/msan_report.cc
+++ b/lib/msan/msan_report.cc
@@ -52,8 +52,8 @@ static void DescribeOrigin(u32 origin) {
Printf("%s", d.Origin());
Printf(" %sUninitialized value was created by an allocation of '%s%s%s'"
" in the stack frame of function '%s%s%s'%s\n",
- d.Origin(), d.Name(), s, d.Origin(), d.Name(), Demangle(sep + 1),
- d.Origin(), d.End());
+ d.Origin(), d.Name(), s, d.Origin(), d.Name(),
+ getSymbolizer()->Demangle(sep + 1), d.Origin(), d.End());
InternalFree(s);
} else {
uptr size = 0;
@@ -65,12 +65,12 @@ static void DescribeOrigin(u32 origin) {
}
static void ReportSummary(const char *error_type, StackTrace *stack) {
- if (!stack->size || !IsSymbolizerAvailable()) return;
+ if (!stack->size || !getSymbolizer()->IsAvailable()) return;
AddressInfo ai;
uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
{
SymbolizerScope sym_scope;
- SymbolizeCode(pc, &ai, 1);
+ getSymbolizer()->SymbolizeCode(pc, &ai, 1);
}
ReportErrorSummary(error_type,
StripPathPrefix(ai.file,
diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt
index 93e3a84cd..3aa56b1f6 100644
--- a/lib/sanitizer_common/CMakeLists.txt
+++ b/lib/sanitizer_common/CMakeLists.txt
@@ -15,9 +15,6 @@ set(SANITIZER_SOURCES
sanitizer_stackdepot.cc
sanitizer_stacktrace.cc
sanitizer_suppressions.cc
- sanitizer_symbolizer_itanium.cc
- sanitizer_symbolizer_linux.cc
- sanitizer_symbolizer_mac.cc
sanitizer_symbolizer_win.cc
sanitizer_thread_registry.cc
sanitizer_win.cc)
@@ -27,8 +24,6 @@ set(SANITIZER_LIBCDEP_SOURCES
sanitizer_linux_libcdep.cc
sanitizer_posix_libcdep.cc
sanitizer_stoptheworld_linux_libcdep.cc
- sanitizer_symbolizer_libcdep.cc
- sanitizer_symbolizer_linux_libcdep.cc
sanitizer_symbolizer_posix_libcdep.cc)
# Explicitly list all sanitizer_common headers. Not all of these are
diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc
index 4aab65d91..97198ea2c 100644
--- a/lib/sanitizer_common/sanitizer_common.cc
+++ b/lib/sanitizer_common/sanitizer_common.cc
@@ -146,6 +146,27 @@ void ReportErrorSummary(const char *error_type, const char *file,
__sanitizer_report_error_summary(buff.data());
}
+LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
+ full_name_ = internal_strdup(module_name);
+ base_address_ = base_address;
+ n_ranges_ = 0;
+}
+
+void LoadedModule::addAddressRange(uptr beg, uptr end) {
+ CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges);
+ ranges_[n_ranges_].beg = beg;
+ ranges_[n_ranges_].end = end;
+ n_ranges_++;
+}
+
+bool LoadedModule::containsAddress(uptr address) const {
+ for (uptr i = 0; i < n_ranges_; i++) {
+ if (ranges_[i].beg <= address && address < ranges_[i].end)
+ return true;
+ }
+ return false;
+}
+
} // namespace __sanitizer
using namespace __sanitizer; // NOLINT
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index abed9440b..90f321917 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -402,6 +402,37 @@ uptr InternalBinarySearch(const Container &v, uptr first, uptr last,
return not_found;
}
+// Represents a binary loaded into virtual memory (e.g. this can be an
+// executable or a shared object).
+class LoadedModule {
+ public:
+ LoadedModule(const char *module_name, uptr base_address);
+ void addAddressRange(uptr beg, uptr end);
+ bool containsAddress(uptr address) const;
+
+ const char *full_name() const { return full_name_; }
+ uptr base_address() const { return base_address_; }
+
+ private:
+ struct AddressRange {
+ uptr beg;
+ uptr end;
+ };
+ char *full_name_;
+ uptr base_address_;
+ static const uptr kMaxNumberOfAddressRanges = 6;
+ AddressRange ranges_[kMaxNumberOfAddressRanges];
+ uptr n_ranges_;
+};
+
+// OS-dependent function that fills array with descriptions of at most
+// "max_modules" currently loaded modules. Returns the number of
+// initialized modules. If filter is nonzero, ignores modules for which
+// filter(full_name) is false.
+typedef bool (*string_predicate_t)(const char *);
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+ string_predicate_t filter);
+
} // namespace __sanitizer
#endif // SANITIZER_COMMON_H
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
index d3c8d6917..aa6110b23 100644
--- a/lib/sanitizer_common/sanitizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -310,7 +310,7 @@ void PrepareForSandboxing() {
// cached mappings.
MemoryMappingLayout::CacheMemoryMappings();
// Same for /proc/self/exe in the symbolizer.
- SymbolizerPrepareForSandboxing();
+ getSymbolizer()->PrepareForSandboxing();
}
// ----------------- sanitizer_procmaps.h
@@ -676,6 +676,39 @@ uptr GetPageSize() {
#endif
}
+static char proc_self_exe_cache_str[kMaxPathLength];
+static uptr proc_self_exe_cache_len = 0;
+
+uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
+ uptr module_name_len = internal_readlink(
+ "/proc/self/exe", buf, buf_len);
+ int readlink_error;
+ if (internal_iserror(buf_len, &readlink_error)) {
+ if (proc_self_exe_cache_len) {
+ // If available, use the cached module name.
+ CHECK_LE(proc_self_exe_cache_len, buf_len);
+ internal_strncpy(buf, proc_self_exe_cache_str, buf_len);
+ module_name_len = internal_strlen(proc_self_exe_cache_str);
+ } else {
+ // We can't read /proc/self/exe for some reason, assume the name of the
+ // binary is unknown.
+ Report("WARNING: readlink(\"/proc/self/exe\") failed with errno %d, "
+ "some stack frames may not be symbolized\n", readlink_error);
+ module_name_len = internal_snprintf(buf, buf_len, "/proc/self/exe");
+ }
+ CHECK_LT(module_name_len, buf_len);
+ buf[module_name_len] = '\0';
+ }
+ return module_name_len;
+}
+
+void CacheBinaryName() {
+ if (!proc_self_exe_cache_len) {
+ proc_self_exe_cache_len =
+ ReadBinaryName(proc_self_exe_cache_str, kMaxPathLength);
+ }
+}
+
// Match full names of the form /path/to/base_name{-,.}*
bool LibraryNameIs(const char *full_name, const char *base_name) {
const char *name = full_name;
diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h
index c0fba48da..4c0450e86 100644
--- a/lib/sanitizer_common/sanitizer_linux.h
+++ b/lib/sanitizer_common/sanitizer_linux.h
@@ -13,6 +13,8 @@
#ifndef SANITIZER_LINUX_H
#define SANITIZER_LINUX_H
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
@@ -69,10 +71,13 @@ bool LibraryNameIs(const char *full_name, const char *base_name);
// Read the name of the current binary from /proc/self/exe.
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len);
+// Cache the value of /proc/self/exe.
+void CacheBinaryName();
// Call cb for each region mapped by map.
void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr));
} // namespace __sanitizer
+#endif // SANITIZER_LINUX
#endif // SANITIZER_LINUX_H
diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
index 6569a2582..a00b5bb4c 100644
--- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -16,6 +16,8 @@
#if SANITIZER_LINUX
#include "sanitizer_common.h"
+#include "sanitizer_linux.h"
+#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"
@@ -25,6 +27,11 @@
#include <sys/resource.h>
#include <unwind.h>
+#if !SANITIZER_ANDROID
+#include <elf.h>
+#include <link.h>
+#endif
+
namespace __sanitizer {
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
@@ -284,6 +291,63 @@ void AdjustStackSizeLinux(void *attr_, int verbosity) {
}
}
+#if SANITIZER_ANDROID
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+ string_predicate_t filter) {
+ return 0;
+}
+#else // SANITIZER_ANDROID
+typedef ElfW(Phdr) Elf_Phdr;
+
+struct DlIteratePhdrData {
+ LoadedModule *modules;
+ uptr current_n;
+ bool first;
+ uptr max_n;
+ string_predicate_t filter;
+};
+
+static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
+ DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
+ if (data->current_n == data->max_n)
+ return 0;
+ InternalScopedBuffer<char> module_name(kMaxPathLength);
+ module_name.data()[0] = '\0';
+ if (data->first) {
+ data->first = false;
+ // First module is the binary itself.
+ ReadBinaryName(module_name.data(), module_name.size());
+ } else if (info->dlpi_name) {
+ internal_strncpy(module_name.data(), info->dlpi_name, module_name.size());
+ }
+ if (module_name.data()[0] == '\0')
+ return 0;
+ if (data->filter && !data->filter(module_name.data()))
+ return 0;
+ void *mem = &data->modules[data->current_n];
+ LoadedModule *cur_module = new(mem) LoadedModule(module_name.data(),
+ info->dlpi_addr);
+ data->current_n++;
+ for (int i = 0; i < info->dlpi_phnum; i++) {
+ const Elf_Phdr *phdr = &info->dlpi_phdr[i];
+ if (phdr->p_type == PT_LOAD) {
+ uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
+ uptr cur_end = cur_beg + phdr->p_memsz;
+ cur_module->addAddressRange(cur_beg, cur_end);
+ }
+ }
+ return 0;
+}
+
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+ string_predicate_t filter) {
+ CHECK(modules);
+ DlIteratePhdrData data = {modules, 0, true, max_modules, filter};
+ dl_iterate_phdr(dl_iterate_phdr_cb, &data);
+ return data.current_n;
+}
+#endif // SANITIZER_ANDROID
+
} // namespace __sanitizer
#endif // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc
index ea87128e7..1ba028453 100644
--- a/lib/sanitizer_common/sanitizer_mac.cc
+++ b/lib/sanitizer_common/sanitizer_mac.cc
@@ -25,6 +25,7 @@
#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
+#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
#include <crt_externs.h> // for _NSGetEnviron
@@ -371,6 +372,37 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
#endif
}
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+ string_predicate_t filter) {
+ MemoryMappingLayout memory_mapping(false);
+ memory_mapping.Reset();
+ uptr cur_beg, cur_end, cur_offset;
+ InternalScopedBuffer<char> module_name(kMaxPathLength);
+ uptr n_modules = 0;
+ for (uptr i = 0;
+ n_modules < max_modules &&
+ memory_mapping.Next(&cur_beg, &cur_end, &cur_offset,
+ module_name.data(), module_name.size(), 0);
+ i++) {
+ const char *cur_name = module_name.data();
+ if (cur_name[0] == '\0')
+ continue;
+ if (filter && !filter(cur_name))
+ continue;
+ LoadedModule *cur_module = 0;
+ if (n_modules > 0 &&
+ 0 == internal_strcmp(cur_name, modules[n_modules - 1].full_name())) {
+ cur_module = &modules[n_modules - 1];
+ } else {
+ void *mem = &modules[n_modules];
+ cur_module = new(mem) LoadedModule(cur_name, cur_beg);
+ n_modules++;
+ }
+ cur_module->addAddressRange(cur_beg, cur_end);
+ }
+ return n_modules;
+}
+
} // namespace __sanitizer
#endif // SANITIZER_MAC
diff --git a/lib/sanitizer_common/sanitizer_stacktrace.cc b/lib/sanitizer_common/sanitizer_stacktrace.cc
index e279a9ff2..665627bc3 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace.cc
+++ b/lib/sanitizer_common/sanitizer_stacktrace.cc
@@ -86,10 +86,10 @@ void StackTrace::PrintStack(const uptr *addr, uptr size,
frame_num++;
}
}
- if (symbolize && addr_frames_num == 0 && &SymbolizeCode) {
+ if (symbolize && addr_frames_num == 0 && &getSymbolizer) {
// Use our own (online) symbolizer, if necessary.
- addr_frames_num = SymbolizeCode(pc, addr_frames.data(),
- addr_frames.size());
+ addr_frames_num = getSymbolizer()->SymbolizeCode(
+ pc, addr_frames.data(), addr_frames.size());
for (uptr j = 0; j < addr_frames_num; j++) {
AddressInfo &info = addr_frames[j];
PrintStackFramePrefix(frame_num, pc);
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h
index 90ee784f5..383e1d4ac 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer.h
+++ b/lib/sanitizer_common/sanitizer_symbolizer.h
@@ -24,6 +24,7 @@
#ifndef SANITIZER_SYMBOLIZER_H
#define SANITIZER_SYMBOLIZER_H
+#include "sanitizer_allocator_internal.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
// WARNING: Do not include system headers here. See details above.
@@ -42,8 +43,14 @@ struct AddressInfo {
AddressInfo() {
internal_memset(this, 0, sizeof(AddressInfo));
}
+
// Deletes all strings and sets all fields to zero.
- SANITIZER_WEAK_ATTRIBUTE void Clear();
+ void Clear() {
+ InternalFree(module);
+ InternalFree(function);
+ InternalFree(file);
+ internal_memset(this, 0, sizeof(AddressInfo));
+ }
void FillAddressAndModuleInfo(uptr addr, const char *mod_name,
uptr mod_offset) {
@@ -62,64 +69,39 @@ struct DataInfo {
uptr size;
};
-// Fills at most "max_frames" elements of "frames" with descriptions
-// for a given address (in all inlined functions). Returns the number
-// of descriptions actually filled.
-// This function should NOT be called from two threads simultaneously.
-SANITIZER_WEAK_ATTRIBUTE
-uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames);
-bool SymbolizeData(uptr address, DataInfo *info);
-
-bool IsSymbolizerAvailable();
-void FlushSymbolizer(); // releases internal caches (if any)
-
-// Attempts to demangle the provided C++ mangled name.
-const char *Demangle(const char *name);
-// Attempts to demangle the name via __cxa_demangle from __cxxabiv1.
-const char *DemangleCXXABI(const char *name);
-
-// Starts external symbolizer program in a subprocess. Sanitizer communicates
-// with external symbolizer via pipes. If path_to_symbolizer is NULL or empty,
-// tries to look for llvm-symbolizer in PATH.
-bool InitializeExternalSymbolizer(const char *path_to_symbolizer);
-
-const int kSymbolizerStartupTimeMillis = 10;
-
-class LoadedModule {
+class SymbolizerInterface {
public:
- LoadedModule(const char *module_name, uptr base_address);
- void addAddressRange(uptr beg, uptr end);
- bool containsAddress(uptr address) const;
-
- const char *full_name() const { return full_name_; }
- uptr base_address() const { return base_address_; }
-
- private:
- struct AddressRange {
- uptr beg;
- uptr end;
- };
- char *full_name_;
- uptr base_address_;
- static const uptr kMaxNumberOfAddressRanges = 6;
- AddressRange ranges_[kMaxNumberOfAddressRanges];
- uptr n_ranges_;
+ // Fills at most "max_frames" elements of "frames" with descriptions
+ // for a given address (in all inlined functions). Returns the number
+ // of descriptions actually filled.
+ virtual uptr SymbolizeCode(uptr address, AddressInfo *frames,
+ uptr max_frames) {
+ return 0;
+ }
+ virtual bool SymbolizeData(uptr address, DataInfo *info) {
+ return false;
+ }
+ virtual bool IsAvailable() {
+ return false;
+ }
+ // Release internal caches (if any).
+ virtual void Flush() {}
+ // Attempts to demangle the provided C++ mangled name.
+ virtual const char *Demangle(const char *name) {
+ return name;
+ }
+ virtual void PrepareForSandboxing() {}
+ // Starts external symbolizer program in a subprocess. Sanitizer communicates
+ // with external symbolizer via pipes. If path_to_symbolizer is NULL or empty,
+ // tries to look for llvm-symbolizer in PATH.
+ virtual bool InitializeExternal(const char *path_to_symbolizer) {
+ return false;
+ }
};
-// Creates external symbolizer connected via pipe, user should write
-// to output_fd and read from input_fd.
-bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
- int *input_fd, int *output_fd);
-
-// OS-dependent function that fills array with descriptions of at most
-// "max_modules" currently loaded modules. Returns the number of
-// initialized modules. If filter is nonzero, ignores modules for which
-// filter(full_name) is false.
-typedef bool (*string_predicate_t)(const char *);
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
- string_predicate_t filter);
-
-void SymbolizerPrepareForSandboxing();
+// Returns platform-specific implementation of SymbolizerInterface. It can't be
+// used from multiple threads simultaneously.
+SANITIZER_WEAK_ATTRIBUTE SymbolizerInterface *getSymbolizer();
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_itanium.cc b/lib/sanitizer_common/sanitizer_symbolizer_itanium.cc
deleted file mode 100644
index 086e84f5a..000000000
--- a/lib/sanitizer_common/sanitizer_symbolizer_itanium.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-//===-- sanitizer_symbolizer_itanium.cc -----------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is shared between the sanitizer run-time libraries.
-// Itanium C++ ABI-specific implementation of symbolizer parts.
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_platform.h"
-#if SANITIZER_MAC || SANITIZER_LINUX
-
-#include "sanitizer_symbolizer.h"
-
-#include <stdlib.h>
-
-// C++ demangling function, as required by Itanium C++ ABI. This is weak,
-// because we do not require a C++ ABI library to be linked to a program
-// using sanitizers; if it's not present, we'll just use the mangled name.
-namespace __cxxabiv1 {
- extern "C" SANITIZER_WEAK_ATTRIBUTE
- char *__cxa_demangle(const char *mangled, char *buffer,
- size_t *length, int *status);
-}
-
-const char *__sanitizer::DemangleCXXABI(const char *name) {
- // FIXME: __cxa_demangle aggressively insists on allocating memory.
- // There's not much we can do about that, short of providing our
- // 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 (const char *demangled_name =
- __cxxabiv1::__cxa_demangle(name, 0, 0, 0))
- return demangled_name;
-
- return name;
-}
-
-#endif // SANITIZER_MAC || SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
deleted file mode 100644
index 9ccd62215..000000000
--- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
+++ /dev/null
@@ -1,491 +0,0 @@
-//===-- sanitizer_symbolizer_libcdep.cc -----------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is shared between AddressSanitizer and ThreadSanitizer
-// run-time libraries. See sanitizer_symbolizer.h for details.
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_allocator_internal.h"
-#include "sanitizer_common.h"
-#include "sanitizer_placement_new.h"
-#include "sanitizer_procmaps.h"
-#include "sanitizer_symbolizer.h"
-
-namespace __sanitizer {
-
-void AddressInfo::Clear() {
- InternalFree(module);
- InternalFree(function);
- InternalFree(file);
- internal_memset(this, 0, sizeof(AddressInfo));
-}
-
-LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
- full_name_ = internal_strdup(module_name);
- base_address_ = base_address;
- n_ranges_ = 0;
-}
-
-void LoadedModule::addAddressRange(uptr beg, uptr end) {
- CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges);
- ranges_[n_ranges_].beg = beg;
- ranges_[n_ranges_].end = end;
- n_ranges_++;
-}
-
-bool LoadedModule::containsAddress(uptr address) const {
- for (uptr i = 0; i < n_ranges_; i++) {
- if (ranges_[i].beg <= address && address < ranges_[i].end)
- return true;
- }
- return false;
-}
-
-// Extracts the prefix of "str" that consists of any characters not
-// present in "delims" string, and copies this prefix to "result", allocating
-// space for it.
-// Returns a pointer to "str" after skipping extracted prefix and first
-// delimiter char.
-static const char *ExtractToken(const char *str, const char *delims,
- char **result) {
- uptr prefix_len = internal_strcspn(str, delims);
- *result = (char*)InternalAlloc(prefix_len + 1);
- internal_memcpy(*result, str, prefix_len);
- (*result)[prefix_len] = '\0';
- const char *prefix_end = str + prefix_len;
- if (*prefix_end != '\0') prefix_end++;
- return prefix_end;
-}
-
-// Same as ExtractToken, but converts extracted token to integer.
-static const char *ExtractInt(const char *str, const char *delims,
- int *result) {
- char *buff;
- const char *ret = ExtractToken(str, delims, &buff);
- if (buff != 0) {
- *result = (int)internal_atoll(buff);
- }
- InternalFree(buff);
- return ret;
-}
-
-static const char *ExtractUptr(const char *str, const char *delims,
- uptr *result) {
- char *buff;
- const char *ret = ExtractToken(str, delims, &buff);
- if (buff != 0) {
- *result = (uptr)internal_atoll(buff);
- }
- InternalFree(buff);
- return ret;
-}
-
-// ExternalSymbolizer encapsulates communication between the tool and
-// external symbolizer program, running in a different subprocess,
-// For now we assume the following protocol:
-// For each request of the form
-// <module_name> <module_offset>
-// passed to STDIN, external symbolizer prints to STDOUT response:
-// <function_name>
-// <file_name>:<line_number>:<column_number>
-// <function_name>
-// <file_name>:<line_number>:<column_number>
-// ...
-// <empty line>
-class ExternalSymbolizer {
- public:
- ExternalSymbolizer(const char *path, int input_fd, int output_fd)
- : path_(path),
- input_fd_(input_fd),
- output_fd_(output_fd),
- times_restarted_(0) {
- CHECK(path_);
- CHECK_NE(input_fd_, kInvalidFd);
- CHECK_NE(output_fd_, kInvalidFd);
- }
-
- char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
- CHECK(module_name);
- internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n",
- is_data ? "DATA " : "", module_name, module_offset);
- if (!writeToSymbolizer(buffer_, internal_strlen(buffer_)))
- return 0;
- if (!readFromSymbolizer(buffer_, kBufferSize))
- return 0;
- return buffer_;
- }
-
- bool Restart() {
- if (times_restarted_ >= kMaxTimesRestarted) return false;
- times_restarted_++;
- internal_close(input_fd_);
- internal_close(output_fd_);
- return StartSymbolizerSubprocess(path_, &input_fd_, &output_fd_);
- }
-
- void Flush() {
- }
-
- private:
- bool readFromSymbolizer(char *buffer, uptr max_length) {
- if (max_length == 0)
- return true;
- uptr read_len = 0;
- while (true) {
- uptr just_read = internal_read(input_fd_, buffer + read_len,
- max_length - read_len);
- // We can't read 0 bytes, as we don't expect external symbolizer to close
- // its stdout.
- if (just_read == 0 || just_read == (uptr)-1) {
- Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_);
- return false;
- }
- read_len += just_read;
- // Empty line marks the end of symbolizer output.
- if (read_len >= 2 && buffer[read_len - 1] == '\n' &&
- buffer[read_len - 2] == '\n') {
- break;
- }
- }
- return true;
- }
-
- bool writeToSymbolizer(const char *buffer, uptr length) {
- if (length == 0)
- return true;
- uptr write_len = internal_write(output_fd_, buffer, length);
- if (write_len == 0 || write_len == (uptr)-1) {
- Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_);
- return false;
- }
- return true;
- }
-
- const char *path_;
- int input_fd_;
- int output_fd_;
-
- static const uptr kBufferSize = 16 * 1024;
- char buffer_[kBufferSize];
-
- static const uptr kMaxTimesRestarted = 5;
- uptr times_restarted_;
-};
-
-static LowLevelAllocator symbolizer_allocator; // Linker initialized.
-
-#if SANITIZER_SUPPORTS_WEAK_HOOKS
-extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset,
- char *Buffer, int MaxLength);
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset,
- char *Buffer, int MaxLength);
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __sanitizer_symbolize_flush();
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-int __sanitizer_symbolize_demangle(const char *Name, char *Buffer,
- int MaxLength);
-} // extern "C"
-
-class InternalSymbolizer {
- public:
- typedef bool (*SanitizerSymbolizeFn)(const char*, u64, char*, int);
-
- static InternalSymbolizer *get() {
- if (__sanitizer_symbolize_code != 0 &&
- __sanitizer_symbolize_data != 0) {
- void *mem = symbolizer_allocator.Allocate(sizeof(InternalSymbolizer));
- return new(mem) InternalSymbolizer();
- }
- return 0;
- }
-
- char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
- SanitizerSymbolizeFn symbolize_fn = is_data ? __sanitizer_symbolize_data
- : __sanitizer_symbolize_code;
- if (symbolize_fn(module_name, module_offset, buffer_, kBufferSize))
- return buffer_;
- return 0;
- }
-
- void Flush() {
- if (__sanitizer_symbolize_flush)
- __sanitizer_symbolize_flush();
- }
-
- const char *Demangle(const char *name) {
- if (__sanitizer_symbolize_demangle) {
- for (uptr res_length = 1024;
- res_length <= InternalSizeClassMap::kMaxSize;) {
- char *res_buff = static_cast<char*>(InternalAlloc(res_length));
- uptr req_length =
- __sanitizer_symbolize_demangle(name, res_buff, res_length);
- if (req_length > res_length) {
- res_length = req_length + 1;
- InternalFree(res_buff);
- continue;
- }
- return res_buff;
- }
- }
- return name;
- }
-
- private:
- InternalSymbolizer() { }
-
- static const int kBufferSize = 16 * 1024;
- static const int kMaxDemangledNameSize = 1024;
- char buffer_[kBufferSize];
-};
-#else // SANITIZER_SUPPORTS_WEAK_HOOKS
-
-class InternalSymbolizer {
- public:
- static InternalSymbolizer *get() { return 0; }
- char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
- return 0;
- }
- void Flush() { }
- const char *Demangle(const char *name) { return name; }
-};
-
-#endif // SANITIZER_SUPPORTS_WEAK_HOOKS
-
-class Symbolizer {
- // This class has no constructor, as global constructors are forbidden in
- // sanitizer_common. It should be linker initialized instead.
- public:
- uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) {
- if (max_frames == 0)
- return 0;
- LoadedModule *module = FindModuleForAddress(addr);
- if (module == 0)
- return 0;
- const char *module_name = module->full_name();
- uptr module_offset = addr - module->base_address();
- const char *str = SendCommand(false, module_name, module_offset);
- if (str == 0) {
- // External symbolizer was not initialized or failed. Fill only data
- // about module name and offset.
- AddressInfo *info = &frames[0];
- info->Clear();
- info->FillAddressAndModuleInfo(addr, module_name, module_offset);
- return 1;
- }
- uptr frame_id = 0;
- for (frame_id = 0; frame_id < max_frames; frame_id++) {
- AddressInfo *info = &frames[frame_id];
- char *function_name = 0;
- str = ExtractToken(str, "\n", &function_name);
- CHECK(function_name);
- if (function_name[0] == '\0') {
- // There are no more frames.
- break;
- }
- info->Clear();
- info->FillAddressAndModuleInfo(addr, module_name, module_offset);
- info->function = function_name;
- // Parse <file>:<line>:<column> buffer.
- char *file_line_info = 0;
- str = ExtractToken(str, "\n", &file_line_info);
- CHECK(file_line_info);
- const char *line_info = ExtractToken(file_line_info, ":", &info->file);
- line_info = ExtractInt(line_info, ":", &info->line);
- line_info = ExtractInt(line_info, "", &info->column);
- InternalFree(file_line_info);
-
- // Functions and filenames can be "??", in which case we write 0
- // to address info to mark that names are unknown.
- if (0 == internal_strcmp(info->function, "??")) {
- InternalFree(info->function);
- info->function = 0;
- }
- if (0 == internal_strcmp(info->file, "??")) {
- InternalFree(info->file);
- info->file = 0;
- }
- }
- if (frame_id == 0) {
- // Make sure we return at least one frame.
- AddressInfo *info = &frames[0];
- info->Clear();
- info->FillAddressAndModuleInfo(addr, module_name, module_offset);
- frame_id = 1;
- }
- return frame_id;
- }
-
- bool SymbolizeData(uptr addr, DataInfo *info) {
- LoadedModule *module = FindModuleForAddress(addr);
- if (module == 0)
- return false;
- const char *module_name = module->full_name();
- uptr module_offset = addr - module->base_address();
- internal_memset(info, 0, sizeof(*info));
- info->address = addr;
- info->module = internal_strdup(module_name);
- info->module_offset = module_offset;
- const char *str = SendCommand(true, module_name, module_offset);
- if (str == 0)
- return true;
- str = ExtractToken(str, "\n", &info->name);
- str = ExtractUptr(str, " ", &info->start);
- str = ExtractUptr(str, "\n", &info->size);
- info->start += module->base_address();
- return true;
- }
-
- bool InitializeExternalSymbolizer(const char *path_to_symbolizer) {
- if (!path_to_symbolizer || path_to_symbolizer[0] == '\0') {
- path_to_symbolizer = FindPathToBinary("llvm-symbolizer");
- if (!path_to_symbolizer)
- return false;
- }
- int input_fd, output_fd;
- if (!StartSymbolizerSubprocess(path_to_symbolizer, &input_fd, &output_fd))
- return false;
- void *mem = symbolizer_allocator.Allocate(sizeof(ExternalSymbolizer));
- external_symbolizer_ = new(mem) ExternalSymbolizer(path_to_symbolizer,
- input_fd, output_fd);
- return true;
- }
-
- bool IsSymbolizerAvailable() {
- if (internal_symbolizer_ == 0)
- internal_symbolizer_ = InternalSymbolizer::get();
- return internal_symbolizer_ || external_symbolizer_;
- }
-
- void Flush() {
- if (internal_symbolizer_)
- internal_symbolizer_->Flush();
- if (external_symbolizer_)
- external_symbolizer_->Flush();
- }
-
- const char *Demangle(const char *name) {
- if (IsSymbolizerAvailable() && internal_symbolizer_ != 0)
- return internal_symbolizer_->Demangle(name);
- return DemangleCXXABI(name);
- }
-
- private:
- char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
- // First, try to use internal symbolizer.
- if (!IsSymbolizerAvailable()) {
- return 0;
- }
- if (internal_symbolizer_) {
- return internal_symbolizer_->SendCommand(is_data, module_name,
- module_offset);
- }
- // Otherwise, fall back to external symbolizer.
- if (external_symbolizer_ == 0) {
- ReportExternalSymbolizerError(
- "WARNING: Trying to symbolize code, but external "
- "symbolizer is not initialized!\n");
- return 0;
- }
- for (;;) {
- char *reply = external_symbolizer_->SendCommand(is_data, module_name,
- module_offset);
- if (reply)
- return reply;
- // Try to restart symbolizer subprocess. If we don't succeed, forget
- // about it and don't try to use it later.
- if (!external_symbolizer_->Restart()) {
- ReportExternalSymbolizerError(
- "WARNING: Failed to use and restart external symbolizer!\n");
- external_symbolizer_ = 0;
- return 0;
- }
- }
- }
-
- LoadedModule *FindModuleForAddress(uptr address) {
- bool modules_were_reloaded = false;
- if (modules_ == 0 || !modules_fresh_) {
- modules_ = (LoadedModule*)(symbolizer_allocator.Allocate(
- kMaxNumberOfModuleContexts * sizeof(LoadedModule)));
- CHECK(modules_);
- n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts,
- /* filter */ 0);
- // FIXME: Return this check when GetListOfModules is implemented on Mac.
- // CHECK_GT(n_modules_, 0);
- CHECK_LT(n_modules_, kMaxNumberOfModuleContexts);
- modules_fresh_ = true;
- modules_were_reloaded = true;
- }
- for (uptr i = 0; i < n_modules_; i++) {
- if (modules_[i].containsAddress(address)) {
- return &modules_[i];
- }
- }
- // Reload the modules and look up again, if we haven't tried it yet.
- if (!modules_were_reloaded) {
- // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors.
- // It's too aggressive to reload the list of modules each time we fail
- // to find a module for a given address.
- modules_fresh_ = false;
- return FindModuleForAddress(address);
- }
- return 0;
- }
-
- void ReportExternalSymbolizerError(const char *msg) {
- // Don't use atomics here for now, as SymbolizeCode can't be called
- // from multiple threads anyway.
- static bool reported;
- if (!reported) {
- Report(msg);
- reported = true;
- }
- }
-
- // 16K loaded modules should be enough for everyone.
- static const uptr kMaxNumberOfModuleContexts = 1 << 14;
- LoadedModule *modules_; // Array of module descriptions is leaked.
- uptr n_modules_;
- // If stale, need to reload the modules before looking up addresses.
- bool modules_fresh_;
-
- ExternalSymbolizer *external_symbolizer_; // Leaked.
- InternalSymbolizer *internal_symbolizer_; // Leaked.
-};
-
-static Symbolizer symbolizer; // Linker initialized.
-
-uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames) {
- return symbolizer.SymbolizeCode(address, frames, max_frames);
-}
-
-bool SymbolizeData(uptr address, DataInfo *info) {
- return symbolizer.SymbolizeData(address, info);
-}
-
-bool InitializeExternalSymbolizer(const char *path_to_symbolizer) {
- return symbolizer.InitializeExternalSymbolizer(path_to_symbolizer);
-}
-
-bool IsSymbolizerAvailable() {
- return symbolizer.IsSymbolizerAvailable();
-}
-
-void FlushSymbolizer() {
- symbolizer.Flush();
-}
-
-const char *Demangle(const char *name) {
- return symbolizer.Demangle(name);
-}
-
-} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_linux.cc b/lib/sanitizer_common/sanitizer_symbolizer_linux.cc
deleted file mode 100644
index 50f6da755..000000000
--- a/lib/sanitizer_common/sanitizer_symbolizer_linux.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-//===-- sanitizer_symbolizer_linux.cc -------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is shared between AddressSanitizer and ThreadSanitizer
-// run-time libraries.
-// Linux-specific implementation of symbolizer parts.
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_platform.h"
-#if SANITIZER_LINUX
-#include "sanitizer_common.h"
-#include "sanitizer_linux.h"
-
-namespace __sanitizer {
-
-#if SANITIZER_ANDROID
-void SymbolizerPrepareForSandboxing() {
- // Do nothing on Android.
-}
-#else
-static char proc_self_exe_cache_str[kMaxPathLength];
-static uptr proc_self_exe_cache_len = 0;
-
-uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
- uptr module_name_len = internal_readlink(
- "/proc/self/exe", buf, buf_len);
- int readlink_error;
- if (internal_iserror(buf_len, &readlink_error)) {
- if (proc_self_exe_cache_len) {
- // If available, use the cached module name.
- CHECK_LE(proc_self_exe_cache_len, buf_len);
- internal_strncpy(buf, proc_self_exe_cache_str, buf_len);
- module_name_len = internal_strlen(proc_self_exe_cache_str);
- } else {
- // We can't read /proc/self/exe for some reason, assume the name of the
- // binary is unknown.
- Report("WARNING: readlink(\"/proc/self/exe\") failed with errno %d, "
- "some stack frames may not be symbolized\n", readlink_error);
- module_name_len = internal_snprintf(buf, buf_len, "/proc/self/exe");
- }
- CHECK_LT(module_name_len, buf_len);
- buf[module_name_len] = '\0';
- }
- return module_name_len;
-}
-
-void SymbolizerPrepareForSandboxing() {
- if (!proc_self_exe_cache_len) {
- proc_self_exe_cache_len =
- ReadBinaryName(proc_self_exe_cache_str, kMaxPathLength);
- }
-}
-#endif // SANITIZER_ANDROID
-
-} // namespace __sanitizer
-
-#endif // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_linux_libcdep.cc
deleted file mode 100644
index f0ef23bc9..000000000
--- a/lib/sanitizer_common/sanitizer_symbolizer_linux_libcdep.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-//===-- sanitizer_symbolizer_linux_libcdep.cc -----------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is shared between AddressSanitizer and ThreadSanitizer
-// run-time libraries.
-// Linux-specific implementation of symbolizer parts.
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_platform.h"
-#if SANITIZER_LINUX
-#include "sanitizer_common.h"
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_libc.h"
-#include "sanitizer_linux.h"
-#include "sanitizer_placement_new.h"
-#include "sanitizer_symbolizer.h"
-
-// Android NDK r8e elf.h depends on stdint.h without including the latter.
-#include <stdint.h>
-
-#include <elf.h>
-#include <errno.h>
-#include <poll.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#if !SANITIZER_ANDROID
-#include <link.h>
-#endif
-
-namespace __sanitizer {
-
-#if SANITIZER_ANDROID
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
- string_predicate_t filter) {
- return 0;
-}
-#else // SANITIZER_ANDROID
-typedef ElfW(Phdr) Elf_Phdr;
-
-struct DlIteratePhdrData {
- LoadedModule *modules;
- uptr current_n;
- bool first;
- uptr max_n;
- string_predicate_t filter;
-};
-
-static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
- DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
- if (data->current_n == data->max_n)
- return 0;
- InternalScopedBuffer<char> module_name(kMaxPathLength);
- module_name.data()[0] = '\0';
- if (data->first) {
- data->first = false;
- // First module is the binary itself.
- ReadBinaryName(module_name.data(), module_name.size());
- } else if (info->dlpi_name) {
- internal_strncpy(module_name.data(), info->dlpi_name, module_name.size());
- }
- if (module_name.data()[0] == '\0')
- return 0;
- if (data->filter && !data->filter(module_name.data()))
- return 0;
- void *mem = &data->modules[data->current_n];
- LoadedModule *cur_module = new(mem) LoadedModule(module_name.data(),
- info->dlpi_addr);
- data->current_n++;
- for (int i = 0; i < info->dlpi_phnum; i++) {
- const Elf_Phdr *phdr = &info->dlpi_phdr[i];
- if (phdr->p_type == PT_LOAD) {
- uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
- uptr cur_end = cur_beg + phdr->p_memsz;
- cur_module->addAddressRange(cur_beg, cur_end);
- }
- }
- return 0;
-}
-
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
- string_predicate_t filter) {
- CHECK(modules);
- DlIteratePhdrData data = {modules, 0, true, max_modules, filter};
- dl_iterate_phdr(dl_iterate_phdr_cb, &data);
- return data.current_n;
-}
-#endif // SANITIZER_ANDROID
-
-} // namespace __sanitizer
-
-#endif // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_mac.cc b/lib/sanitizer_common/sanitizer_symbolizer_mac.cc
deleted file mode 100644
index c44e3b3cf..000000000
--- a/lib/sanitizer_common/sanitizer_symbolizer_mac.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-//===-- sanitizer_symbolizer_mac.cc ---------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is shared between AddressSanitizer and ThreadSanitizer
-// run-time libraries.
-// Mac-specific implementation of symbolizer parts.
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_platform.h"
-#if SANITIZER_MAC
-#include "sanitizer_common.h"
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_placement_new.h"
-#include "sanitizer_procmaps.h"
-#include "sanitizer_symbolizer.h"
-
-namespace __sanitizer {
-
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
- string_predicate_t filter) {
- MemoryMappingLayout memory_mapping(false);
- memory_mapping.Reset();
- uptr cur_beg, cur_end, cur_offset;
- InternalScopedBuffer<char> module_name(kMaxPathLength);
- uptr n_modules = 0;
- for (uptr i = 0;
- n_modules < max_modules &&
- memory_mapping.Next(&cur_beg, &cur_end, &cur_offset,
- module_name.data(), module_name.size(), 0);
- i++) {
- const char *cur_name = module_name.data();
- if (cur_name[0] == '\0')
- continue;
- if (filter && !filter(cur_name))
- continue;
- LoadedModule *cur_module = 0;
- if (n_modules > 0 &&
- 0 == internal_strcmp(cur_name, modules[n_modules - 1].full_name())) {
- cur_module = &modules[n_modules - 1];
- } else {
- void *mem = &modules[n_modules];
- cur_module = new(mem) LoadedModule(cur_name, cur_beg);
- n_modules++;
- }
- cur_module->addAddressRange(cur_beg, cur_end);
- }
- return n_modules;
-}
-
-void SymbolizerPrepareForSandboxing() {
- // Do nothing on Mac.
-}
-
-} // namespace __sanitizer
-
-#endif // SANITIZER_MAC
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
index b580f3701..5a300dd4f 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
@@ -14,16 +14,45 @@
#include "sanitizer_platform.h"
#if SANITIZER_POSIX
+#include "sanitizer_allocator_internal.h"
#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
+#include "sanitizer_linux.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_procmaps.h"
#include "sanitizer_symbolizer.h"
#include <errno.h>
+#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
+// C++ demangling function, as required by Itanium C++ ABI. This is weak,
+// because we do not require a C++ ABI library to be linked to a program
+// using sanitizers; if it's not present, we'll just use the mangled name.
+namespace __cxxabiv1 {
+ extern "C" SANITIZER_WEAK_ATTRIBUTE
+ char *__cxa_demangle(const char *mangled, char *buffer,
+ size_t *length, int *status);
+}
+
namespace __sanitizer {
+// Attempts to demangle the name via __cxa_demangle from __cxxabiv1.
+static const char *DemangleCXXABI(const char *name) {
+ // FIXME: __cxa_demangle aggressively insists on allocating memory.
+ // There's not much we can do about that, short of providing our
+ // 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 (const char *demangled_name =
+ __cxxabiv1::__cxa_demangle(name, 0, 0, 0))
+ return demangled_name;
+
+ return name;
+}
+
#if defined(__x86_64__)
static const char* const kSymbolizerArch = "--default-arch=x86_64";
#elif defined(__i386__)
@@ -34,8 +63,12 @@ static const char* const kSymbolizerArch = "--default-arch=powerpc64";
static const char* const kSymbolizerArch = "--default-arch=unknown";
#endif
-bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
- int *input_fd, int *output_fd) {
+static const int kSymbolizerStartupTimeMillis = 10;
+
+// Creates external symbolizer connected via pipe, user should write
+// to output_fd and read from input_fd.
+static bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
+ int *input_fd, int *output_fd) {
if (!FileExists(path_to_symbolizer)) {
Report("WARNING: invalid path to external symbolizer!\n");
return false;
@@ -121,6 +154,433 @@ bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
return true;
}
+// Extracts the prefix of "str" that consists of any characters not
+// present in "delims" string, and copies this prefix to "result", allocating
+// space for it.
+// Returns a pointer to "str" after skipping extracted prefix and first
+// delimiter char.
+static const char *ExtractToken(const char *str, const char *delims,
+ char **result) {
+ uptr prefix_len = internal_strcspn(str, delims);
+ *result = (char*)InternalAlloc(prefix_len + 1);
+ internal_memcpy(*result, str, prefix_len);
+ (*result)[prefix_len] = '\0';
+ const char *prefix_end = str + prefix_len;
+ if (*prefix_end != '\0') prefix_end++;
+ return prefix_end;
+}
+
+// Same as ExtractToken, but converts extracted token to integer.
+static const char *ExtractInt(const char *str, const char *delims,
+ int *result) {
+ char *buff;
+ const char *ret = ExtractToken(str, delims, &buff);
+ if (buff != 0) {
+ *result = (int)internal_atoll(buff);
+ }
+ InternalFree(buff);
+ return ret;
+}
+
+static const char *ExtractUptr(const char *str, const char *delims,
+ uptr *result) {
+ char *buff;
+ const char *ret = ExtractToken(str, delims, &buff);
+ if (buff != 0) {
+ *result = (uptr)internal_atoll(buff);
+ }
+ InternalFree(buff);
+ return ret;
+}
+
+// ExternalSymbolizer encapsulates communication between the tool and
+// external symbolizer program, running in a different subprocess,
+// For now we assume the following protocol:
+// For each request of the form
+// <module_name> <module_offset>
+// passed to STDIN, external symbolizer prints to STDOUT response:
+// <function_name>
+// <file_name>:<line_number>:<column_number>
+// <function_name>
+// <file_name>:<line_number>:<column_number>
+// ...
+// <empty line>
+class ExternalSymbolizer {
+ public:
+ ExternalSymbolizer(const char *path, int input_fd, int output_fd)
+ : path_(path),
+ input_fd_(input_fd),
+ output_fd_(output_fd),
+ times_restarted_(0) {
+ CHECK(path_);
+ CHECK_NE(input_fd_, kInvalidFd);
+ CHECK_NE(output_fd_, kInvalidFd);
+ }
+
+ char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ CHECK(module_name);
+ internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n",
+ is_data ? "DATA " : "", module_name, module_offset);
+ if (!writeToSymbolizer(buffer_, internal_strlen(buffer_)))
+ return 0;
+ if (!readFromSymbolizer(buffer_, kBufferSize))
+ return 0;
+ return buffer_;
+ }
+
+ bool Restart() {
+ if (times_restarted_ >= kMaxTimesRestarted) return false;
+ times_restarted_++;
+ internal_close(input_fd_);
+ internal_close(output_fd_);
+ return StartSymbolizerSubprocess(path_, &input_fd_, &output_fd_);
+ }
+
+ void Flush() {
+ }
+
+ private:
+ bool readFromSymbolizer(char *buffer, uptr max_length) {
+ if (max_length == 0)
+ return true;
+ uptr read_len = 0;
+ while (true) {
+ uptr just_read = internal_read(input_fd_, buffer + read_len,
+ max_length - read_len);
+ // We can't read 0 bytes, as we don't expect external symbolizer to close
+ // its stdout.
+ if (just_read == 0 || just_read == (uptr)-1) {
+ Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_);
+ return false;
+ }
+ read_len += just_read;
+ // Empty line marks the end of symbolizer output.
+ if (read_len >= 2 && buffer[read_len - 1] == '\n' &&
+ buffer[read_len - 2] == '\n') {
+ break;
+ }
+ }
+ return true;
+ }
+
+ bool writeToSymbolizer(const char *buffer, uptr length) {
+ if (length == 0)
+ return true;
+ uptr write_len = internal_write(output_fd_, buffer, length);
+ if (write_len == 0 || write_len == (uptr)-1) {
+ Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_);
+ return false;
+ }
+ return true;
+ }
+
+ const char *path_;
+ int input_fd_;
+ int output_fd_;
+
+ static const uptr kBufferSize = 16 * 1024;
+ char buffer_[kBufferSize];
+
+ static const uptr kMaxTimesRestarted = 5;
+ uptr times_restarted_;
+};
+
+static LowLevelAllocator symbolizer_allocator; // Linker initialized.
+
+#if SANITIZER_SUPPORTS_WEAK_HOOKS
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset,
+ char *Buffer, int MaxLength);
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset,
+ char *Buffer, int MaxLength);
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_symbolize_flush();
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+int __sanitizer_symbolize_demangle(const char *Name, char *Buffer,
+ int MaxLength);
+} // extern "C"
+
+class InternalSymbolizer {
+ public:
+ typedef bool (*SanitizerSymbolizeFn)(const char*, u64, char*, int);
+
+ static InternalSymbolizer *get() {
+ if (__sanitizer_symbolize_code != 0 &&
+ __sanitizer_symbolize_data != 0) {
+ void *mem = symbolizer_allocator.Allocate(sizeof(InternalSymbolizer));
+ return new(mem) InternalSymbolizer();
+ }
+ return 0;
+ }
+
+ char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ SanitizerSymbolizeFn symbolize_fn = is_data ? __sanitizer_symbolize_data
+ : __sanitizer_symbolize_code;
+ if (symbolize_fn(module_name, module_offset, buffer_, kBufferSize))
+ return buffer_;
+ return 0;
+ }
+
+ void Flush() {
+ if (__sanitizer_symbolize_flush)
+ __sanitizer_symbolize_flush();
+ }
+
+ const char *Demangle(const char *name) {
+ if (__sanitizer_symbolize_demangle) {
+ for (uptr res_length = 1024;
+ res_length <= InternalSizeClassMap::kMaxSize;) {
+ char *res_buff = static_cast<char*>(InternalAlloc(res_length));
+ uptr req_length =
+ __sanitizer_symbolize_demangle(name, res_buff, res_length);
+ if (req_length > res_length) {
+ res_length = req_length + 1;
+ InternalFree(res_buff);
+ continue;
+ }
+ return res_buff;
+ }
+ }
+ return name;
+ }
+
+ private:
+ InternalSymbolizer() { }
+
+ static const int kBufferSize = 16 * 1024;
+ static const int kMaxDemangledNameSize = 1024;
+ char buffer_[kBufferSize];
+};
+#else // SANITIZER_SUPPORTS_WEAK_HOOKS
+
+class InternalSymbolizer {
+ public:
+ static InternalSymbolizer *get() { return 0; }
+ char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ return 0;
+ }
+ void Flush() { }
+ const char *Demangle(const char *name) { return name; }
+};
+
+#endif // SANITIZER_SUPPORTS_WEAK_HOOKS
+
+class Symbolizer : public SymbolizerInterface {
+ // This class has no constructor, as global constructors are forbidden in
+ // sanitizer_common. It should be linker initialized instead.
+ public:
+ uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) {
+ if (max_frames == 0)
+ return 0;
+ LoadedModule *module = FindModuleForAddress(addr);
+ if (module == 0)
+ return 0;
+ const char *module_name = module->full_name();
+ uptr module_offset = addr - module->base_address();
+ const char *str = SendCommand(false, module_name, module_offset);
+ if (str == 0) {
+ // External symbolizer was not initialized or failed. Fill only data
+ // about module name and offset.
+ AddressInfo *info = &frames[0];
+ info->Clear();
+ info->FillAddressAndModuleInfo(addr, module_name, module_offset);
+ return 1;
+ }
+ uptr frame_id = 0;
+ for (frame_id = 0; frame_id < max_frames; frame_id++) {
+ AddressInfo *info = &frames[frame_id];
+ char *function_name = 0;
+ str = ExtractToken(str, "\n", &function_name);
+ CHECK(function_name);
+ if (function_name[0] == '\0') {
+ // There are no more frames.
+ break;
+ }
+ info->Clear();
+ info->FillAddressAndModuleInfo(addr, module_name, module_offset);
+ info->function = function_name;
+ // Parse <file>:<line>:<column> buffer.
+ char *file_line_info = 0;
+ str = ExtractToken(str, "\n", &file_line_info);
+ CHECK(file_line_info);
+ const char *line_info = ExtractToken(file_line_info, ":", &info->file);
+ line_info = ExtractInt(line_info, ":", &info->line);
+ line_info = ExtractInt(line_info, "", &info->column);
+ InternalFree(file_line_info);
+
+ // Functions and filenames can be "??", in which case we write 0
+ // to address info to mark that names are unknown.
+ if (0 == internal_strcmp(info->function, "??")) {
+ InternalFree(info->function);
+ info->function = 0;
+ }
+ if (0 == internal_strcmp(info->file, "??")) {
+ InternalFree(info->file);
+ info->file = 0;
+ }
+ }
+ if (frame_id == 0) {
+ // Make sure we return at least one frame.
+ AddressInfo *info = &frames[0];
+ info->Clear();
+ info->FillAddressAndModuleInfo(addr, module_name, module_offset);
+ frame_id = 1;
+ }
+ return frame_id;
+ }
+
+ bool SymbolizeData(uptr addr, DataInfo *info) {
+ LoadedModule *module = FindModuleForAddress(addr);
+ if (module == 0)
+ return false;
+ const char *module_name = module->full_name();
+ uptr module_offset = addr - module->base_address();
+ internal_memset(info, 0, sizeof(*info));
+ info->address = addr;
+ info->module = internal_strdup(module_name);
+ info->module_offset = module_offset;
+ const char *str = SendCommand(true, module_name, module_offset);
+ if (str == 0)
+ return true;
+ str = ExtractToken(str, "\n", &info->name);
+ str = ExtractUptr(str, " ", &info->start);
+ str = ExtractUptr(str, "\n", &info->size);
+ info->start += module->base_address();
+ return true;
+ }
+
+ bool InitializeExternal(const char *path_to_symbolizer) {
+ if (!path_to_symbolizer || path_to_symbolizer[0] == '\0') {
+ path_to_symbolizer = FindPathToBinary("llvm-symbolizer");
+ if (!path_to_symbolizer)
+ return false;
+ }
+ int input_fd, output_fd;
+ if (!StartSymbolizerSubprocess(path_to_symbolizer, &input_fd, &output_fd))
+ return false;
+ void *mem = symbolizer_allocator.Allocate(sizeof(ExternalSymbolizer));
+ external_symbolizer_ = new(mem) ExternalSymbolizer(path_to_symbolizer,
+ input_fd, output_fd);
+ return true;
+ }
+
+ bool IsAvailable() {
+ if (internal_symbolizer_ == 0)
+ internal_symbolizer_ = InternalSymbolizer::get();
+ return internal_symbolizer_ || external_symbolizer_;
+ }
+
+ void Flush() {
+ if (internal_symbolizer_)
+ internal_symbolizer_->Flush();
+ if (external_symbolizer_)
+ external_symbolizer_->Flush();
+ }
+
+ const char *Demangle(const char *name) {
+ if (IsAvailable() && internal_symbolizer_ != 0)
+ return internal_symbolizer_->Demangle(name);
+ return DemangleCXXABI(name);
+ }
+
+ void PrepareForSandboxing() {
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ // Cache /proc/self/exe on Linux.
+ CacheBinaryName();
+#endif
+ }
+
+ private:
+ char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ // First, try to use internal symbolizer.
+ if (!IsAvailable()) {
+ return 0;
+ }
+ if (internal_symbolizer_) {
+ return internal_symbolizer_->SendCommand(is_data, module_name,
+ module_offset);
+ }
+ // Otherwise, fall back to external symbolizer.
+ if (external_symbolizer_ == 0) {
+ ReportExternalSymbolizerError(
+ "WARNING: Trying to symbolize code, but external "
+ "symbolizer is not initialized!\n");
+ return 0;
+ }
+ for (;;) {
+ char *reply = external_symbolizer_->SendCommand(is_data, module_name,
+ module_offset);
+ if (reply)
+ return reply;
+ // Try to restart symbolizer subprocess. If we don't succeed, forget
+ // about it and don't try to use it later.
+ if (!external_symbolizer_->Restart()) {
+ ReportExternalSymbolizerError(
+ "WARNING: Failed to use and restart external symbolizer!\n");
+ external_symbolizer_ = 0;
+ return 0;
+ }
+ }
+ }
+
+ LoadedModule *FindModuleForAddress(uptr address) {
+ bool modules_were_reloaded = false;
+ if (modules_ == 0 || !modules_fresh_) {
+ modules_ = (LoadedModule*)(symbolizer_allocator.Allocate(
+ kMaxNumberOfModuleContexts * sizeof(LoadedModule)));
+ CHECK(modules_);
+ n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts,
+ /* filter */ 0);
+ // FIXME: Return this check when GetListOfModules is implemented on Mac.
+ // CHECK_GT(n_modules_, 0);
+ CHECK_LT(n_modules_, kMaxNumberOfModuleContexts);
+ modules_fresh_ = true;
+ modules_were_reloaded = true;
+ }
+ for (uptr i = 0; i < n_modules_; i++) {
+ if (modules_[i].containsAddress(address)) {
+ return &modules_[i];
+ }
+ }
+ // Reload the modules and look up again, if we haven't tried it yet.
+ if (!modules_were_reloaded) {
+ // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors.
+ // It's too aggressive to reload the list of modules each time we fail
+ // to find a module for a given address.
+ modules_fresh_ = false;
+ return FindModuleForAddress(address);
+ }
+ return 0;
+ }
+
+ void ReportExternalSymbolizerError(const char *msg) {
+ // Don't use atomics here for now, as SymbolizeCode can't be called
+ // from multiple threads anyway.
+ static bool reported;
+ if (!reported) {
+ Report(msg);
+ reported = true;
+ }
+ }
+
+ // 16K loaded modules should be enough for everyone.
+ static const uptr kMaxNumberOfModuleContexts = 1 << 14;
+ LoadedModule *modules_; // Array of module descriptions is leaked.
+ uptr n_modules_;
+ // If stale, need to reload the modules before looking up addresses.
+ bool modules_fresh_;
+
+ ExternalSymbolizer *external_symbolizer_; // Leaked.
+ InternalSymbolizer *internal_symbolizer_; // Leaked.
+};
+
+static Symbolizer symbolizer; // Linker initialized.
+
+SymbolizerInterface *getSymbolizer() {
+ return &symbolizer;
+}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.cc b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
index e2bd66440..de7a5b9c7 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
@@ -14,29 +14,15 @@
#include "sanitizer_platform.h"
#if SANITIZER_WINDOWS
-#include <windows.h>
-
#include "sanitizer_internal_defs.h"
#include "sanitizer_symbolizer.h"
namespace __sanitizer {
-bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
- int *input_fd, int *output_fd) {
- UNIMPLEMENTED();
-}
-
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
- string_predicate_t filter) {
- UNIMPLEMENTED();
-};
-
-void SymbolizerPrepareForSandboxing() {
- // Do nothing on Windows.
-}
+static SymbolizerInterface win_symbolizer; // Linker initialized.
-const char *DemangleCXXABI(const char *name) {
- return name;
+SymbolizerInterface *getSymbolizer() {
+ return &win_symbolizer;
}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
index 4c5327ea9..49028bc21 100644
--- a/lib/sanitizer_common/sanitizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -218,6 +218,11 @@ void Abort() {
_exit(-1); // abort is not NORETURN on Windows.
}
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+ string_predicate_t filter) {
+ UNIMPLEMENTED();
+};
+
#ifndef SANITIZER_GO
int Atexit(void (*function)(void)) {
return atexit(function);
diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc
index 820a6eeb9..7badaf786 100644
--- a/lib/tsan/rtl/tsan_rtl.cc
+++ b/lib/tsan/rtl/tsan_rtl.cc
@@ -217,7 +217,7 @@ void Initialize(ThreadState *thr) {
// Initialize external symbolizer before internal threads are started.
const char *external_symbolizer = flags()->external_symbolizer_path;
if (external_symbolizer != 0 && external_symbolizer[0] != '\0') {
- if (!InitializeExternalSymbolizer(external_symbolizer)) {
+ if (!getSymbolizer()->InitializeExternal(external_symbolizer)) {
Printf("Failed to start external symbolizer: '%s'\n",
external_symbolizer);
Die();
diff --git a/lib/tsan/rtl/tsan_symbolize.cc b/lib/tsan/rtl/tsan_symbolize.cc
index 12226064f..5b178389b 100644
--- a/lib/tsan/rtl/tsan_symbolize.cc
+++ b/lib/tsan/rtl/tsan_symbolize.cc
@@ -70,15 +70,15 @@ static ReportStack *NewReportStackEntry(const AddressInfo &info) {
}
ReportStack *SymbolizeCode(uptr addr) {
- if (!IsSymbolizerAvailable())
+ if (!getSymbolizer()->IsAvailable())
return SymbolizeCodeAddr2Line(addr);
ScopedInSymbolizer in_symbolizer;
static const uptr kMaxAddrFrames = 16;
InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
for (uptr i = 0; i < kMaxAddrFrames; i++)
new(&addr_frames[i]) AddressInfo();
- uptr addr_frames_num = __sanitizer::SymbolizeCode(addr, addr_frames.data(),
- kMaxAddrFrames);
+ uptr addr_frames_num =
+ getSymbolizer()->SymbolizeCode(addr, addr_frames.data(), kMaxAddrFrames);
if (addr_frames_num == 0)
return NewReportStackEntry(addr);
ReportStack *top = 0;
@@ -97,11 +97,11 @@ ReportStack *SymbolizeCode(uptr addr) {
}
ReportLocation *SymbolizeData(uptr addr) {
- if (!IsSymbolizerAvailable())
+ if (!getSymbolizer()->IsAvailable())
return 0;
ScopedInSymbolizer in_symbolizer;
DataInfo info;
- if (!__sanitizer::SymbolizeData(addr, &info))
+ if (!getSymbolizer()->SymbolizeData(addr, &info))
return 0;
ReportLocation *ent = (ReportLocation*)internal_alloc(MBlockReportStack,
sizeof(ReportLocation));
@@ -117,10 +117,10 @@ ReportLocation *SymbolizeData(uptr addr) {
}
void SymbolizeFlush() {
- if (!IsSymbolizerAvailable())
+ if (!getSymbolizer()->IsAvailable())
return;
ScopedInSymbolizer in_symbolizer;
- __sanitizer::FlushSymbolizer();
+ getSymbolizer()->Flush();
}
} // namespace __tsan
diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc
index 3f9276146..65df48c83 100644
--- a/lib/ubsan/ubsan_diag.cc
+++ b/lib/ubsan/ubsan_diag.cc
@@ -28,7 +28,8 @@ Location __ubsan::getCallerLocation(uptr CallerLoc) {
uptr Loc = StackTrace::GetPreviousInstructionPc(CallerLoc);
AddressInfo Info;
- if (!SymbolizeCode(Loc, &Info, 1) || !Info.module || !*Info.module)
+ if (!getSymbolizer()->SymbolizeCode(Loc, &Info, 1) ||
+ !Info.module || !*Info.module)
return Location(Loc);
if (!Info.file)
@@ -109,7 +110,7 @@ static void renderText(const char *Message, const Diag::Arg *Args) {
Printf("%s", A.String);
break;
case Diag::AK_Mangled: {
- Printf("'%s'", Demangle(A.String));
+ Printf("'%s'", getSymbolizer()->Demangle(A.String));
break;
}
case Diag::AK_SInt: