[ASan] Introduce the dump_instruction_bytes flag to print the faulting instruction upon SIGSEGV

When dump_instruction_bytes=1 and the instruction pointer doesn't point to the zero page, ASan prints 16 bytes starting at the instruction point.

llvm-svn: 218243
This commit is contained in:
Alexander Potapenko 2014-09-22 11:58:52 +00:00
parent 6da8a243f9
commit 1aba330e52
4 changed files with 55 additions and 4 deletions

View File

@ -65,6 +65,7 @@ struct Flags {
int detect_invalid_pointer_pairs;
bool detect_container_overflow;
int detect_odr_violation;
bool dump_instruction_bytes;
};
extern Flags asan_flags_dont_use_directly;

View File

@ -86,15 +86,24 @@ class Decorator: public __sanitizer::SanitizerCommonDecorator {
}
}
const char *EndShadowByte() { return Default(); }
const char *MemoryByte() { return Magenta(); }
const char *EndMemoryByte() { return Default(); }
};
// ---------------------- Helper functions ----------------------- {{{1
static void PrintShadowByte(InternalScopedString *str, const char *before,
u8 byte, const char *after = "\n") {
static void PrintMemoryByte(InternalScopedString *str, const char *before,
u8 byte, bool in_shadow, const char *after = "\n") {
Decorator d;
str->append("%s%s%x%x%s%s", before, d.ShadowByte(byte), byte >> 4, byte & 15,
d.EndShadowByte(), after);
str->append("%s%s%x%x%s%s", before,
in_shadow ? d.ShadowByte(byte) : d.MemoryByte(),
byte >> 4, byte & 15,
in_shadow ? d.EndShadowByte() : d.EndMemoryByte(), after);
}
static void PrintShadowByte(InternalScopedString *str, const char *before,
u8 byte, const char *after = "\n") {
PrintMemoryByte(str, before, byte, /*in_shadow*/true, after);
}
static void PrintShadowBytes(InternalScopedString *str, const char *before,
@ -149,6 +158,22 @@ static void PrintLegend(InternalScopedString *str) {
PrintShadowByte(str, " ASan internal: ", kAsanInternalHeapMagic);
}
void MaybeDumpInstructionBytes(uptr pc) {
if (!flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
return;
InternalScopedString str(1024);
str.append("First 16 instruction bytes at pc: ");
if (IsAccessibleMemoryRange(pc, 16)) {
for (int i = 0; i < 16; ++i) {
PrintMemoryByte(&str, "", ((u8 *)pc)[i], /*in_shadow*/false, " ");
}
str.append("\n");
} else {
str.append("unaccessible\n");
}
Report("%s", str.data());
}
static void PrintShadowMemoryForAddress(uptr addr) {
if (!AddrIsInMem(addr)) return;
uptr shadow_addr = MemToShadow(addr);
@ -636,6 +661,7 @@ void ReportSIGSEGV(const char *description, uptr pc, uptr sp, uptr bp,
Printf("%s", d.EndWarning());
GET_STACK_TRACE_SIGNAL(pc, bp, context);
stack.Print();
MaybeDumpInstructionBytes(pc);
Printf("AddressSanitizer can not provide additional info.\n");
ReportErrorSummary("SEGV", &stack);
}

View File

@ -230,6 +230,9 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
"If >=2, detect violation of One-Definition-Rule (ODR); "
"If ==1, detect ODR-violation only if the two variables "
"have different sizes");
ParseFlag(str, &f->dump_instruction_bytes, "dump_instruction_bytes",
"If true, dump 16 bytes starting at the instruction that caused SEGV");
}
void InitializeFlags(Flags *f, const char *env) {
@ -283,6 +286,7 @@ void InitializeFlags(Flags *f, const char *env) {
f->detect_invalid_pointer_pairs = 0;
f->detect_container_overflow = true;
f->detect_odr_violation = 2;
f->dump_instruction_bytes = false;
// Override from compile definition.
ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefinition());

View File

@ -0,0 +1,20 @@
// Check that ASan prints the faulting instruction bytes on
// dump_instruction_bytes=1
// RUN: %clangxx_asan %s -o %t
// RUN: env ASAN_OPTIONS=dump_instruction_bytes=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-DUMP
// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NODUMP
int main() {
#if defined(__x86_64__)
asm("movq $0, %rax");
asm("movl $0xcafebabe, 0x0(%rax)");
#elif defined(i386)
asm("movl $0, %eax");
asm("movl $0xcafebabe, 0x0(%eax)");
#endif
// CHECK-DUMP: First 16 instruction bytes at pc: c7 00 be ba fe ca
// CHECK-NODUMP-NOT: First 16 instruction bytes
return 0;
}
// XFAIL: arm