diff options
Diffstat (limited to 'compiler-rt')
26 files changed, 725 insertions, 866 deletions
diff --git a/compiler-rt/lib/asan/asan_report.cc b/compiler-rt/lib/asan/asan_report.cc index 7717cd26871..b77d265b478 100644 --- a/compiler-rt/lib/asan/asan_report.cc +++ b/compiler-rt/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/compiler-rt/lib/asan/asan_rtl.cc b/compiler-rt/lib/asan/asan_rtl.cc index 4c3e776578e..80bd5918013 100644 --- a/compiler-rt/lib/asan/asan_rtl.cc +++ b/compiler-rt/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/compiler-rt/lib/lsan/lsan.cc b/compiler-rt/lib/lsan/lsan.cc index 99b165b5d8c..7f37da6c332 100644 --- a/compiler-rt/lib/lsan/lsan.cc +++ b/compiler-rt/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/compiler-rt/lib/lsan/lsan_common.cc b/compiler-rt/lib/lsan/lsan_common.cc index 1d895a3b169..7fa067522fe 100644 --- a/compiler-rt/lib/lsan/lsan_common.cc +++ b/compiler-rt/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/compiler-rt/lib/msan/msan.cc b/compiler-rt/lib/msan/msan.cc index afe7f8e725f..8388f307f6a 100644 --- a/compiler-rt/lib/msan/msan.cc +++ b/compiler-rt/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/compiler-rt/lib/msan/msan_report.cc b/compiler-rt/lib/msan/msan_report.cc index b1cfe87b4cc..2f80d68f6ec 100644 --- a/compiler-rt/lib/msan/msan_report.cc +++ b/compiler-rt/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/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt index 93e3a84cd02..3aa56b1f655 100644 --- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt +++ b/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_common.cc b/compiler-rt/lib/sanitizer_common/sanitizer_common.cc index 4aab65d914b..97198ea2cc6 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.cc +++ b/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h index abed9440b17..90f321917df 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc index d3c8d6917ac..aa6110b230f 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc +++ b/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_linux.h b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h index c0fba48da13..4c0450e8626 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h +++ b/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 6569a25821d..a00b5bb4c44 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc index ea87128e7f2..1ba02845335 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc +++ b/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc index e279a9ff2f3..665627bc3dc 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc +++ b/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h index 90ee784f561..383e1d4ac97 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h +++ b/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_itanium.cc b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_itanium.cc deleted file mode 100644 index 086e84f5ad0..00000000000 --- a/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc deleted file mode 100644 index 9ccd622153e..00000000000 --- a/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_linux.cc b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_linux.cc deleted file mode 100644 index 50f6da755e1..00000000000 --- a/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_linux_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_linux_libcdep.cc deleted file mode 100644 index f0ef23bc99a..00000000000 --- a/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cc b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cc deleted file mode 100644 index c44e3b3cfaf..00000000000 --- a/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc index b580f37011c..5a300dd4ffe 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ b/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cc b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cc index e2bd6644090..de7a5b9c781 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cc +++ b/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_win.cc b/compiler-rt/lib/sanitizer_common/sanitizer_win.cc index 4c5327ea962..49028bc2105 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cc +++ b/compiler-rt/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/compiler-rt/lib/tsan/rtl/tsan_rtl.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl.cc index 820a6eeb9b2..7badaf78643 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cc +++ b/compiler-rt/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/compiler-rt/lib/tsan/rtl/tsan_symbolize.cc b/compiler-rt/lib/tsan/rtl/tsan_symbolize.cc index 12226064f5a..5b178389bfa 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_symbolize.cc +++ b/compiler-rt/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/compiler-rt/lib/ubsan/ubsan_diag.cc b/compiler-rt/lib/ubsan/ubsan_diag.cc index 3f92761465d..65df48c83ab 100644 --- a/compiler-rt/lib/ubsan/ubsan_diag.cc +++ b/compiler-rt/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: |