* pt.c (lookup_template_class_1): Splice out abi_tag attribute if
[official-gcc.git] / libsanitizer / ubsan / ubsan_diag.cc
blob1dfe7255f68371c40454591373f2b622a745fed7
1 //===-- ubsan_diag.cc -----------------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // Diagnostic reporting for the UBSan runtime.
9 //
10 //===----------------------------------------------------------------------===//
12 #include "ubsan_diag.h"
13 #include "sanitizer_common/sanitizer_common.h"
14 #include "sanitizer_common/sanitizer_flags.h"
15 #include "sanitizer_common/sanitizer_libc.h"
16 #include "sanitizer_common/sanitizer_report_decorator.h"
17 #include "sanitizer_common/sanitizer_stacktrace.h"
18 #include "sanitizer_common/sanitizer_symbolizer.h"
19 #include <stdio.h>
21 using namespace __ubsan;
23 static void InitializeSanitizerCommon() {
24 static StaticSpinMutex init_mu;
25 SpinMutexLock l(&init_mu);
26 static bool initialized;
27 if (initialized)
28 return;
29 if (0 == internal_strcmp(SanitizerToolName, "SanitizerTool")) {
30 // UBSan is run in a standalone mode. Initialize it now.
31 SanitizerToolName = "UndefinedBehaviorSanitizer";
32 CommonFlags *cf = common_flags();
33 SetCommonFlagsDefaults(cf);
34 cf->print_summary = false;
36 initialized = true;
39 Location __ubsan::getCallerLocation(uptr CallerLoc) {
40 if (!CallerLoc)
41 return Location();
43 uptr Loc = StackTrace::GetPreviousInstructionPc(CallerLoc);
44 return getFunctionLocation(Loc, 0);
47 Location __ubsan::getFunctionLocation(uptr Loc, const char **FName) {
48 if (!Loc)
49 return Location();
50 // FIXME: We may need to run initialization earlier.
51 InitializeSanitizerCommon();
53 AddressInfo Info;
54 if (!Symbolizer::GetOrInit()->SymbolizePC(Loc, &Info, 1) ||
55 !Info.module || !*Info.module)
56 return Location(Loc);
58 if (FName && Info.function)
59 *FName = Info.function;
61 if (!Info.file)
62 return ModuleLocation(Info.module, Info.module_offset);
64 return SourceLocation(Info.file, Info.line, Info.column);
67 Diag &Diag::operator<<(const TypeDescriptor &V) {
68 return AddArg(V.getTypeName());
71 Diag &Diag::operator<<(const Value &V) {
72 if (V.getType().isSignedIntegerTy())
73 AddArg(V.getSIntValue());
74 else if (V.getType().isUnsignedIntegerTy())
75 AddArg(V.getUIntValue());
76 else if (V.getType().isFloatTy())
77 AddArg(V.getFloatValue());
78 else
79 AddArg("<unknown>");
80 return *this;
83 /// Hexadecimal printing for numbers too large for Printf to handle directly.
84 static void PrintHex(UIntMax Val) {
85 #if HAVE_INT128_T
86 Printf("0x%08x%08x%08x%08x",
87 (unsigned int)(Val >> 96),
88 (unsigned int)(Val >> 64),
89 (unsigned int)(Val >> 32),
90 (unsigned int)(Val));
91 #else
92 UNREACHABLE("long long smaller than 64 bits?");
93 #endif
96 static void renderLocation(Location Loc) {
97 InternalScopedString LocBuffer(1024);
98 switch (Loc.getKind()) {
99 case Location::LK_Source: {
100 SourceLocation SLoc = Loc.getSourceLocation();
101 if (SLoc.isInvalid())
102 LocBuffer.append("<unknown>");
103 else
104 PrintSourceLocation(&LocBuffer, SLoc.getFilename(), SLoc.getLine(),
105 SLoc.getColumn());
106 break;
108 case Location::LK_Module:
109 PrintModuleAndOffset(&LocBuffer, Loc.getModuleLocation().getModuleName(),
110 Loc.getModuleLocation().getOffset());
111 break;
112 case Location::LK_Memory:
113 LocBuffer.append("%p", Loc.getMemoryLocation());
114 break;
115 case Location::LK_Null:
116 LocBuffer.append("<unknown>");
117 break;
119 Printf("%s:", LocBuffer.data());
122 static void renderText(const char *Message, const Diag::Arg *Args) {
123 for (const char *Msg = Message; *Msg; ++Msg) {
124 if (*Msg != '%') {
125 char Buffer[64];
126 unsigned I;
127 for (I = 0; Msg[I] && Msg[I] != '%' && I != 63; ++I)
128 Buffer[I] = Msg[I];
129 Buffer[I] = '\0';
130 Printf(Buffer);
131 Msg += I - 1;
132 } else {
133 const Diag::Arg &A = Args[*++Msg - '0'];
134 switch (A.Kind) {
135 case Diag::AK_String:
136 Printf("%s", A.String);
137 break;
138 case Diag::AK_Mangled: {
139 Printf("'%s'", Symbolizer::GetOrInit()->Demangle(A.String));
140 break;
142 case Diag::AK_SInt:
143 // 'long long' is guaranteed to be at least 64 bits wide.
144 if (A.SInt >= INT64_MIN && A.SInt <= INT64_MAX)
145 Printf("%lld", (long long)A.SInt);
146 else
147 PrintHex(A.SInt);
148 break;
149 case Diag::AK_UInt:
150 if (A.UInt <= UINT64_MAX)
151 Printf("%llu", (unsigned long long)A.UInt);
152 else
153 PrintHex(A.UInt);
154 break;
155 case Diag::AK_Float: {
156 // FIXME: Support floating-point formatting in sanitizer_common's
157 // printf, and stop using snprintf here.
158 char Buffer[32];
159 snprintf(Buffer, sizeof(Buffer), "%Lg", (long double)A.Float);
160 Printf("%s", Buffer);
161 break;
163 case Diag::AK_Pointer:
164 Printf("%p", A.Pointer);
165 break;
171 /// Find the earliest-starting range in Ranges which ends after Loc.
172 static Range *upperBound(MemoryLocation Loc, Range *Ranges,
173 unsigned NumRanges) {
174 Range *Best = 0;
175 for (unsigned I = 0; I != NumRanges; ++I)
176 if (Ranges[I].getEnd().getMemoryLocation() > Loc &&
177 (!Best ||
178 Best->getStart().getMemoryLocation() >
179 Ranges[I].getStart().getMemoryLocation()))
180 Best = &Ranges[I];
181 return Best;
184 /// Render a snippet of the address space near a location.
185 static void renderMemorySnippet(const __sanitizer::AnsiColorDecorator &Decor,
186 MemoryLocation Loc,
187 Range *Ranges, unsigned NumRanges,
188 const Diag::Arg *Args) {
189 const unsigned BytesToShow = 32;
190 const unsigned MinBytesNearLoc = 4;
192 // Show at least the 8 bytes surrounding Loc.
193 MemoryLocation Min = Loc - MinBytesNearLoc, Max = Loc + MinBytesNearLoc;
194 for (unsigned I = 0; I < NumRanges; ++I) {
195 Min = __sanitizer::Min(Ranges[I].getStart().getMemoryLocation(), Min);
196 Max = __sanitizer::Max(Ranges[I].getEnd().getMemoryLocation(), Max);
199 // If we have too many interesting bytes, prefer to show bytes after Loc.
200 if (Max - Min > BytesToShow)
201 Min = __sanitizer::Min(Max - BytesToShow, Loc - MinBytesNearLoc);
202 Max = Min + BytesToShow;
204 // Emit data.
205 for (uptr P = Min; P != Max; ++P) {
206 // FIXME: Check that the address is readable before printing it.
207 unsigned char C = *reinterpret_cast<const unsigned char*>(P);
208 Printf("%s%02x", (P % 8 == 0) ? " " : " ", C);
210 Printf("\n");
212 // Emit highlights.
213 Printf(Decor.Green());
214 Range *InRange = upperBound(Min, Ranges, NumRanges);
215 for (uptr P = Min; P != Max; ++P) {
216 char Pad = ' ', Byte = ' ';
217 if (InRange && InRange->getEnd().getMemoryLocation() == P)
218 InRange = upperBound(P, Ranges, NumRanges);
219 if (!InRange && P > Loc)
220 break;
221 if (InRange && InRange->getStart().getMemoryLocation() < P)
222 Pad = '~';
223 if (InRange && InRange->getStart().getMemoryLocation() <= P)
224 Byte = '~';
225 char Buffer[] = { Pad, Pad, P == Loc ? '^' : Byte, Byte, 0 };
226 Printf((P % 8 == 0) ? Buffer : &Buffer[1]);
228 Printf("%s\n", Decor.Default());
230 // Go over the line again, and print names for the ranges.
231 InRange = 0;
232 unsigned Spaces = 0;
233 for (uptr P = Min; P != Max; ++P) {
234 if (!InRange || InRange->getEnd().getMemoryLocation() == P)
235 InRange = upperBound(P, Ranges, NumRanges);
236 if (!InRange)
237 break;
239 Spaces += (P % 8) == 0 ? 2 : 1;
241 if (InRange && InRange->getStart().getMemoryLocation() == P) {
242 while (Spaces--)
243 Printf(" ");
244 renderText(InRange->getText(), Args);
245 Printf("\n");
246 // FIXME: We only support naming one range for now!
247 break;
250 Spaces += 2;
253 // FIXME: Print names for anything we can identify within the line:
255 // * If we can identify the memory itself as belonging to a particular
256 // global, stack variable, or dynamic allocation, then do so.
258 // * If we have a pointer-size, pointer-aligned range highlighted,
259 // determine whether the value of that range is a pointer to an
260 // entity which we can name, and if so, print that name.
262 // This needs an external symbolizer, or (preferably) ASan instrumentation.
265 Diag::~Diag() {
266 __sanitizer::AnsiColorDecorator Decor(PrintsToTty());
267 SpinMutexLock l(&CommonSanitizerReportMutex);
268 Printf(Decor.Bold());
270 renderLocation(Loc);
272 switch (Level) {
273 case DL_Error:
274 Printf("%s runtime error: %s%s",
275 Decor.Red(), Decor.Default(), Decor.Bold());
276 break;
278 case DL_Note:
279 Printf("%s note: %s", Decor.Black(), Decor.Default());
280 break;
283 renderText(Message, Args);
285 Printf("%s\n", Decor.Default());
287 if (Loc.isMemoryLocation())
288 renderMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges,
289 NumRanges, Args);