diff options
author | Ben Cheng <bccheng@google.com> | 2014-03-25 22:37:19 -0700 |
---|---|---|
committer | Ben Cheng <bccheng@google.com> | 2014-03-25 22:37:19 -0700 |
commit | 1bc5aee63eb72b341f506ad058502cd0361f0d10 (patch) | |
tree | c607e8252f3405424ff15bc2d00aa38dadbb2518 /gcc-4.9/libsanitizer/ubsan/ubsan_diag.cc | |
parent | 283a0bf58fcf333c58a2a92c3ebbc41fb9eb1fdb (diff) | |
download | toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.gz toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.bz2 toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.zip |
Initial checkin of GCC 4.9.0 from trunk (r208799).
Change-Id: I48a3c08bb98542aa215912a75f03c0890e497dba
Diffstat (limited to 'gcc-4.9/libsanitizer/ubsan/ubsan_diag.cc')
-rw-r--r-- | gcc-4.9/libsanitizer/ubsan/ubsan_diag.cc | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/gcc-4.9/libsanitizer/ubsan/ubsan_diag.cc b/gcc-4.9/libsanitizer/ubsan/ubsan_diag.cc new file mode 100644 index 000000000..786ffa725 --- /dev/null +++ b/gcc-4.9/libsanitizer/ubsan/ubsan_diag.cc @@ -0,0 +1,271 @@ +//===-- ubsan_diag.cc -----------------------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Diagnostic reporting for the UBSan runtime. +// +//===----------------------------------------------------------------------===// + +#include "ubsan_diag.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_report_decorator.h" +#include "sanitizer_common/sanitizer_stacktrace.h" +#include "sanitizer_common/sanitizer_symbolizer.h" +#include <stdio.h> + +using namespace __ubsan; + +Location __ubsan::getCallerLocation(uptr CallerLoc) { + if (!CallerLoc) + return Location(); + + uptr Loc = StackTrace::GetPreviousInstructionPc(CallerLoc); + return getFunctionLocation(Loc, 0); +} + +Location __ubsan::getFunctionLocation(uptr Loc, const char **FName) { + if (!Loc) + return Location(); + + AddressInfo Info; + if (!Symbolizer::GetOrInit()->SymbolizeCode(Loc, &Info, 1) || + !Info.module || !*Info.module) + return Location(Loc); + + if (FName && Info.function) + *FName = Info.function; + + if (!Info.file) + return ModuleLocation(Info.module, Info.module_offset); + + return SourceLocation(Info.file, Info.line, Info.column); +} + +Diag &Diag::operator<<(const TypeDescriptor &V) { + return AddArg(V.getTypeName()); +} + +Diag &Diag::operator<<(const Value &V) { + if (V.getType().isSignedIntegerTy()) + AddArg(V.getSIntValue()); + else if (V.getType().isUnsignedIntegerTy()) + AddArg(V.getUIntValue()); + else if (V.getType().isFloatTy()) + AddArg(V.getFloatValue()); + else + AddArg("<unknown>"); + return *this; +} + +/// Hexadecimal printing for numbers too large for Printf to handle directly. +static void PrintHex(UIntMax Val) { +#if HAVE_INT128_T + Printf("0x%08x%08x%08x%08x", + (unsigned int)(Val >> 96), + (unsigned int)(Val >> 64), + (unsigned int)(Val >> 32), + (unsigned int)(Val)); +#else + UNREACHABLE("long long smaller than 64 bits?"); +#endif +} + +static void renderLocation(Location Loc) { + InternalScopedString LocBuffer(1024); + switch (Loc.getKind()) { + case Location::LK_Source: { + SourceLocation SLoc = Loc.getSourceLocation(); + if (SLoc.isInvalid()) + LocBuffer.append("<unknown>"); + else + PrintSourceLocation(&LocBuffer, SLoc.getFilename(), SLoc.getLine(), + SLoc.getColumn()); + break; + } + case Location::LK_Module: + PrintModuleAndOffset(&LocBuffer, Loc.getModuleLocation().getModuleName(), + Loc.getModuleLocation().getOffset()); + break; + case Location::LK_Memory: + LocBuffer.append("%p", Loc.getMemoryLocation()); + break; + case Location::LK_Null: + LocBuffer.append("<unknown>"); + break; + } + Printf("%s:", LocBuffer.data()); +} + +static void renderText(const char *Message, const Diag::Arg *Args) { + for (const char *Msg = Message; *Msg; ++Msg) { + if (*Msg != '%') { + char Buffer[64]; + unsigned I; + for (I = 0; Msg[I] && Msg[I] != '%' && I != 63; ++I) + Buffer[I] = Msg[I]; + Buffer[I] = '\0'; + Printf(Buffer); + Msg += I - 1; + } else { + const Diag::Arg &A = Args[*++Msg - '0']; + switch (A.Kind) { + case Diag::AK_String: + Printf("%s", A.String); + break; + case Diag::AK_Mangled: { + Printf("'%s'", Symbolizer::GetOrInit()->Demangle(A.String)); + break; + } + case Diag::AK_SInt: + // 'long long' is guaranteed to be at least 64 bits wide. + if (A.SInt >= INT64_MIN && A.SInt <= INT64_MAX) + Printf("%lld", (long long)A.SInt); + else + PrintHex(A.SInt); + break; + case Diag::AK_UInt: + if (A.UInt <= UINT64_MAX) + Printf("%llu", (unsigned long long)A.UInt); + else + PrintHex(A.UInt); + break; + case Diag::AK_Float: { + // FIXME: Support floating-point formatting in sanitizer_common's + // printf, and stop using snprintf here. + char Buffer[32]; + snprintf(Buffer, sizeof(Buffer), "%Lg", (long double)A.Float); + Printf("%s", Buffer); + break; + } + case Diag::AK_Pointer: + Printf("%p", A.Pointer); + break; + } + } + } +} + +/// Find the earliest-starting range in Ranges which ends after Loc. +static Range *upperBound(MemoryLocation Loc, Range *Ranges, + unsigned NumRanges) { + Range *Best = 0; + for (unsigned I = 0; I != NumRanges; ++I) + if (Ranges[I].getEnd().getMemoryLocation() > Loc && + (!Best || + Best->getStart().getMemoryLocation() > + Ranges[I].getStart().getMemoryLocation())) + Best = &Ranges[I]; + return Best; +} + +/// Render a snippet of the address space near a location. +static void renderMemorySnippet(const __sanitizer::AnsiColorDecorator &Decor, + MemoryLocation Loc, + Range *Ranges, unsigned NumRanges, + const Diag::Arg *Args) { + const unsigned BytesToShow = 32; + const unsigned MinBytesNearLoc = 4; + + // Show at least the 8 bytes surrounding Loc. + MemoryLocation Min = Loc - MinBytesNearLoc, Max = Loc + MinBytesNearLoc; + for (unsigned I = 0; I < NumRanges; ++I) { + Min = __sanitizer::Min(Ranges[I].getStart().getMemoryLocation(), Min); + Max = __sanitizer::Max(Ranges[I].getEnd().getMemoryLocation(), Max); + } + + // If we have too many interesting bytes, prefer to show bytes after Loc. + if (Max - Min > BytesToShow) + Min = __sanitizer::Min(Max - BytesToShow, Loc - MinBytesNearLoc); + Max = Min + BytesToShow; + + // Emit data. + for (uptr P = Min; P != Max; ++P) { + // FIXME: Check that the address is readable before printing it. + unsigned char C = *reinterpret_cast<const unsigned char*>(P); + Printf("%s%02x", (P % 8 == 0) ? " " : " ", C); + } + Printf("\n"); + + // Emit highlights. + Printf(Decor.Green()); + Range *InRange = upperBound(Min, Ranges, NumRanges); + for (uptr P = Min; P != Max; ++P) { + char Pad = ' ', Byte = ' '; + if (InRange && InRange->getEnd().getMemoryLocation() == P) + InRange = upperBound(P, Ranges, NumRanges); + if (!InRange && P > Loc) + break; + if (InRange && InRange->getStart().getMemoryLocation() < P) + Pad = '~'; + if (InRange && InRange->getStart().getMemoryLocation() <= P) + Byte = '~'; + char Buffer[] = { Pad, Pad, P == Loc ? '^' : Byte, Byte, 0 }; + Printf((P % 8 == 0) ? Buffer : &Buffer[1]); + } + Printf("%s\n", Decor.Default()); + + // Go over the line again, and print names for the ranges. + InRange = 0; + unsigned Spaces = 0; + for (uptr P = Min; P != Max; ++P) { + if (!InRange || InRange->getEnd().getMemoryLocation() == P) + InRange = upperBound(P, Ranges, NumRanges); + if (!InRange) + break; + + Spaces += (P % 8) == 0 ? 2 : 1; + + if (InRange && InRange->getStart().getMemoryLocation() == P) { + while (Spaces--) + Printf(" "); + renderText(InRange->getText(), Args); + Printf("\n"); + // FIXME: We only support naming one range for now! + break; + } + + Spaces += 2; + } + + // FIXME: Print names for anything we can identify within the line: + // + // * If we can identify the memory itself as belonging to a particular + // global, stack variable, or dynamic allocation, then do so. + // + // * If we have a pointer-size, pointer-aligned range highlighted, + // determine whether the value of that range is a pointer to an + // entity which we can name, and if so, print that name. + // + // This needs an external symbolizer, or (preferably) ASan instrumentation. +} + +Diag::~Diag() { + __sanitizer::AnsiColorDecorator Decor(PrintsToTty()); + SpinMutexLock l(&CommonSanitizerReportMutex); + Printf(Decor.Bold()); + + renderLocation(Loc); + + switch (Level) { + case DL_Error: + Printf("%s runtime error: %s%s", + Decor.Red(), Decor.Default(), Decor.Bold()); + break; + + case DL_Note: + Printf("%s note: %s", Decor.Black(), Decor.Default()); + break; + } + + renderText(Message, Args); + + Printf("%s\n", Decor.Default()); + + if (Loc.isMemoryLocation()) + renderMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges, + NumRanges, Args); +} |