summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKuba Mracek <mracek@apple.com>2017-01-06 20:57:47 +0000
committerKuba Mracek <mracek@apple.com>2017-01-06 20:57:47 +0000
commit47b4cadc8fc1d82b28f648609604c7d7bf12aa0d (patch)
treea8a30372e4f5edc748c0f44babb1bcd87781568d
parent0aad13bae1d86febf022d0c9b0299183e1d00f34 (diff)
[sanitizer] Add a 'print_module_map' flag which prints modules with UUIDs on Darwin
This patch add a new sanitizer flag, print_module_map, which enables printing a module map when the process exits, or after each report (for TSan). The output format is very similar to what Crash Reporter produces on Darwin (e.g. the format of module UUIDs). This enables users to use the existing symbol servers to offline symbolicate and aggregate reports. Differential Revision: https://reviews.llvm.org/D27400 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@291277 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/asan/asan_report.cc2
-rw-r--r--lib/asan/asan_rtl.cc1
-rw-r--r--lib/sanitizer_common/sanitizer_common.cc4
-rw-r--r--lib/sanitizer_common/sanitizer_common.h30
-rw-r--r--lib/sanitizer_common/sanitizer_flags.inc3
-rw-r--r--lib/sanitizer_common/sanitizer_linux.cc2
-rw-r--r--lib/sanitizer_common/sanitizer_mac.cc30
-rw-r--r--lib/sanitizer_common/sanitizer_printf.cc28
-rw-r--r--lib/sanitizer_common/sanitizer_win.cc2
-rw-r--r--lib/tsan/rtl/tsan_report.cc2
-rw-r--r--lib/tsan/rtl/tsan_rtl.cc2
-rw-r--r--test/asan/TestCases/Darwin/uuid.cc28
12 files changed, 123 insertions, 11 deletions
diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc
index 937ba4077..3ad48fa88 100644
--- a/lib/asan/asan_report.cc
+++ b/lib/asan/asan_report.cc
@@ -179,6 +179,8 @@ class ScopedInErrorReport {
if (common_flags()->print_cmdline)
PrintCmdline();
+ if (common_flags()->print_module_map == 2) PrintModuleMap();
+
// Copy the message buffer so that we could start logging without holding a
// lock that gets aquired during printing.
InternalScopedBuffer<char> buffer_copy(kErrorMessageBufferSize);
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index fee7b8a2d..d9d7d7e4f 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -46,6 +46,7 @@ static void AsanDie() {
// Don't die twice - run a busy loop.
while (1) { }
}
+ if (common_flags()->print_module_map >= 1) PrintModuleMap();
if (flags()->sleep_before_dying) {
Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying);
SleepForSeconds(flags()->sleep_before_dying);
diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc
index 89c5c4511..9824a5198 100644
--- a/lib/sanitizer_common/sanitizer_common.cc
+++ b/lib/sanitizer_common/sanitizer_common.cc
@@ -270,6 +270,8 @@ void LoadedModule::set(const char *module_name, uptr base_address,
void LoadedModule::clear() {
InternalFree(full_name_);
+ base_address_ = 0;
+ max_executable_address_ = 0;
full_name_ = nullptr;
arch_ = kModuleArchUnknown;
internal_memset(uuid_, 0, kModuleUUIDSize);
@@ -285,6 +287,8 @@ void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) {
void *mem = InternalAlloc(sizeof(AddressRange));
AddressRange *r = new(mem) AddressRange(beg, end, executable);
ranges_.push_back(r);
+ if (executable && end > max_executable_address_)
+ max_executable_address_ = end;
}
bool LoadedModule::containsAddress(uptr address) const {
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index fee642f3e..fc44ecd5b 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -283,6 +283,7 @@ void UpdateProcessName();
void CacheBinaryName();
void DisableCoreDumperIfNecessary();
void DumpProcessMap();
+void PrintModuleMap();
bool FileExists(const char *filename);
const char *GetEnv(const char *name);
bool SetEnv(const char *name, const char *value);
@@ -665,6 +666,32 @@ enum ModuleArch {
kModuleArchARM64
};
+// When adding a new architecture, don't forget to also update
+// script/asan_symbolize.py and sanitizer_symbolizer_libcdep.cc.
+inline const char *ModuleArchToString(ModuleArch arch) {
+ switch (arch) {
+ case kModuleArchUnknown:
+ return "";
+ case kModuleArchI386:
+ return "i386";
+ case kModuleArchX86_64:
+ return "x86_64";
+ case kModuleArchX86_64H:
+ return "x86_64h";
+ case kModuleArchARMV6:
+ return "armv6";
+ case kModuleArchARMV7:
+ return "armv7";
+ case kModuleArchARMV7S:
+ return "armv7s";
+ case kModuleArchARMV7K:
+ return "armv7k";
+ case kModuleArchARM64:
+ return "arm64";
+ }
+ CHECK(0 && "Invalid module arch");
+}
+
const uptr kModuleUUIDSize = 16;
// Represents a binary loaded into virtual memory (e.g. this can be an
@@ -674,6 +701,7 @@ class LoadedModule {
LoadedModule()
: full_name_(nullptr),
base_address_(0),
+ max_executable_address_(0),
arch_(kModuleArchUnknown),
instrumented_(false) {
internal_memset(uuid_, 0, kModuleUUIDSize);
@@ -688,6 +716,7 @@ class LoadedModule {
const char *full_name() const { return full_name_; }
uptr base_address() const { return base_address_; }
+ uptr max_executable_address() const { return max_executable_address_; }
ModuleArch arch() const { return arch_; }
const u8 *uuid() const { return uuid_; }
bool instrumented() const { return instrumented_; }
@@ -707,6 +736,7 @@ class LoadedModule {
private:
char *full_name_; // Owned.
uptr base_address_;
+ uptr max_executable_address_;
ModuleArch arch_;
u8 uuid_[kModuleUUIDSize];
bool instrumented_;
diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc
index 43900f87b..d7fa34a58 100644
--- a/lib/sanitizer_common/sanitizer_flags.inc
+++ b/lib/sanitizer_common/sanitizer_flags.inc
@@ -74,6 +74,9 @@ COMMON_FLAG(bool, allocator_may_return_null, false,
COMMON_FLAG(bool, print_summary, true,
"If false, disable printing error summaries in addition to error "
"reports.")
+COMMON_FLAG(int, print_module_map, 0,
+ "OS X only. 0 = don't print, 1 = print only once before process "
+ "exits, 2 = print after each report.")
COMMON_FLAG(bool, check_printf, true, "Check printf arguments.")
COMMON_FLAG(bool, handle_segv, true,
"If set, registers the tool's custom SIGSEGV/SIGBUS handler.")
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
index 76cdc72a0..7328a5c0a 100644
--- a/lib/sanitizer_common/sanitizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -1393,6 +1393,8 @@ void MaybeReexec() {
// No need to re-exec on Linux.
}
+void PrintModuleMap() { }
+
uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding) {
UNREACHABLE("FindAvailableMemoryRange is not available");
return 0;
diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc
index 73e018c85..b4f8ab5e3 100644
--- a/lib/sanitizer_common/sanitizer_mac.cc
+++ b/lib/sanitizer_common/sanitizer_mac.cc
@@ -854,6 +854,36 @@ void SignalContext::DumpAllRegisters(void *context) {
# undef DUMPREG
}
+static inline bool CompareBaseAddress(const LoadedModule &a,
+ const LoadedModule &b) {
+ return a.base_address() < b.base_address();
+}
+
+void FormatUUID(char *out, uptr size, const u8 *uuid) {
+ internal_snprintf(out, size,
+ "<%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-"
+ "%02X%02X%02X%02X%02X%02X>",
+ uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5],
+ uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15]);
+}
+
+void PrintModuleMap() {
+ Printf("Process module map:\n");
+ MemoryMappingLayout memory_mapping(false);
+ InternalMmapVector<LoadedModule> modules(/*initial_capacity*/ 128);
+ memory_mapping.DumpListOfModules(&modules);
+ InternalSort(&modules, modules.size(), CompareBaseAddress);
+ for (uptr i = 0; i < modules.size(); ++i) {
+ char uuid_str[128];
+ FormatUUID(uuid_str, sizeof(uuid_str), modules[i].uuid());
+ Printf("0x%zx-0x%zx %s (%s) %s\n", modules[i].base_address(),
+ modules[i].max_executable_address(), modules[i].full_name(),
+ ModuleArchToString(modules[i].arch()), uuid_str);
+ }
+ Printf("End of module map.\n");
+}
+
} // namespace __sanitizer
#endif // SANITIZER_MAC
diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc
index f394e75b0..c8317be60 100644
--- a/lib/sanitizer_common/sanitizer_printf.cc
+++ b/lib/sanitizer_common/sanitizer_printf.cc
@@ -43,7 +43,7 @@ static int AppendChar(char **buff, const char *buff_end, char c) {
// on the value of |pad_with_zero|.
static int AppendNumber(char **buff, const char *buff_end, u64 absolute_value,
u8 base, u8 minimal_num_length, bool pad_with_zero,
- bool negative) {
+ bool negative, bool uppercase) {
uptr const kMaxLen = 30;
RAW_CHECK(base == 10 || base == 16);
RAW_CHECK(base == 10 || !negative);
@@ -76,23 +76,25 @@ static int AppendNumber(char **buff, const char *buff_end, u64 absolute_value,
if (negative && !pad_with_zero) result += AppendChar(buff, buff_end, '-');
for (; pos >= 0; pos--) {
char digit = static_cast<char>(num_buffer[pos]);
- result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit
- : 'a' + digit - 10);
+ digit = (digit < 10) ? '0' + digit : (uppercase ? 'A' : 'a') + digit - 10;
+ result += AppendChar(buff, buff_end, digit);
}
return result;
}
static int AppendUnsigned(char **buff, const char *buff_end, u64 num, u8 base,
- u8 minimal_num_length, bool pad_with_zero) {
+ u8 minimal_num_length, bool pad_with_zero,
+ bool uppercase) {
return AppendNumber(buff, buff_end, num, base, minimal_num_length,
- pad_with_zero, false /* negative */);
+ pad_with_zero, false /* negative */, uppercase);
}
static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num,
u8 minimal_num_length, bool pad_with_zero) {
bool negative = (num < 0);
return AppendNumber(buff, buff_end, (u64)(negative ? -num : num), 10,
- minimal_num_length, pad_with_zero, negative);
+ minimal_num_length, pad_with_zero, negative,
+ false /* uppercase */);
}
static int AppendString(char **buff, const char *buff_end, int precision,
@@ -112,14 +114,16 @@ 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_POINTER_FORMAT_LENGTH, true);
+ SANITIZER_POINTER_FORMAT_LENGTH,
+ true /* pad_with_zero */, false /* uppercase */);
return result;
}
int VSNPrintf(char *buff, int buff_length,
const char *format, va_list args) {
static const char *kPrintfFormatsHelp =
- "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x}; %p; %(\\.\\*)?s; %c\n";
+ "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x,X}; %p; %(\\.\\*)?s; "
+ "%c\n";
RAW_CHECK(format);
RAW_CHECK(buff_length > 0);
const char *buff_end = &buff[buff_length - 1];
@@ -164,12 +168,14 @@ int VSNPrintf(char *buff, int buff_length,
break;
}
case 'u':
- case 'x': {
+ case 'x':
+ case 'X': {
uval = have_ll ? va_arg(args, u64)
: have_z ? va_arg(args, uptr)
: va_arg(args, unsigned);
- result += AppendUnsigned(&buff, buff_end, uval,
- (*cur == 'u') ? 10 : 16, width, pad_with_zero);
+ bool uppercase = (*cur == 'X');
+ result += AppendUnsigned(&buff, buff_end, uval, (*cur == 'u') ? 10 : 16,
+ width, pad_with_zero, uppercase);
break;
}
case 'p': {
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
index 6efd33021..9682d2921 100644
--- a/lib/sanitizer_common/sanitizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -388,6 +388,8 @@ void DumpProcessMap() {
}
#endif
+void PrintModuleMap() { }
+
void DisableCoreDumperIfNecessary() {
// Do nothing.
}
diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc
index 156876e5c..07fd41208 100644
--- a/lib/tsan/rtl/tsan_report.cc
+++ b/lib/tsan/rtl/tsan_report.cc
@@ -358,6 +358,8 @@ void PrintReport(const ReportDesc *rep) {
ReportErrorSummary(rep_typ_str, frame->info);
}
+ if (common_flags()->print_module_map == 2) PrintModuleMap();
+
Printf("==================\n");
}
diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc
index 804f3cf64..bfb835889 100644
--- a/lib/tsan/rtl/tsan_rtl.cc
+++ b/lib/tsan/rtl/tsan_rtl.cc
@@ -404,6 +404,8 @@ void Initialize(ThreadState *thr) {
int Finalize(ThreadState *thr) {
bool failed = false;
+ if (common_flags()->print_module_map == 1) PrintModuleMap();
+
if (flags()->atexit_sleep_ms > 0 && ThreadCount(thr) > 1)
SleepForMillis(flags()->atexit_sleep_ms);
diff --git a/test/asan/TestCases/Darwin/uuid.cc b/test/asan/TestCases/Darwin/uuid.cc
new file mode 100644
index 000000000..eaa022036
--- /dev/null
+++ b/test/asan/TestCases/Darwin/uuid.cc
@@ -0,0 +1,28 @@
+// RUN: %clangxx_asan %s -o %t
+// RUN: %env_asan_opts=print_module_map=1 not %run %t 2>&1 | FileCheck %s
+// RUN: %env_asan_opts=print_module_map=2 not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan %s -o %t -fsanitize-recover=address
+// RUN: %env_asan_opts=print_module_map=2:halt_on_error=0 %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char *argv[]) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "otool -l %s", argv[0]);
+ system(buf);
+ // CHECK: cmd LC_UUID
+ // CHECK-NEXT: cmdsize 24
+ // CHECK-NEXT: uuid [[UUID:[0-9A-F-]{36}]]
+
+ char *x = (char*)malloc(10 * sizeof(char));
+ free(x);
+ char mybuf[10];
+ memcpy(mybuf, x, 10);
+ // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
+ // CHECK: Process module map:
+ // CHECK: uuid.cc.tmp {{.*}} <[[UUID]]>
+
+ fprintf(stderr, "Done.\n");
+}