]> git.ipfire.org Git - thirdparty/gcc.git/blame - libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cc
Remove support for alternative Solaris 11.4 ld -V output
[thirdparty/gcc.git] / libsanitizer / sanitizer_common / sanitizer_symbolizer_report.cc
CommitLineData
d2ef4bee 1//===-- sanitizer_symbolizer_report.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/// This file is shared between AddressSanitizer and other sanitizer run-time
9/// libraries and implements symbolized reports related functions.
10///
11//===----------------------------------------------------------------------===//
12
13#include "sanitizer_common.h"
14#include "sanitizer_file.h"
15#include "sanitizer_flags.h"
16#include "sanitizer_procmaps.h"
17#include "sanitizer_report_decorator.h"
18#include "sanitizer_stacktrace.h"
19#include "sanitizer_stacktrace_printer.h"
20#include "sanitizer_symbolizer.h"
21
22#if SANITIZER_POSIX
23# include "sanitizer_posix.h"
24# include <sys/mman.h>
25#endif
26
27namespace __sanitizer {
28
29#if !SANITIZER_GO
30void ReportErrorSummary(const char *error_type, const AddressInfo &info,
31 const char *alt_tool_name) {
32 if (!common_flags()->print_summary) return;
33 InternalScopedString buff(kMaxSummaryLength);
34 buff.append("%s ", error_type);
35 RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style,
36 common_flags()->strip_path_prefix);
37 ReportErrorSummary(buff.data(), alt_tool_name);
38}
39#endif
40
41#if !SANITIZER_FUCHSIA
42
43bool ReportFile::SupportsColors() {
44 SpinMutexLock l(mu);
45 ReopenIfNecessary();
46 return SupportsColoredOutput(fd);
47}
48
49static INLINE bool ReportSupportsColors() {
50 return report_file.SupportsColors();
51}
52
53#else // SANITIZER_FUCHSIA
54
55// Fuchsia's logs always go through post-processing that handles colorization.
56static INLINE bool ReportSupportsColors() { return true; }
57
58#endif // !SANITIZER_FUCHSIA
59
60bool ColorizeReports() {
61 // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color
62 // printing on Windows.
63 if (SANITIZER_WINDOWS)
64 return false;
65
66 const char *flag = common_flags()->color;
67 return internal_strcmp(flag, "always") == 0 ||
68 (internal_strcmp(flag, "auto") == 0 && ReportSupportsColors());
69}
70
71void ReportErrorSummary(const char *error_type, const StackTrace *stack,
72 const char *alt_tool_name) {
73#if !SANITIZER_GO
74 if (!common_flags()->print_summary)
75 return;
76 if (stack->size == 0) {
77 ReportErrorSummary(error_type);
78 return;
79 }
80 // Currently, we include the first stack frame into the report summary.
81 // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
82 uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
83 SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
84 ReportErrorSummary(error_type, frame->info, alt_tool_name);
85 frame->ClearAll();
86#endif
87}
88
89void ReportMmapWriteExec(int prot) {
90#if SANITIZER_POSIX && (!SANITIZER_GO && !SANITIZER_ANDROID)
91 if ((prot & (PROT_WRITE | PROT_EXEC)) != (PROT_WRITE | PROT_EXEC))
92 return;
93
94 ScopedErrorReportLock l;
95 SanitizerCommonDecorator d;
96
97 InternalMmapVector<BufferedStackTrace> stack_buffer(1);
98 BufferedStackTrace *stack = stack_buffer.data();
99 stack->Reset();
100 uptr top = 0;
101 uptr bottom = 0;
102 GET_CALLER_PC_BP_SP;
103 (void)sp;
104 bool fast = common_flags()->fast_unwind_on_fatal;
105 if (fast)
106 GetThreadStackTopAndBottom(false, &top, &bottom);
107 stack->Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, fast);
108
109 Printf("%s", d.Warning());
110 Report("WARNING: %s: writable-executable page usage\n", SanitizerToolName);
111 Printf("%s", d.Default());
112
113 stack->Print();
114 ReportErrorSummary("w-and-x-usage", stack);
115#endif
116}
117
118#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_GO
119void StartReportDeadlySignal() {
120 // Write the first message using fd=2, just in case.
121 // It may actually fail to write in case stderr is closed.
122 CatastrophicErrorWrite(SanitizerToolName, internal_strlen(SanitizerToolName));
123 static const char kDeadlySignal[] = ":DEADLYSIGNAL\n";
124 CatastrophicErrorWrite(kDeadlySignal, sizeof(kDeadlySignal) - 1);
125}
126
127static void MaybeReportNonExecRegion(uptr pc) {
128#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
129 MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
130 MemoryMappedSegment segment;
131 while (proc_maps.Next(&segment)) {
132 if (pc >= segment.start && pc < segment.end && !segment.IsExecutable())
133 Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n");
134 }
135#endif
136}
137
138static void PrintMemoryByte(InternalScopedString *str, const char *before,
139 u8 byte) {
140 SanitizerCommonDecorator d;
141 str->append("%s%s%x%x%s ", before, d.MemoryByte(), byte >> 4, byte & 15,
142 d.Default());
143}
144
145static void MaybeDumpInstructionBytes(uptr pc) {
146 if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
147 return;
148 InternalScopedString str(1024);
149 str.append("First 16 instruction bytes at pc: ");
150 if (IsAccessibleMemoryRange(pc, 16)) {
151 for (int i = 0; i < 16; ++i) {
152 PrintMemoryByte(&str, "", ((u8 *)pc)[i]);
153 }
154 str.append("\n");
155 } else {
156 str.append("unaccessible\n");
157 }
158 Report("%s", str.data());
159}
160
161static void MaybeDumpRegisters(void *context) {
162 if (!common_flags()->dump_registers) return;
163 SignalContext::DumpAllRegisters(context);
164}
165
166static void ReportStackOverflowImpl(const SignalContext &sig, u32 tid,
167 UnwindSignalStackCallbackType unwind,
168 const void *unwind_context) {
169 SanitizerCommonDecorator d;
170 Printf("%s", d.Warning());
171 static const char kDescription[] = "stack-overflow";
172 Report("ERROR: %s: %s on address %p (pc %p bp %p sp %p T%d)\n",
173 SanitizerToolName, kDescription, (void *)sig.addr, (void *)sig.pc,
174 (void *)sig.bp, (void *)sig.sp, tid);
175 Printf("%s", d.Default());
176 InternalMmapVector<BufferedStackTrace> stack_buffer(1);
177 BufferedStackTrace *stack = stack_buffer.data();
178 stack->Reset();
179 unwind(sig, unwind_context, stack);
180 stack->Print();
181 ReportErrorSummary(kDescription, stack);
182}
183
184static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
185 UnwindSignalStackCallbackType unwind,
186 const void *unwind_context) {
187 SanitizerCommonDecorator d;
188 Printf("%s", d.Warning());
189 const char *description = sig.Describe();
190 Report("ERROR: %s: %s on unknown address %p (pc %p bp %p sp %p T%d)\n",
191 SanitizerToolName, description, (void *)sig.addr, (void *)sig.pc,
192 (void *)sig.bp, (void *)sig.sp, tid);
193 Printf("%s", d.Default());
194 if (sig.pc < GetPageSizeCached())
195 Report("Hint: pc points to the zero page.\n");
196 if (sig.is_memory_access) {
197 const char *access_type =
198 sig.write_flag == SignalContext::WRITE
199 ? "WRITE"
200 : (sig.write_flag == SignalContext::READ ? "READ" : "UNKNOWN");
201 Report("The signal is caused by a %s memory access.\n", access_type);
202 if (sig.addr < GetPageSizeCached())
203 Report("Hint: address points to the zero page.\n");
204 }
205 MaybeReportNonExecRegion(sig.pc);
206 InternalMmapVector<BufferedStackTrace> stack_buffer(1);
207 BufferedStackTrace *stack = stack_buffer.data();
208 stack->Reset();
209 unwind(sig, unwind_context, stack);
210 stack->Print();
211 MaybeDumpInstructionBytes(sig.pc);
212 MaybeDumpRegisters(sig.context);
213 Printf("%s can not provide additional info.\n", SanitizerToolName);
214 ReportErrorSummary(description, stack);
215}
216
217void ReportDeadlySignal(const SignalContext &sig, u32 tid,
218 UnwindSignalStackCallbackType unwind,
219 const void *unwind_context) {
220 if (sig.IsStackOverflow())
221 ReportStackOverflowImpl(sig, tid, unwind, unwind_context);
222 else
223 ReportDeadlySignalImpl(sig, tid, unwind, unwind_context);
224}
225
226void HandleDeadlySignal(void *siginfo, void *context, u32 tid,
227 UnwindSignalStackCallbackType unwind,
228 const void *unwind_context) {
229 StartReportDeadlySignal();
230 ScopedErrorReportLock rl;
231 SignalContext sig(siginfo, context);
232 ReportDeadlySignal(sig, tid, unwind, unwind_context);
233 Report("ABORTING\n");
234 Die();
235}
236
237#endif // !SANITIZER_FUCHSIA && !SANITIZER_GO
238
239static atomic_uintptr_t reporting_thread = {0};
240static StaticSpinMutex CommonSanitizerReportMutex;
241
242ScopedErrorReportLock::ScopedErrorReportLock() {
243 uptr current = GetThreadSelf();
244 for (;;) {
245 uptr expected = 0;
246 if (atomic_compare_exchange_strong(&reporting_thread, &expected, current,
247 memory_order_relaxed)) {
248 // We've claimed reporting_thread so proceed.
249 CommonSanitizerReportMutex.Lock();
250 return;
251 }
252
253 if (expected == current) {
254 // This is either asynch signal or nested error during error reporting.
255 // Fail simple to avoid deadlocks in Report().
256
257 // Can't use Report() here because of potential deadlocks in nested
258 // signal handlers.
259 CatastrophicErrorWrite(SanitizerToolName,
260 internal_strlen(SanitizerToolName));
261 static const char msg[] = ": nested bug in the same thread, aborting.\n";
262 CatastrophicErrorWrite(msg, sizeof(msg) - 1);
263
264 internal__exit(common_flags()->exitcode);
265 }
266
267 internal_sched_yield();
268 }
269}
270
271ScopedErrorReportLock::~ScopedErrorReportLock() {
272 CommonSanitizerReportMutex.Unlock();
273 atomic_store_relaxed(&reporting_thread, 0);
274}
275
276void ScopedErrorReportLock::CheckLocked() {
277 CommonSanitizerReportMutex.CheckLocked();
278}
279
280} // namespace __sanitizer