diff options
author | kcc <kcc@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-11-13 20:41:38 +0000 |
---|---|---|
committer | kcc <kcc@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-11-13 20:41:38 +0000 |
commit | 0328398d933acf544888379949eb5c061dfcfe02 (patch) | |
tree | 5275c09e09235f15fe0ae824d5bbef4151a7d1f9 /libsanitizer/sanitizer_common | |
parent | 85f72a88010a2885f602ca074c084e55759943ed (diff) | |
download | gcc-0328398d933acf544888379949eb5c061dfcfe02.tar.gz |
libsanitizer merge from upstream r221802
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@217518 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libsanitizer/sanitizer_common')
32 files changed, 531 insertions, 271 deletions
diff --git a/libsanitizer/sanitizer_common/Makefile.am b/libsanitizer/sanitizer_common/Makefile.am index bc1f18c2a18..c5da0c15119 100644 --- a/libsanitizer/sanitizer_common/Makefile.am +++ b/libsanitizer/sanitizer_common/Makefile.am @@ -6,6 +6,7 @@ gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER) DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fno-rtti -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros AM_CXXFLAGS += $(LIBSTDCXX_RAW_CXX_CXXFLAGS) +AM_CXXFLAGS += -std=c++11 if LIBBACKTRACE_SUPPORTED AM_CXXFLAGS += -DSANITIZER_LIBBACKTRACE -DSANITIZER_CP_DEMANGLE \ -I $(top_srcdir)/../libbacktrace \ @@ -44,6 +45,7 @@ sanitizer_common_files = \ sanitizer_stackdepot.cc \ sanitizer_stacktrace.cc \ sanitizer_stacktrace_libcdep.cc \ + sanitizer_stacktrace_printer.cc \ sanitizer_stoptheworld_linux_libcdep.cc \ sanitizer_suppressions.cc \ sanitizer_symbolizer.cc \ diff --git a/libsanitizer/sanitizer_common/Makefile.in b/libsanitizer/sanitizer_common/Makefile.in index d82b4834efc..db02613eb81 100644 --- a/libsanitizer/sanitizer_common/Makefile.in +++ b/libsanitizer/sanitizer_common/Makefile.in @@ -78,6 +78,7 @@ am__objects_1 = sanitizer_allocator.lo sanitizer_common.lo \ sanitizer_procmaps_linux.lo sanitizer_procmaps_mac.lo \ sanitizer_stackdepot.lo sanitizer_stacktrace.lo \ sanitizer_stacktrace_libcdep.lo \ + sanitizer_stacktrace_printer.lo \ sanitizer_stoptheworld_linux_libcdep.lo \ sanitizer_suppressions.lo sanitizer_symbolizer.lo \ sanitizer_symbolizer_libbacktrace.lo \ @@ -252,7 +253,7 @@ gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER) AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \ -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fno-rtti \ -fomit-frame-pointer -funwind-tables -fvisibility=hidden \ - -Wno-variadic-macros $(LIBSTDCXX_RAW_CXX_CXXFLAGS) \ + -Wno-variadic-macros $(LIBSTDCXX_RAW_CXX_CXXFLAGS) -std=c++11 \ $(am__append_1) ACLOCAL_AMFLAGS = -I m4 noinst_LTLIBRARIES = libsanitizer_common.la @@ -283,6 +284,7 @@ sanitizer_common_files = \ sanitizer_stackdepot.cc \ sanitizer_stacktrace.cc \ sanitizer_stacktrace_libcdep.cc \ + sanitizer_stacktrace_printer.cc \ sanitizer_stoptheworld_linux_libcdep.cc \ sanitizer_suppressions.cc \ sanitizer_symbolizer.cc \ @@ -414,6 +416,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stackdepot.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stacktrace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stacktrace_libcdep.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stacktrace_printer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stoptheworld_linux_libcdep.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_suppressions.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer.Plo@am__quote@ diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator.h b/libsanitizer/sanitizer_common/sanitizer_allocator.h index fb394129202..dd5539a2087 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator.h +++ b/libsanitizer/sanitizer_common/sanitizer_allocator.h @@ -459,6 +459,11 @@ class SizeClassAllocator64 { } } + static uptr AdditionalSize() { + return RoundUpTo(sizeof(RegionInfo) * kNumClassesRounded, + GetPageSizeCached()); + } + typedef SizeClassMap SizeClassMapT; static const uptr kNumClasses = SizeClassMap::kNumClasses; static const uptr kNumClassesRounded = SizeClassMap::kNumClassesRounded; @@ -488,11 +493,6 @@ class SizeClassAllocator64 { }; COMPILER_CHECK(sizeof(RegionInfo) >= kCacheLineSize); - static uptr AdditionalSize() { - return RoundUpTo(sizeof(RegionInfo) * kNumClassesRounded, - GetPageSizeCached()); - } - RegionInfo *GetRegionInfo(uptr class_id) { CHECK_LT(class_id, kNumClasses); RegionInfo *regions = reinterpret_cast<RegionInfo*>(kSpaceBeg + kSpaceSize); @@ -1013,12 +1013,15 @@ class LargeMmapAllocator { if (map_size < size) return AllocatorReturnNull(); // Overflow. uptr map_beg = reinterpret_cast<uptr>( MmapOrDie(map_size, "LargeMmapAllocator")); + CHECK(IsAligned(map_beg, page_size_)); MapUnmapCallback().OnMap(map_beg, map_size); uptr map_end = map_beg + map_size; uptr res = map_beg + page_size_; if (res & (alignment - 1)) // Align. res += alignment - (res & (alignment - 1)); - CHECK_EQ(0, res & (alignment - 1)); + CHECK(IsAligned(res, alignment)); + CHECK(IsAligned(res, page_size_)); + CHECK_GE(res + size, map_beg); CHECK_LE(res + size, map_end); Header *h = GetHeader(res); h->size = size; diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cc b/libsanitizer/sanitizer_common/sanitizer_common.cc index d4da3206e13..f06efffb325 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common.cc +++ b/libsanitizer/sanitizer_common/sanitizer_common.cc @@ -153,23 +153,12 @@ const char *StripPathPrefix(const char *filepath, return pos; } -void PrintSourceLocation(InternalScopedString *buffer, const char *file, - int line, int column) { - CHECK(file); - buffer->append("%s", - StripPathPrefix(file, common_flags()->strip_path_prefix)); - if (line > 0) { - buffer->append(":%d", line); - if (column > 0) - buffer->append(":%d", column); - } -} - -void PrintModuleAndOffset(InternalScopedString *buffer, const char *module, - uptr offset) { - buffer->append("(%s+0x%zx)", - StripPathPrefix(module, common_flags()->strip_path_prefix), - offset); +const char *StripModuleName(const char *module) { + if (module == 0) + return 0; + if (const char *slash_pos = internal_strrchr(module, '/')) + return slash_pos + 1; + return module; } void ReportErrorSummary(const char *error_message) { @@ -215,17 +204,6 @@ bool LoadedModule::containsAddress(uptr address) const { return false; } -char *StripModuleName(const char *module) { - if (module == 0) - return 0; - const char *short_module_name = internal_strrchr(module, '/'); - if (short_module_name) - short_module_name += 1; - else - short_module_name = module; - return internal_strdup(short_module_name); -} - static atomic_uintptr_t g_total_mmaped; void IncreaseTotalMmap(uptr size) { diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h index a9db1082f48..a8924913872 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common.h +++ b/libsanitizer/sanitizer_common/sanitizer_common.h @@ -170,10 +170,8 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size); // Error report formatting. const char *StripPathPrefix(const char *filepath, const char *strip_file_prefix); -void PrintSourceLocation(InternalScopedString *buffer, const char *file, - int line, int column); -void PrintModuleAndOffset(InternalScopedString *buffer, - const char *module, uptr offset); +// Strip the directories from the module name. +const char *StripModuleName(const char *module); // OS void DisableCoreDumperIfNecessary(); @@ -207,9 +205,6 @@ void SleepForMillis(int millis); u64 NanoTime(); int Atexit(void (*function)(void)); void SortArray(uptr *array, uptr size); -// Strip the directories from the module name, return a new string allocated -// with internal_strdup. -char *StripModuleName(const char *module); // Exit void NORETURN Abort(); diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc index f55a31de77e..10f321838e8 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc @@ -39,6 +39,10 @@ #define va_copy(dst, src) ((dst) = (src)) #endif // _WIN32 +#if SANITIZER_FREEBSD +#define pthread_setname_np pthread_set_name_np +#endif + #ifndef COMMON_INTERCEPTOR_INITIALIZE_RANGE #define COMMON_INTERCEPTOR_INITIALIZE_RANGE(p, size) {} #endif diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep.cc index 9b02cd75017..214e8a98d0f 100644 --- a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -36,6 +36,7 @@ #include "sanitizer_mutex.h" #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" +#include "sanitizer_symbolizer.h" #include "sanitizer_flags.h" atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once. @@ -61,6 +62,9 @@ class CoverageData { void AfterFork(int child_pid); void Extend(uptr npcs); void Add(uptr pc); + void IndirCall(uptr caller, uptr callee, uptr callee_cache[], + uptr cache_size); + void DumpCallerCalleePairs(); uptr *data(); uptr size(); @@ -83,6 +87,14 @@ class CoverageData { uptr pc_array_mapped_size; // Descriptor of the file mapped pc array. int pc_fd; + + // Caller-Callee (cc) array, size and current index. + static const uptr kCcArrayMaxSize = FIRST_32_SECOND_64(1 << 18, 1 << 24); + uptr **cc_array; + atomic_uintptr_t cc_array_index; + atomic_uintptr_t cc_array_size; + + StaticSpinMutex mu; void DirectOpen(); @@ -116,6 +128,11 @@ void CoverageData::Init() { atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed); atomic_store(&pc_array_index, 0, memory_order_relaxed); } + + cc_array = reinterpret_cast<uptr **>(MmapNoReserveOrDie( + sizeof(uptr *) * kCcArrayMaxSize, "CovInit::cc_array")); + atomic_store(&cc_array_size, kCcArrayMaxSize, memory_order_relaxed); + atomic_store(&cc_array_index, 0, memory_order_relaxed); } void CoverageData::ReInit() { @@ -184,6 +201,38 @@ void CoverageData::Add(uptr pc) { pc_array[idx] = pc; } +// Registers a pair caller=>callee. +// When a given caller is seen for the first time, the callee_cache is added +// to the global array cc_array, callee_cache[0] is set to caller and +// callee_cache[1] is set to cache_size. +// Then we are trying to add callee to callee_cache [2,cache_size) if it is +// not there yet. +// If the cache is full we drop the callee (may want to fix this later). +void CoverageData::IndirCall(uptr caller, uptr callee, uptr callee_cache[], + uptr cache_size) { + if (!cc_array) return; + atomic_uintptr_t *atomic_callee_cache = + reinterpret_cast<atomic_uintptr_t *>(callee_cache); + uptr zero = 0; + if (atomic_compare_exchange_strong(&atomic_callee_cache[0], &zero, caller, + memory_order_seq_cst)) { + uptr idx = atomic_fetch_add(&cc_array_index, 1, memory_order_relaxed); + CHECK_LT(idx * sizeof(uptr), + atomic_load(&cc_array_size, memory_order_acquire)); + callee_cache[1] = cache_size; + cc_array[idx] = callee_cache; + } + CHECK_EQ(atomic_load(&atomic_callee_cache[0], memory_order_relaxed), caller); + for (uptr i = 2; i < cache_size; i++) { + uptr was = 0; + if (atomic_compare_exchange_strong(&atomic_callee_cache[i], &was, callee, + memory_order_seq_cst)) + return; + if (was == callee) // Already have this callee. + return; + } +} + uptr *CoverageData::data() { return pc_array; } @@ -266,6 +315,45 @@ static int CovOpenFile(bool packed, const char* name) { return fd; } +// This function dumps the caller=>callee pairs into a file as a sequence of +// lines like "module_name offset". +void CoverageData::DumpCallerCalleePairs() { + uptr max_idx = atomic_load(&cc_array_index, memory_order_relaxed); + if (!max_idx) return; + auto sym = Symbolizer::GetOrInit(); + if (!sym) + return; + InternalScopedString out(32 << 20); + uptr total = 0; + for (uptr i = 0; i < max_idx; i++) { + uptr *cc_cache = cc_array[i]; + CHECK(cc_cache); + uptr caller = cc_cache[0]; + uptr n_callees = cc_cache[1]; + const char *caller_module_name = "<unknown>"; + uptr caller_module_address = 0; + sym->GetModuleNameAndOffsetForPC(caller, &caller_module_name, + &caller_module_address); + for (uptr j = 2; j < n_callees; j++) { + uptr callee = cc_cache[j]; + if (!callee) break; + total++; + const char *callee_module_name = "<unknown>"; + uptr callee_module_address = 0; + sym->GetModuleNameAndOffsetForPC(callee, &callee_module_name, + &callee_module_address); + out.append("%s 0x%zx\n%s 0x%zx\n", caller_module_name, + caller_module_address, callee_module_name, + callee_module_address); + } + } + int fd = CovOpenFile(false, "caller-callee"); + if (fd < 0) return; + internal_write(fd, out.data(), out.length()); + internal_close(fd); + VReport(1, " CovDump: %zd caller-callee pairs written\n", total); +} + // Dump the coverage on disk. static void CovDump() { if (!common_flags()->coverage || common_flags()->coverage_direct) return; @@ -297,7 +385,7 @@ static void CovDump() { CHECK_LE(diff, 0xffffffffU); offsets.push_back(static_cast<u32>(diff)); } - char *module_name = StripModuleName(module.data()); + const char *module_name = StripModuleName(module.data()); if (cov_sandboxed) { if (cov_fd >= 0) { CovWritePacked(internal_getpid(), module_name, offsets.data(), @@ -317,11 +405,11 @@ static void CovDump() { vb - old_vb); } } - InternalFree(module_name); } } if (cov_fd >= 0) internal_close(cov_fd); + coverage_data.DumpCallerCalleePairs(); #endif // !SANITIZER_WINDOWS } @@ -357,6 +445,11 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov() { coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC())); } +SANITIZER_INTERFACE_ATTRIBUTE void +__sanitizer_cov_indir_call16(uptr callee, uptr callee_cache16[]) { + coverage_data.IndirCall(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()), + callee, callee_cache16, 16); +} SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); } SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() { coverage_data.Init(); diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc index a134053a719..b88814b8167 100644 --- a/libsanitizer/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc +++ b/libsanitizer/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc @@ -78,7 +78,7 @@ void CovUpdateMapping(uptr caller_pc) { text.append("%d\n", sizeof(uptr) * 8); for (int i = 0; i < n_modules; ++i) { - char *module_name = StripModuleName(modules[i].full_name()); + const char *module_name = StripModuleName(modules[i].full_name()); for (unsigned j = 0; j < modules[i].n_ranges(); ++j) { if (modules[i].address_range_executable(j)) { uptr start = modules[i].address_range_start(j); @@ -89,7 +89,6 @@ void CovUpdateMapping(uptr caller_pc) { cached_mapping.SetModuleRange(start, end); } } - InternalFree(module_name); } int err; diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.cc b/libsanitizer/sanitizer_common/sanitizer_flags.cc index 476f793c27d..d7e7118212e 100644 --- a/libsanitizer/sanitizer_common/sanitizer_flags.cc +++ b/libsanitizer/sanitizer_common/sanitizer_flags.cc @@ -37,6 +37,7 @@ void SetCommonFlagsDefaults(CommonFlags *f) { f->external_symbolizer_path = 0; f->allow_addr2line = false; f->strip_path_prefix = ""; + f->fast_unwind_on_check = false; f->fast_unwind_on_fatal = false; f->fast_unwind_on_malloc = true; f->handle_ioctl = false; @@ -64,6 +65,8 @@ void SetCommonFlagsDefaults(CommonFlags *f) { f->suppressions = ""; f->print_suppressions = true; f->disable_coredump = (SANITIZER_WORDSIZE == 64); + f->symbolize_inline_frames = true; + f->stack_trace_format = "DEFAULT"; } void ParseCommonFlagsFromString(CommonFlags *f, const char *str) { @@ -79,6 +82,9 @@ void ParseCommonFlagsFromString(CommonFlags *f, const char *str) { "unavailable."); ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix", "Strips this prefix from file paths in error reports."); + ParseFlag(str, &f->fast_unwind_on_check, "fast_unwind_on_check", + "If available, use the fast frame-pointer-based unwinder on " + "internal CHECK failures."); ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal", "If available, use the fast frame-pointer-based unwinder on fatal " "errors."); @@ -152,6 +158,12 @@ void ParseCommonFlagsFromString(CommonFlags *f, const char *str) { "Disable core dumping. By default, disable_core=1 on 64-bit to avoid " "dumping a 16T+ core file. Ignored on OSes that don't dump core by" "default and for sanitizers that don't reserve lots of virtual memory."); + ParseFlag(str, &f->symbolize_inline_frames, "symbolize_inline_frames", + "Print inlined frames in stacktraces. Defaults to true."); + ParseFlag(str, &f->stack_trace_format, "stack_trace_format", + "Format string used to render stack frames. " + "See sanitizer_stacktrace_printer.h for the format description. " + "Use DEFAULT to get default format."); // Do a sanity check for certain flags. if (f->malloc_context_size < 1) diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.h b/libsanitizer/sanitizer_common/sanitizer_flags.h index a906c9e4535..b7a50131811 100644 --- a/libsanitizer/sanitizer_common/sanitizer_flags.h +++ b/libsanitizer/sanitizer_common/sanitizer_flags.h @@ -30,6 +30,7 @@ struct CommonFlags { const char *external_symbolizer_path; bool allow_addr2line; const char *strip_path_prefix; + bool fast_unwind_on_check; bool fast_unwind_on_fatal; bool fast_unwind_on_malloc; bool handle_ioctl; @@ -58,6 +59,8 @@ struct CommonFlags { const char *suppressions; bool print_suppressions; bool disable_coredump; + bool symbolize_inline_frames; + const char *stack_trace_format; }; inline CommonFlags *common_flags() { diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cc b/libsanitizer/sanitizer_common/sanitizer_mac.cc index 2c2a1d74be7..17b931cb535 100644 --- a/libsanitizer/sanitizer_common/sanitizer_mac.cc +++ b/libsanitizer/sanitizer_common/sanitizer_mac.cc @@ -158,7 +158,7 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, // pthread_get_stacksize_np() returns an incorrect stack size for the main // thread on Mavericks. See // https://code.google.com/p/address-sanitizer/issues/detail?id=261 - if ((GetMacosVersion() == MACOS_VERSION_MAVERICKS) && at_initialization && + if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization && stacksize == (1 << 19)) { struct rlimit rl; CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0); @@ -295,6 +295,7 @@ MacosVersion GetMacosVersionInternal() { case '1': return MACOS_VERSION_LION; case '2': return MACOS_VERSION_MOUNTAIN_LION; case '3': return MACOS_VERSION_MAVERICKS; + case '4': return MACOS_VERSION_YOSEMITE; default: return MACOS_VERSION_UNKNOWN; } } diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.h b/libsanitizer/sanitizer_common/sanitizer_mac.h index 63055297fef..47739f71c3c 100644 --- a/libsanitizer/sanitizer_common/sanitizer_mac.h +++ b/libsanitizer/sanitizer_common/sanitizer_mac.h @@ -23,7 +23,8 @@ enum MacosVersion { MACOS_VERSION_SNOW_LEOPARD, MACOS_VERSION_LION, MACOS_VERSION_MOUNTAIN_LION, - MACOS_VERSION_MAVERICKS + MACOS_VERSION_MAVERICKS, + MACOS_VERSION_YOSEMITE, }; MacosVersion GetMacosVersion(); diff --git a/libsanitizer/sanitizer_common/sanitizer_platform.h b/libsanitizer/sanitizer_common/sanitizer_platform.h index 14594d5ce55..7064b7166b0 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform.h @@ -47,7 +47,7 @@ # define SANITIZER_WINDOWS 0 #endif -#if defined(__ANDROID__) || defined(ANDROID) +#if defined(__ANDROID__) # define SANITIZER_ANDROID 1 #else # define SANITIZER_ANDROID 0 @@ -79,7 +79,7 @@ // For such platforms build this code with -DSANITIZER_CAN_USE_ALLOCATOR64=0 or // change the definition of SANITIZER_CAN_USE_ALLOCATOR64 here. #ifndef SANITIZER_CAN_USE_ALLOCATOR64 -# if defined(__aarch64__) +# if defined(__aarch64__) || defined(__mips64) # define SANITIZER_CAN_USE_ALLOCATOR64 0 # else # define SANITIZER_CAN_USE_ALLOCATOR64 (SANITIZER_WORDSIZE == 64) @@ -107,4 +107,10 @@ # endif #endif +#ifdef __mips__ +# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 10) +#else +# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 12) +#endif + #endif // SANITIZER_PLATFORM_H diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h index 81a09927d79..fc2d7ba990c 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h @@ -204,7 +204,8 @@ #define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD #define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \ + SI_FREEBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_TLS_GET_ADDR SI_LINUX_NOT_ANDROID @@ -226,7 +227,8 @@ #define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_FFLUSH SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_FCLOSE SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE SI_LINUX_NOT_ANDROID || SI_MAC +#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE \ + SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_MAC #define SANITIZER_INTERCEPT_GETPASS SI_LINUX_NOT_ANDROID || SI_MAC #define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc index a1f04325033..8779d8adf72 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc @@ -36,7 +36,6 @@ #define uid_t __kernel_uid_t #define gid_t __kernel_gid_t #define off_t __kernel_off_t -#define time_t __kernel_time_t // This header seems to contain the definitions of _kernel_ stat* structs. #include <asm/stat.h> #undef ino_t @@ -61,7 +60,7 @@ namespace __sanitizer { } // namespace __sanitizer #if !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__aarch64__)\ - && !defined(__mips__) && !defined(__sparc__) + && !defined(__mips__) COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat)); #endif diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc index f5678dceccc..13d908e9f8c 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc @@ -13,7 +13,19 @@ #include "sanitizer_platform.h" #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC - +// Tests in this file assume that off_t-dependent data structures match the +// libc ABI. For example, struct dirent here is what readdir() function (as +// exported from libc) returns, and not the user-facing "dirent", which +// depends on _FILE_OFFSET_BITS setting. +// To get this "true" dirent definition, we undefine _FILE_OFFSET_BITS below. +#ifdef _FILE_OFFSET_BITS +#undef _FILE_OFFSET_BITS +#endif +#if SANITIZER_FREEBSD +#define _WANT_RTENTRY +#include <sys/param.h> +#include <sys/socketvar.h> +#endif #include <arpa/inet.h> #include <dirent.h> #include <errno.h> @@ -551,7 +563,9 @@ namespace __sanitizer { unsigned IOCTL_PPPIOCSMAXCID = PPPIOCSMAXCID; unsigned IOCTL_PPPIOCSMRU = PPPIOCSMRU; unsigned IOCTL_PPPIOCSXASYNCMAP = PPPIOCSXASYNCMAP; + unsigned IOCTL_SIOCADDRT = SIOCADDRT; unsigned IOCTL_SIOCDARP = SIOCDARP; + unsigned IOCTL_SIOCDELRT = SIOCDELRT; unsigned IOCTL_SIOCDRARP = SIOCDRARP; unsigned IOCTL_SIOCGARP = SIOCGARP; unsigned IOCTL_SIOCGIFENCAP = SIOCGIFENCAP; @@ -637,8 +651,6 @@ namespace __sanitizer { #if SANITIZER_LINUX || SANITIZER_FREEBSD unsigned IOCTL_MTIOCGET = MTIOCGET; unsigned IOCTL_MTIOCTOP = MTIOCTOP; - unsigned IOCTL_SIOCADDRT = SIOCADDRT; - unsigned IOCTL_SIOCDELRT = SIOCDELRT; unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h index 284be11cb5f..139fe0a1821 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h @@ -72,14 +72,6 @@ namespace __sanitizer { const unsigned struct_kernel_stat_sz = 144; #endif const unsigned struct_kernel_stat64_sz = 104; -#elif defined(__sparc__) && defined(__arch64__) - const unsigned struct___old_kernel_stat_sz = 0; - const unsigned struct_kernel_stat_sz = 104; - const unsigned struct_kernel_stat64_sz = 144; -#elif defined(__sparc__) && !defined(__arch64__) - const unsigned struct___old_kernel_stat_sz = 0; - const unsigned struct_kernel_stat_sz = 64; - const unsigned struct_kernel_stat64_sz = 104; #endif struct __sanitizer_perf_event_attr { unsigned type; @@ -102,7 +94,7 @@ namespace __sanitizer { #if defined(__powerpc64__) const unsigned struct___old_kernel_stat_sz = 0; -#elif !defined(__sparc__) +#else const unsigned struct___old_kernel_stat_sz = 32; #endif @@ -181,18 +173,6 @@ namespace __sanitizer { unsigned short __pad1; unsigned long __unused1; unsigned long __unused2; -#elif defined(__sparc__) -# if defined(__arch64__) - unsigned mode; - unsigned short __pad1; -# else - unsigned short __pad1; - unsigned short mode; - unsigned short __pad2; -# endif - unsigned short __seq; - unsigned long long __unused1; - unsigned long long __unused2; #else unsigned short mode; unsigned short __pad1; @@ -210,26 +190,6 @@ namespace __sanitizer { struct __sanitizer_shmid_ds { __sanitizer_ipc_perm shm_perm; - #if defined(__sparc__) - # if !defined(__arch64__) - u32 __pad1; - # endif - long shm_atime; - # if !defined(__arch64__) - u32 __pad2; - # endif - long shm_dtime; - # if !defined(__arch64__) - u32 __pad3; - # endif - long shm_ctime; - uptr shm_segsz; - int shm_cpid; - int shm_lpid; - unsigned long shm_nattch; - unsigned long __glibc_reserved1; - unsigned long __glibc_reserved2; - #else #ifndef __powerpc__ uptr shm_segsz; #elif !defined(__powerpc64__) @@ -267,7 +227,6 @@ namespace __sanitizer { uptr __unused4; uptr __unused5; #endif -#endif }; #elif SANITIZER_FREEBSD struct __sanitizer_ipc_perm { @@ -511,7 +470,7 @@ namespace __sanitizer { typedef long __sanitizer___kernel_off_t; #endif -#if defined(__powerpc__) || defined(__aarch64__) || defined(__mips__) +#if defined(__powerpc__) || defined(__mips__) typedef unsigned int __sanitizer___kernel_old_uid_t; typedef unsigned int __sanitizer___kernel_old_gid_t; #else @@ -564,13 +523,9 @@ namespace __sanitizer { #else __sanitizer_sigset_t sa_mask; #ifndef __mips__ -#if defined(__sparc__) - unsigned long sa_flags; -#else int sa_flags; #endif #endif -#endif #if SANITIZER_LINUX void (*sa_restorer)(); #endif @@ -790,7 +745,7 @@ struct __sanitizer_obstack { #define IOC_NRBITS 8 #define IOC_TYPEBITS 8 -#if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__) || defined(__sparc__) +#if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__) #define IOC_SIZEBITS 13 #define IOC_DIRBITS 3 #define IOC_NONE 1U @@ -820,17 +775,7 @@ struct __sanitizer_obstack { #define IOC_DIR(nr) (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK) #define IOC_TYPE(nr) (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK) #define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK) - -#if defined(__sparc__) -// In sparc the 14 bits SIZE field overlaps with the -// least significant bit of DIR, so either IOC_READ or -// IOC_WRITE shall be 1 in order to get a non-zero SIZE. -# define IOC_SIZE(nr) \ - ((((((nr) >> 29) & 0x7) & (4U|2U)) == 0)? \ - 0 : (((nr) >> 16) & 0x3fff)) -#else #define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) -#endif extern unsigned struct_arpreq_sz; extern unsigned struct_ifreq_sz; diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cc b/libsanitizer/sanitizer_common/sanitizer_posix.cc index 24e99f9472d..229870e00dc 100644 --- a/libsanitizer/sanitizer_common/sanitizer_posix.cc +++ b/libsanitizer/sanitizer_common/sanitizer_posix.cc @@ -82,9 +82,12 @@ uptr GetMaxVirtualAddress() { // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL. // Note that with 'ulimit -s unlimited' the stack is moved away from the top // of the address space, so simply checking the stack address is not enough. - return (1ULL << 44) - 1; // 0x00000fffffffffffUL + // This should (does) work for both PowerPC64 Endian modes. + return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1; # elif defined(__aarch64__) return (1ULL << 39) - 1; +# elif defined(__mips64) + return (1ULL << 40) - 1; # else return (1ULL << 47) - 1; // 0x00007fffffffffffUL; # endif diff --git a/libsanitizer/sanitizer_common/sanitizer_printf.cc b/libsanitizer/sanitizer_common/sanitizer_printf.cc index fc0c357ba86..599f2c5d7c6 100644 --- a/libsanitizer/sanitizer_common/sanitizer_printf.cc +++ b/libsanitizer/sanitizer_common/sanitizer_printf.cc @@ -111,7 +111,7 @@ static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) { int result = 0; result += AppendString(buff, buff_end, -1, "0x"); result += AppendUnsigned(buff, buff_end, ptr_value, 16, - (SANITIZER_WORDSIZE == 64) ? 12 : 8, true); + SANITIZER_POINTER_FORMAT_LENGTH, true); return result; } diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cc b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cc index e1915cb808f..a3c9c0677e2 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cc +++ b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cc @@ -16,31 +16,6 @@ namespace __sanitizer { -struct StackDepotDesc { - const uptr *stack; - uptr size; - u32 hash() const { - // murmur2 - const u32 m = 0x5bd1e995; - const u32 seed = 0x9747b28c; - const u32 r = 24; - u32 h = seed ^ (size * sizeof(uptr)); - for (uptr i = 0; i < size; i++) { - u32 k = stack[i]; - k *= m; - k ^= k >> r; - k *= m; - h *= m; - h ^= k; - } - h ^= h >> 13; - h *= m; - h ^= h >> 15; - return h; - } - bool is_valid() { return size > 0 && stack; } -}; - struct StackDepotNode { StackDepotNode *link; u32 id; @@ -56,28 +31,49 @@ struct StackDepotNode { static const u32 kUseCountMask = (1 << kUseCountBits) - 1; static const u32 kHashMask = ~kUseCountMask; - typedef StackDepotDesc args_type; + typedef StackTrace args_type; bool eq(u32 hash, const args_type &args) const { u32 hash_bits = atomic_load(&hash_and_use_count, memory_order_relaxed) & kHashMask; if ((hash & kHashMask) != hash_bits || args.size != size) return false; uptr i = 0; for (; i < size; i++) { - if (stack[i] != args.stack[i]) return false; + if (stack[i] != args.trace[i]) return false; } return true; } static uptr storage_size(const args_type &args) { return sizeof(StackDepotNode) + (args.size - 1) * sizeof(uptr); } + static u32 hash(const args_type &args) { + // murmur2 + const u32 m = 0x5bd1e995; + const u32 seed = 0x9747b28c; + const u32 r = 24; + u32 h = seed ^ (args.size * sizeof(uptr)); + for (uptr i = 0; i < args.size; i++) { + u32 k = args.trace[i]; + k *= m; + k ^= k >> r; + k *= m; + h *= m; + h ^= k; + } + h ^= h >> 13; + h *= m; + h ^= h >> 15; + return h; + } + static bool is_valid(const args_type &args) { + return args.size > 0 && args.trace; + } void store(const args_type &args, u32 hash) { atomic_store(&hash_and_use_count, hash & kHashMask, memory_order_relaxed); size = args.size; - internal_memcpy(stack, args.stack, size * sizeof(uptr)); + internal_memcpy(stack, args.trace, size * sizeof(uptr)); } args_type load() const { - args_type ret = {&stack[0], size}; - return ret; + return args_type(&stack[0], size); } StackDepotHandle get_handle() { return StackDepotHandle(this); } @@ -97,8 +93,6 @@ void StackDepotHandle::inc_use_count_unsafe() { StackDepotNode::kUseCountMask; CHECK_LT(prev + 1, StackDepotNode::kMaxUseCount); } -uptr StackDepotHandle::size() { return node_->size; } -uptr *StackDepotHandle::stack() { return &node_->stack[0]; } // FIXME(dvyukov): this single reserved bit is used in TSan. typedef StackDepotBase<StackDepotNode, 1, StackDepotNode::kTabSizeLog> @@ -109,21 +103,17 @@ StackDepotStats *StackDepotGetStats() { return theDepot.GetStats(); } -u32 StackDepotPut(const uptr *stack, uptr size) { - StackDepotDesc desc = {stack, size}; - StackDepotHandle h = theDepot.Put(desc); +u32 StackDepotPut(StackTrace stack) { + StackDepotHandle h = theDepot.Put(stack); return h.valid() ? h.id() : 0; } -StackDepotHandle StackDepotPut_WithHandle(const uptr *stack, uptr size) { - StackDepotDesc desc = {stack, size}; - return theDepot.Put(desc); +StackDepotHandle StackDepotPut_WithHandle(StackTrace stack) { + return theDepot.Put(stack); } -const uptr *StackDepotGet(u32 id, uptr *size) { - StackDepotDesc desc = theDepot.Get(id); - *size = desc.size; - return desc.stack; +StackTrace StackDepotGet(u32 id) { + return theDepot.Get(id); } void StackDepotLockAll() { @@ -154,18 +144,15 @@ StackDepotReverseMap::StackDepotReverseMap() InternalSort(&map_, map_.size(), IdDescPair::IdComparator); } -const uptr *StackDepotReverseMap::Get(u32 id, uptr *size) { - if (!map_.size()) return 0; +StackTrace StackDepotReverseMap::Get(u32 id) { + if (!map_.size()) + return StackTrace(); IdDescPair pair = {id, 0}; uptr idx = InternalBinarySearch(map_, 0, map_.size(), pair, IdDescPair::IdComparator); - if (idx > map_.size()) { - *size = 0; - return 0; - } - StackDepotNode *desc = map_[idx].desc; - *size = desc->size; - return desc->stack; + if (idx > map_.size()) + return StackTrace(); + return map_[idx].desc->load(); } } // namespace __sanitizer diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepot.h b/libsanitizer/sanitizer_common/sanitizer_stackdepot.h index 2b1da4ee14f..aad9bfb8d35 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stackdepot.h +++ b/libsanitizer/sanitizer_common/sanitizer_stackdepot.h @@ -13,6 +13,7 @@ #include "sanitizer_common.h" #include "sanitizer_internal_defs.h" +#include "sanitizer_stacktrace.h" namespace __sanitizer { @@ -26,17 +27,15 @@ struct StackDepotHandle { u32 id(); int use_count(); void inc_use_count_unsafe(); - uptr size(); - uptr *stack(); }; const int kStackDepotMaxUseCount = 1U << 20; StackDepotStats *StackDepotGetStats(); -u32 StackDepotPut(const uptr *stack, uptr size); -StackDepotHandle StackDepotPut_WithHandle(const uptr *stack, uptr size); +u32 StackDepotPut(StackTrace stack); +StackDepotHandle StackDepotPut_WithHandle(StackTrace stack); // Retrieves a stored stack trace by the id. -const uptr *StackDepotGet(u32 id, uptr *size); +StackTrace StackDepotGet(u32 id); void StackDepotLockAll(); void StackDepotUnlockAll(); @@ -48,7 +47,7 @@ void StackDepotUnlockAll(); class StackDepotReverseMap { public: StackDepotReverseMap(); - const uptr *Get(u32 id, uptr *size); + StackTrace Get(u32 id); private: struct IdDescPair { diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepotbase.h b/libsanitizer/sanitizer_common/sanitizer_stackdepotbase.h index b9dedec2621..05b63092b80 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stackdepotbase.h +++ b/libsanitizer/sanitizer_common/sanitizer_stackdepotbase.h @@ -95,8 +95,8 @@ typename StackDepotBase<Node, kReservedBits, kTabSizeLog>::handle_type StackDepotBase<Node, kReservedBits, kTabSizeLog>::Put(args_type args, bool *inserted) { if (inserted) *inserted = false; - if (!args.is_valid()) return handle_type(); - uptr h = args.hash(); + if (!Node::is_valid(args)) return handle_type(); + uptr h = Node::hash(args); atomic_uintptr_t *p = &tab[h % kTabSize]; uptr v = atomic_load(p, memory_order_consume); Node *s = (Node *)(v & ~1); diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc index 0ce5ae475f6..9b99b5bb201 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc @@ -23,7 +23,7 @@ uptr StackTrace::GetPreviousInstructionPc(uptr pc) { #if defined(__powerpc__) || defined(__powerpc64__) // PCs are always 4 byte aligned. return pc - 4; -#elif defined(__sparc__) +#elif defined(__sparc__) || defined(__mips__) return pc - 8; #else return pc - 1; @@ -34,6 +34,15 @@ uptr StackTrace::GetCurrentPc() { return GET_CALLER_PC(); } +void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) { + size = cnt + !!extra_top_pc; + CHECK_LE(size, kStackTraceMax); + internal_memcpy(trace_buffer, pcs, cnt * sizeof(trace_buffer[0])); + if (extra_top_pc) + trace_buffer[cnt] = extra_top_pc; + top_frame_bp = 0; +} + // Check if given pointer points into allocated stack area. static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) { return frame > stack_bottom && frame < stack_top - 2 * sizeof (uhwptr); @@ -49,32 +58,40 @@ static inline uhwptr *GetCanonicFrame(uptr bp, if (!IsValidFrame(bp, stack_top, stack_bottom)) return 0; uhwptr *bp_prev = (uhwptr *)bp; if (IsValidFrame((uptr)bp_prev[0], stack_top, stack_bottom)) return bp_prev; - return bp_prev - 1; + // The next frame pointer does not look right. This could be a GCC frame, step + // back by 1 word and try again. + if (IsValidFrame((uptr)bp_prev[-1], stack_top, stack_bottom)) + return bp_prev - 1; + // Nope, this does not look right either. This means the frame after next does + // not have a valid frame pointer, but we can still extract the caller PC. + // Unfortunately, there is no way to decide between GCC and LLVM frame + // layouts. Assume LLVM. + return bp_prev; #else return (uhwptr*)bp; #endif } -void StackTrace::FastUnwindStack(uptr pc, uptr bp, - uptr stack_top, uptr stack_bottom, - uptr max_depth) { +void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top, + uptr stack_bottom, uptr max_depth) { CHECK_GE(max_depth, 2); - trace[0] = pc; + trace_buffer[0] = pc; size = 1; if (stack_top < 4096) return; // Sanity check for stack top. uhwptr *frame = GetCanonicFrame(bp, stack_top, stack_bottom); - uhwptr *prev_frame = 0; + // Lowest possible address that makes sense as the next frame pointer. + // Goes up as we walk the stack. + uptr bottom = stack_bottom; // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. - while (frame > prev_frame && - IsValidFrame((uptr)frame, stack_top, stack_bottom) && + while (IsValidFrame((uptr)frame, stack_top, bottom) && IsAligned((uptr)frame, sizeof(*frame)) && size < max_depth) { uhwptr pc1 = frame[1]; if (pc1 != pc) { - trace[size++] = (uptr) pc1; + trace_buffer[size++] = (uptr) pc1; } - prev_frame = frame; - frame = GetCanonicFrame((uptr)frame[0], stack_top, stack_bottom); + bottom = (uptr)frame; + frame = GetCanonicFrame((uptr)frame[0], stack_top, bottom); } } @@ -82,15 +99,15 @@ static bool MatchPc(uptr cur_pc, uptr trace_pc, uptr threshold) { return cur_pc - trace_pc <= threshold || trace_pc - cur_pc <= threshold; } -void StackTrace::PopStackFrames(uptr count) { +void BufferedStackTrace::PopStackFrames(uptr count) { CHECK_LT(count, size); size -= count; for (uptr i = 0; i < size; ++i) { - trace[i] = trace[i + count]; + trace_buffer[i] = trace_buffer[i + count]; } } -uptr StackTrace::LocatePcInTrace(uptr pc) { +uptr BufferedStackTrace::LocatePcInTrace(uptr pc) { // Use threshold to find PC in stack trace, as PC we want to unwind from may // slightly differ from return address in the actual unwinded stack trace. const int kPcThreshold = 288; diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h index 0e0f1702228..31495cfc568 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h @@ -27,44 +27,49 @@ static const uptr kStackTraceMax = 256; # define SANITIZER_CAN_FAST_UNWIND 1 #endif +// Fast unwind is the only option on Mac for now; we will need to +// revisit this macro when slow unwind works on Mac, see +// https://code.google.com/p/address-sanitizer/issues/detail?id=137 +#if SANITIZER_MAC +# define SANITIZER_CAN_SLOW_UNWIND 0 +#else +# define SANITIZER_CAN_SLOW_UNWIND 1 +#endif + struct StackTrace { - typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer, - int out_size); - uptr top_frame_bp; + const uptr *trace; uptr size; - uptr trace[kStackTraceMax]; - // Prints a symbolized stacktrace, followed by an empty line. - static void PrintStack(const uptr *addr, uptr size); - void Print() const { - PrintStack(trace, size); - } + StackTrace() : trace(nullptr), size(0) {} + StackTrace(const uptr *trace, uptr size) : trace(trace), size(size) {} - void CopyFrom(const uptr *src, uptr src_size) { - top_frame_bp = 0; - size = src_size; - if (size > kStackTraceMax) size = kStackTraceMax; - for (uptr i = 0; i < size; i++) - trace[i] = src[i]; - } + // Prints a symbolized stacktrace, followed by an empty line. + void Print() const; static bool WillUseFastUnwind(bool request_fast_unwind) { - // Check if fast unwind is available. Fast unwind is the only option on Mac. - // It is also the only option on FreeBSD as the slow unwinding that - // leverages _Unwind_Backtrace() yields the call stack of the signal's - // handler and not of the code that raised the signal (as it does on Linux). if (!SANITIZER_CAN_FAST_UNWIND) return false; - else if (SANITIZER_MAC != 0 || SANITIZER_FREEBSD != 0) + else if (!SANITIZER_CAN_SLOW_UNWIND) return true; return request_fast_unwind; } - void Unwind(uptr max_depth, uptr pc, uptr bp, void *context, uptr stack_top, - uptr stack_bottom, bool request_fast_unwind); - static uptr GetCurrentPc(); static uptr GetPreviousInstructionPc(uptr pc); + typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer, + int out_size); +}; + +// StackTrace that owns the buffer used to store the addresses. +struct BufferedStackTrace : public StackTrace { + uptr trace_buffer[kStackTraceMax]; + uptr top_frame_bp; // Optional bp of a top frame. + + BufferedStackTrace() : StackTrace(trace_buffer, 0), top_frame_bp(0) {} + + void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0); + void Unwind(uptr max_depth, uptr pc, uptr bp, void *context, uptr stack_top, + uptr stack_bottom, bool request_fast_unwind); private: void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom, @@ -74,6 +79,9 @@ struct StackTrace { uptr max_depth); void PopStackFrames(uptr count); uptr LocatePcInTrace(uptr pc); + + BufferedStackTrace(const BufferedStackTrace &); + void operator=(const BufferedStackTrace &); }; } // namespace __sanitizer diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc index 5dcc0e9ed15..2d55b73f03a 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc @@ -10,58 +10,40 @@ //===----------------------------------------------------------------------===// #include "sanitizer_common.h" +#include "sanitizer_placement_new.h" #include "sanitizer_stacktrace.h" +#include "sanitizer_stacktrace_printer.h" #include "sanitizer_symbolizer.h" namespace __sanitizer { -static void PrintStackFramePrefix(InternalScopedString *buffer, uptr frame_num, - uptr pc) { - buffer->append(" #%zu 0x%zx", frame_num, pc); -} - -void StackTrace::PrintStack(const uptr *addr, uptr size) { - if (addr == 0 || size == 0) { +void StackTrace::Print() const { + if (trace == nullptr || size == 0) { Printf(" <empty stack>\n\n"); return; } - InternalScopedBuffer<char> buff(GetPageSizeCached() * 2); - InternalScopedBuffer<AddressInfo> addr_frames(64); + const int kMaxAddrFrames = 64; + InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames); + for (uptr i = 0; i < kMaxAddrFrames; i++) + new(&addr_frames[i]) AddressInfo(); InternalScopedString frame_desc(GetPageSizeCached() * 2); uptr frame_num = 0; - for (uptr i = 0; i < size && addr[i]; i++) { + for (uptr i = 0; i < size && trace[i]; i++) { // PCs in stack traces are actually the return addresses, that is, // addresses of the next instructions after the call. - uptr pc = GetPreviousInstructionPc(addr[i]); + uptr pc = GetPreviousInstructionPc(trace[i]); uptr addr_frames_num = Symbolizer::GetOrInit()->SymbolizePC( - pc, addr_frames.data(), addr_frames.size()); + pc, addr_frames.data(), kMaxAddrFrames); if (addr_frames_num == 0) { - frame_desc.clear(); - PrintStackFramePrefix(&frame_desc, frame_num, pc); - frame_desc.append(" (<unknown module>)"); - Printf("%s\n", frame_desc.data()); - frame_num++; - continue; + addr_frames[0].address = pc; + addr_frames_num = 1; } for (uptr j = 0; j < addr_frames_num; j++) { AddressInfo &info = addr_frames[j]; frame_desc.clear(); - PrintStackFramePrefix(&frame_desc, frame_num, pc); - if (info.function) { - frame_desc.append(" in %s", info.function); - // Print offset in function if we don't know the source file. - if (!info.file && info.function_offset != AddressInfo::kUnknown) - frame_desc.append("+0x%zx", info.function_offset); - } - if (info.file) { - frame_desc.append(" "); - PrintSourceLocation(&frame_desc, info.file, info.line, info.column); - } else if (info.module) { - frame_desc.append(" "); - PrintModuleAndOffset(&frame_desc, info.module, info.module_offset); - } + RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++, + info, common_flags()->strip_path_prefix); Printf("%s\n", frame_desc.data()); - frame_num++; info.Clear(); } } @@ -69,9 +51,9 @@ void StackTrace::PrintStack(const uptr *addr, uptr size) { Printf("\n"); } -void StackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, void *context, - uptr stack_top, uptr stack_bottom, - bool request_fast_unwind) { +void BufferedStackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, void *context, + uptr stack_top, uptr stack_bottom, + bool request_fast_unwind) { top_frame_bp = (max_depth > 0) ? bp : 0; // Avoid doing any work for small max_depth. if (max_depth == 0) { @@ -80,7 +62,7 @@ void StackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, void *context, } if (max_depth == 1) { size = 1; - trace[0] = pc; + trace_buffer[0] = pc; return; } if (!WillUseFastUnwind(request_fast_unwind)) { diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cc b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cc new file mode 100644 index 00000000000..300b4904c54 --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cc @@ -0,0 +1,130 @@ +//===-- sanitizer_common.cc -----------------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizers' run-time libraries. +// +//===----------------------------------------------------------------------===// +#include "sanitizer_stacktrace_printer.h" + +namespace __sanitizer { + +static const char *StripFunctionName(const char *function, const char *prefix) { + if (function == 0) return 0; + if (prefix == 0) return function; + uptr prefix_len = internal_strlen(prefix); + if (0 == internal_strncmp(function, prefix, prefix_len)) + return function + prefix_len; + return function; +} + +static const char kDefaultFormat[] = " #%n %p %F %L"; + +void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, + const AddressInfo &info, const char *strip_path_prefix, + const char *strip_func_prefix) { + if (0 == internal_strcmp(format, "DEFAULT")) + format = kDefaultFormat; + for (const char *p = format; *p != '\0'; p++) { + if (*p != '%') { + buffer->append("%c", *p); + continue; + } + p++; + switch (*p) { + case '%': + buffer->append("%%"); + break; + // Frame number and all fields of AddressInfo structure. + case 'n': + buffer->append("%zu", frame_no); + break; + case 'p': + buffer->append("0x%zx", info.address); + break; + case 'm': + buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix)); + break; + case 'o': + buffer->append("0x%zx", info.module_offset); + break; + case 'f': + buffer->append("%s", StripFunctionName(info.function, strip_func_prefix)); + break; + case 'q': + buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown + ? info.function_offset + : 0x0); + break; + case 's': + buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix)); + break; + case 'l': + buffer->append("%d", info.line); + break; + case 'c': + buffer->append("%d", info.column); + break; + // Smarter special cases. + case 'F': + // Function name and offset, if file is unknown. + if (info.function) { + buffer->append("in %s", + StripFunctionName(info.function, strip_func_prefix)); + if (!info.file && info.function_offset != AddressInfo::kUnknown) + buffer->append("+0x%zx", info.function_offset); + } + break; + case 'S': + // File/line information. + RenderSourceLocation(buffer, info.file, info.line, info.column, + strip_path_prefix); + break; + case 'L': + // Source location, or module location. + if (info.file) { + RenderSourceLocation(buffer, info.file, info.line, info.column, + strip_path_prefix); + } else if (info.module) { + RenderModuleLocation(buffer, info.module, info.module_offset, + strip_path_prefix); + } else { + buffer->append("(<unknown module>)"); + } + break; + case 'M': + // Module basename and offset, or PC. + if (info.module) + buffer->append("(%s+%p)", StripModuleName(info.module), + (void *)info.module_offset); + else + buffer->append("(%p)", (void *)info.address); + break; + default: + Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", + *p, *p); + Die(); + } + } +} + +void RenderSourceLocation(InternalScopedString *buffer, const char *file, + int line, int column, const char *strip_path_prefix) { + buffer->append("%s", StripPathPrefix(file, strip_path_prefix)); + if (line > 0) { + buffer->append(":%d", line); + if (column > 0) + buffer->append(":%d", column); + } +} + +void RenderModuleLocation(InternalScopedString *buffer, const char *module, + uptr offset, const char *strip_path_prefix) { + buffer->append("(%s+0x%zx)", StripPathPrefix(module, strip_path_prefix), + offset); +} + +} // namespace __sanitizer diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h new file mode 100644 index 00000000000..54e2fb024df --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h @@ -0,0 +1,60 @@ +//===-- sanitizer_stacktrace_printer.h --------------------------*- C++ -*-===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizers' run-time libraries. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_STACKTRACE_PRINTER_H +#define SANITIZER_STACKTRACE_PRINTER_H + +#include "sanitizer_common.h" +#include "sanitizer_symbolizer.h" + +namespace __sanitizer { + +// Render the contents of "info" structure, which represents the contents of +// stack frame "frame_no" and appends it to the "buffer". "format" is a +// string with placeholders, which is copied to the output with +// placeholders substituted with the contents of "info". For example, +// format string +// " frame %n: function %F at %S" +// will be turned into +// " frame 10: function foo::bar() at my/file.cc:10" +// You may additionally pass "strip_path_prefix" to strip prefixes of paths to +// source files and modules, and "strip_func_prefix" to strip prefixes of +// function names. +// Here's the full list of available placeholders: +// %% - represents a '%' character; +// %n - frame number (copy of frame_no); +// %p - PC in hex format; +// %m - path to module (binary or shared object); +// %o - offset in the module in hex format; +// %f - function name; +// %q - offset in the function in hex format (*if available*); +// %s - path to source file; +// %l - line in the source file; +// %c - column in the source file; +// %F - if function is known to be <foo>, prints "in <foo>", possibly +// followed by the offset in this function, but only if source file +// is unknown; +// %S - prints file/line/column information; +// %L - prints location information: file/line/column, if it is known, or +// module+offset if it is known, or (<unknown module>) string. +// %M - prints module basename and offset, if it is known, or PC. +void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, + const AddressInfo &info, const char *strip_path_prefix = "", + const char *strip_func_prefix = ""); + +void RenderSourceLocation(InternalScopedString *buffer, const char *file, + int line, int column, const char *strip_path_prefix); + +void RenderModuleLocation(InternalScopedString *buffer, const char *module, + uptr offset, const char *strip_path_prefix); + +} // namespace __sanitizer + +#endif // SANITIZER_STACKTRACE_PRINTER_H diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h index 73a68b2ee11..2ff99372da9 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h @@ -59,13 +59,23 @@ struct AddressInfo { } }; +// For now, DataInfo is used to describe global variable. struct DataInfo { - uptr address; char *module; uptr module_offset; char *name; uptr start; uptr size; + + DataInfo() { + internal_memset(this, 0, sizeof(DataInfo)); + } + + void Clear() { + InternalFree(module); + InternalFree(name); + internal_memset(this, 0, sizeof(DataInfo)); + } }; class Symbolizer { diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc index 86d32e529ec..905079475b8 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc @@ -166,7 +166,7 @@ uptr LibbacktraceSymbolizer::SymbolizeCode(uptr addr, AddressInfo *frames, } bool LibbacktraceSymbolizer::SymbolizeData(DataInfo *info) { - backtrace_syminfo((backtrace_state *)state_, info->address, + backtrace_syminfo((backtrace_state *)state_, info->start, SymbolizeDataCallback, ErrorCallback, info); return true; } diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc index 4f30225a4c8..ccd2d70f0f0 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -339,12 +339,19 @@ class LLVMSymbolizerProcess : public SymbolizerProcess { const char* const kSymbolizerArch = "--default-arch=x86_64"; #elif defined(__i386__) const char* const kSymbolizerArch = "--default-arch=i386"; -#elif defined(__powerpc64__) +#elif defined(__powerpc64__) && defined(__BIG_ENDIAN__) const char* const kSymbolizerArch = "--default-arch=powerpc64"; +#elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__) + const char* const kSymbolizerArch = "--default-arch=powerpc64le"; #else const char* const kSymbolizerArch = "--default-arch=unknown"; #endif - execl(path_to_binary, path_to_binary, kSymbolizerArch, (char *)0); + + const char *const inline_flag = common_flags()->symbolize_inline_frames + ? "--inlining=true" + : "--inlining=false"; + execl(path_to_binary, path_to_binary, inline_flag, kSymbolizerArch, + (char *)0); } }; @@ -580,8 +587,7 @@ class POSIXSymbolizer : public Symbolizer { 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->Clear(); info->module = internal_strdup(module_name); info->module_offset = module_offset; // First, try to use libbacktrace symbolizer (if it's available). diff --git a/libsanitizer/sanitizer_common/sanitizer_unwind_posix_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_unwind_posix_libcdep.cc index c49113e1d0b..b2ca931e9d9 100644 --- a/libsanitizer/sanitizer_common/sanitizer_unwind_posix_libcdep.cc +++ b/libsanitizer/sanitizer_common/sanitizer_unwind_posix_libcdep.cc @@ -93,7 +93,7 @@ uptr Unwind_GetIP(struct _Unwind_Context *ctx) { } struct UnwindTraceArg { - StackTrace *stack; + BufferedStackTrace *stack; uptr max_depth; }; @@ -101,27 +101,27 @@ _Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { UnwindTraceArg *arg = (UnwindTraceArg*)param; CHECK_LT(arg->stack->size, arg->max_depth); uptr pc = Unwind_GetIP(ctx); - arg->stack->trace[arg->stack->size++] = pc; + arg->stack->trace_buffer[arg->stack->size++] = pc; if (arg->stack->size == arg->max_depth) return UNWIND_STOP; return UNWIND_CONTINUE; } -void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) { +void BufferedStackTrace::SlowUnwindStack(uptr pc, uptr max_depth) { CHECK_GE(max_depth, 2); size = 0; UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; _Unwind_Backtrace(Unwind_Trace, &arg); // We need to pop a few frames so that pc is on top. uptr to_pop = LocatePcInTrace(pc); - // trace[0] belongs to the current function so we always pop it. - if (to_pop == 0) + // trace_buffer[0] belongs to the current function so we always pop it. + if (to_pop == 0 && size > 1) to_pop = 1; PopStackFrames(to_pop); - trace[0] = pc; + trace_buffer[0] = pc; } -void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context, - uptr max_depth) { +void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, + uptr max_depth) { CHECK_GE(max_depth, 2); if (!unwind_backtrace_signal_arch) { SlowUnwindStack(pc, max_depth); @@ -143,7 +143,7 @@ void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context, // +2 compensate for libcorkscrew unwinder returning addresses of call // instructions instead of raw return addresses. for (sptr i = 0; i < res; ++i) - trace[size++] = frames[i].absolute_pc + 2; + trace_buffer[size++] = frames[i].absolute_pc + 2; } } // namespace __sanitizer diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cc b/libsanitizer/sanitizer_common/sanitizer_win.cc index 9f24510dbd0..fbccef19cb1 100644 --- a/libsanitizer/sanitizer_common/sanitizer_win.cc +++ b/libsanitizer/sanitizer_common/sanitizer_win.cc @@ -442,7 +442,7 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, } #if !SANITIZER_GO -void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) { +void BufferedStackTrace::SlowUnwindStack(uptr pc, uptr max_depth) { CHECK_GE(max_depth, 2); // FIXME: CaptureStackBackTrace might be too slow for us. // FIXME: Compare with StackWalk64. @@ -457,8 +457,8 @@ void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) { PopStackFrames(pc_location); } -void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context, - uptr max_depth) { +void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, + uptr max_depth) { CONTEXT ctx = *(CONTEXT *)context; STACKFRAME64 stack_frame; memset(&stack_frame, 0, sizeof(stack_frame)); @@ -481,7 +481,7 @@ void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context, &stack_frame, &ctx, NULL, &SymFunctionTableAccess64, &SymGetModuleBase64, NULL) && size < Min(max_depth, kStackTraceMax)) { - trace[size++] = (uptr)stack_frame.AddrPC.Offset; + trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset; } } #endif // #if !SANITIZER_GO |