ubsan_diag.cc revision 5f1164955fb28a9bcb826abc195aa2119feb0f97
1//===-- ubsan_diag.cc -----------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Diagnostic reporting for the UBSan runtime.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ubsan_diag.h"
15#include "sanitizer_common/sanitizer_common.h"
16#include "sanitizer_common/sanitizer_libc.h"
17#include "sanitizer_common/sanitizer_stacktrace.h"
18#include "sanitizer_common/sanitizer_symbolizer.h"
19#include <stdio.h>
20
21using namespace __ubsan;
22
23Location __ubsan::getCallerLocation(uptr CallerLoc) {
24  if (!CallerLoc)
25    return Location();
26
27  // Adjust to find the call instruction.
28  // FIXME: This is not portable.
29  --CallerLoc;
30
31  AddressInfo Info;
32  if (!SymbolizeCode(CallerLoc, &Info, 1) || !Info.module || !*Info.module)
33    return Location(CallerLoc);
34
35  if (!Info.function)
36    return ModuleLocation(Info.module, Info.module_offset);
37
38  return SourceLocation(Info.file, Info.line, Info.column);
39}
40
41Diag &Diag::operator<<(const TypeDescriptor &V) {
42  return AddArg(V.getTypeName());
43}
44
45Diag &Diag::operator<<(const Value &V) {
46  if (V.getType().isSignedIntegerTy())
47    AddArg(V.getSIntValue());
48  else if (V.getType().isUnsignedIntegerTy())
49    AddArg(V.getUIntValue());
50  else if (V.getType().isFloatTy())
51    AddArg(V.getFloatValue());
52  else
53    AddArg("<unknown>");
54  return *this;
55}
56
57/// Hexadecimal printing for numbers too large for fprintf to handle directly.
58static void PrintHex(UIntMax Val) {
59#if HAVE_INT128_T
60  Printf("0x%08x%08x%08x%08x",
61          (unsigned int)(Val >> 96),
62          (unsigned int)(Val >> 64),
63          (unsigned int)(Val >> 32),
64          (unsigned int)(Val));
65#else
66  UNREACHABLE("long long smaller than 64 bits?");
67#endif
68}
69
70static void renderLocation(Location Loc) {
71  switch (Loc.getKind()) {
72  case Location::LK_Source: {
73    SourceLocation SLoc = Loc.getSourceLocation();
74    if (SLoc.isInvalid())
75      RawWrite("<unknown>:");
76    else {
77      Printf("%s:%d:", SLoc.getFilename(), SLoc.getLine());
78      if (SLoc.getColumn())
79        Printf("%d:", SLoc.getColumn());
80    }
81    break;
82  }
83  case Location::LK_Module:
84    Printf("%s:0x%zx:", Loc.getModuleLocation().getModuleName(),
85           Loc.getModuleLocation().getOffset());
86    break;
87  case Location::LK_Memory:
88    Printf("0x%zx:", Loc.getMemoryLocation());
89    break;
90  case Location::LK_Null:
91    RawWrite("<unknown>:");
92  }
93}
94
95Diag::~Diag() {
96  bool UseAnsiColor = PrintsToTty();
97  if (UseAnsiColor)
98    RawWrite("\033[1m");
99
100  renderLocation(Loc);
101
102  if (UseAnsiColor)
103    RawWrite("\033[31m");
104
105  RawWrite(" runtime error: ");
106  if (UseAnsiColor)
107    RawWrite("\033[0;1m");
108  for (const char *Msg = Message; *Msg; ++Msg) {
109    if (*Msg != '%') {
110      char Buffer[64];
111      unsigned I;
112      for (I = 0; Msg[I] && Msg[I] != '%' && I != 63; ++I)
113        Buffer[I] = Msg[I];
114      Buffer[I] = '\0';
115      RawWrite(Buffer);
116      Msg += I - 1;
117    } else {
118      const Arg &A = Args[*++Msg - '0'];
119      switch (A.Kind) {
120      case AK_String:
121        Printf("%s", A.String);
122        break;
123      case AK_SInt:
124        // 'long long' is guaranteed to be at least 64 bits wide.
125        if (A.SInt >= INT64_MIN && A.SInt <= INT64_MAX)
126          Printf("%lld", (long long)A.SInt);
127        else
128          PrintHex(A.SInt);
129        break;
130      case AK_UInt:
131        if (A.UInt <= UINT64_MAX)
132          Printf("%llu", (unsigned long long)A.UInt);
133        else
134          PrintHex(A.UInt);
135        break;
136      case AK_Float: {
137        // FIXME: Support floating-point formatting in sanitizer_common's
138        //        printf, and stop using snprintf here.
139        char Buffer[32];
140        snprintf(Buffer, sizeof(Buffer), "%Lg", (long double)A.Float);
141        Printf("%s", Buffer);
142        break;
143      }
144      case AK_Pointer:
145        Printf("0x%zx", (uptr)A.Pointer);
146        break;
147      }
148    }
149  }
150  RawWrite("\n");
151  if (UseAnsiColor)
152    Printf("\033[0m");
153}
154