Index: lib/asan/asan_flags.h =================================================================== --- lib/asan/asan_flags.h +++ lib/asan/asan_flags.h @@ -65,6 +65,7 @@ int detect_invalid_pointer_pairs; bool detect_container_overflow; int detect_odr_violation; + bool dump_instruction_bytes; }; extern Flags asan_flags_dont_use_directly; Index: lib/asan/asan_report.cc =================================================================== --- lib/asan/asan_report.cc +++ lib/asan/asan_report.cc @@ -86,15 +86,24 @@ } } 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 @@ 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, "", ((char *)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 @@ 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); } Index: lib/asan/asan_rtl.cc =================================================================== --- lib/asan/asan_rtl.cc +++ lib/asan/asan_rtl.cc @@ -230,6 +230,9 @@ "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 @@ 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()); Index: test/asan/TestCases/dump_instruction_bytes.cc =================================================================== --- test/asan/TestCases/dump_instruction_bytes.cc +++ test/asan/TestCases/dump_instruction_bytes.cc @@ -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