• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/debug/stack_trace.h"
6 
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <signal.h>
10 #include <stddef.h>
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/param.h>
16 #include <sys/stat.h>
17 #include <sys/syscall.h>
18 #include <sys/types.h>
19 #include <unistd.h>
20 
21 #include <algorithm>
22 #include <array>
23 #include <map>
24 #include <memory>
25 #include <ostream>
26 #include <string>
27 #include <tuple>
28 #include <vector>
29 
30 #include "base/containers/heap_array.h"
31 #include "base/containers/span.h"
32 #include "base/containers/span_writer.h"
33 #include "base/memory/raw_ptr.h"
34 #include "base/strings/cstring_view.h"
35 #include "build/build_config.h"
36 
37 // Controls whether `dladdr(...)` is used to print the callstack. This is
38 // only used on iOS Official build where `backtrace_symbols(...)` prints
39 // misleading symbols (as the binary is stripped).
40 #if BUILDFLAG(IS_IOS) && defined(OFFICIAL_BUILD)
41 #define HAVE_DLADDR
42 #include <dlfcn.h>
43 #endif
44 
45 // Surprisingly, uClibc defines __GLIBC__ in some build configs, but
46 // execinfo.h and backtrace(3) are really only present in glibc and in macOS
47 // libc.
48 #if BUILDFLAG(IS_APPLE) || \
49     (defined(__GLIBC__) && !defined(__UCLIBC__) && !defined(__AIX))
50 #define HAVE_BACKTRACE
51 #include <execinfo.h>
52 #endif
53 
54 // Controls whether to include code to demangle C++ symbols.
55 #if !defined(USE_SYMBOLIZE) && defined(HAVE_BACKTRACE) && !defined(HAVE_DLADDR)
56 #define DEMANGLE_SYMBOLS
57 #endif
58 
59 #if defined(DEMANGLE_SYMBOLS)
60 #include <cxxabi.h>
61 #endif
62 
63 #if BUILDFLAG(IS_APPLE)
64 #include <AvailabilityMacros.h>
65 #endif
66 
67 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
68 #include <sys/prctl.h>
69 
70 #include "base/debug/proc_maps_linux.h"
71 #endif
72 
73 #include "base/cfi_buildflags.h"
74 #include "base/debug/debugger.h"
75 #include "base/debug/debugging_buildflags.h"
76 #include "base/debug/stack_trace.h"
77 #include "base/files/scoped_file.h"
78 #include "base/logging.h"
79 #include "base/memory/free_deleter.h"
80 #include "base/memory/singleton.h"
81 #include "base/numerics/safe_conversions.h"
82 #include "base/posix/eintr_wrapper.h"
83 #include "base/strings/string_number_conversions.h"
84 #include "base/strings/string_util.h"
85 #include "build/build_config.h"
86 
87 #if defined(USE_SYMBOLIZE)
88 #include "base/third_party/symbolize/symbolize.h"  // nogncheck
89 
90 #if BUILDFLAG(ENABLE_STACK_TRACE_LINE_NUMBERS)
91 #include "base/debug/dwarf_line_no.h"  // nogncheck
92 #endif
93 
94 #endif
95 
96 namespace base::debug {
97 
98 namespace {
99 
100 volatile sig_atomic_t in_signal_handler = 0;
101 
102 #if !BUILDFLAG(IS_NACL)
103 bool (*try_handle_signal)(int, siginfo_t*, void*) = nullptr;
104 #endif
105 
106 #if defined(DEMANGLE_SYMBOLS)
107 // The prefix used for mangled symbols, per the Itanium C++ ABI:
108 // http://www.codesourcery.com/cxx-abi/abi.html#mangling
109 const char kMangledSymbolPrefix[] = "_Z";
110 
111 // Characters that can be used for symbols, generated by Ruby:
112 // (('a'..'z').to_a+('A'..'Z').to_a+('0'..'9').to_a + ['_']).join
113 const char kSymbolCharacters[] =
114     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
115 
116 // Demangles C++ symbols in the given text. Example:
117 //
118 // "out/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]"
119 // =>
120 // "out/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]"
DemangleSymbols(std::string * text)121 void DemangleSymbols(std::string* text) {
122   // Note: code in this function is NOT async-signal safe (std::string uses
123   // malloc internally).
124 
125   std::string::size_type search_from = 0;
126   while (search_from < text->size()) {
127     // Look for the start of a mangled symbol, from search_from.
128     std::string::size_type mangled_start =
129         text->find(kMangledSymbolPrefix, search_from);
130     if (mangled_start == std::string::npos) {
131       break;  // Mangled symbol not found.
132     }
133 
134     // Look for the end of the mangled symbol.
135     std::string::size_type mangled_end =
136         text->find_first_not_of(kSymbolCharacters, mangled_start);
137     if (mangled_end == std::string::npos) {
138       mangled_end = text->size();
139     }
140     std::string mangled_symbol =
141         text->substr(mangled_start, mangled_end - mangled_start);
142 
143     // Try to demangle the mangled symbol candidate.
144     int status = 0;
145     std::unique_ptr<char, base::FreeDeleter> demangled_symbol(
146         abi::__cxa_demangle(mangled_symbol.c_str(), nullptr, 0, &status));
147     if (status == 0) {  // Demangling is successful.
148       // Remove the mangled symbol.
149       text->erase(mangled_start, mangled_end - mangled_start);
150       // Insert the demangled symbol.
151       text->insert(mangled_start, demangled_symbol.get());
152       // Next time, we'll start right after the demangled symbol we inserted.
153       search_from = mangled_start + strlen(demangled_symbol.get());
154     } else {
155       // Failed to demangle.  Retry after the "_Z" we just found.
156       search_from = mangled_start + 2;
157     }
158   }
159 }
160 #endif  // defined(DEMANGLE_SYMBOLS)
161 
162 class BacktraceOutputHandler {
163  public:
164   virtual void HandleOutput(const char* output) = 0;
165 
166  protected:
167   virtual ~BacktraceOutputHandler() = default;
168 };
169 
170 #if defined(HAVE_BACKTRACE)
OutputPointer(const void * pointer,BacktraceOutputHandler * handler)171 void OutputPointer(const void* pointer, BacktraceOutputHandler* handler) {
172   // This should be more than enough to store a 64-bit number in hex:
173   // 16 hex digits + 1 for null-terminator.
174   char buf[17] = { '\0' };
175   handler->HandleOutput("0x");
176   internal::itoa_r(reinterpret_cast<intptr_t>(pointer), 16, 12, buf);
177   handler->HandleOutput(buf);
178 }
179 
180 #if defined(HAVE_DLADDR) || defined(USE_SYMBOLIZE)
OutputValue(size_t value,BacktraceOutputHandler * handler)181 void OutputValue(size_t value, BacktraceOutputHandler* handler) {
182   // Max unsigned 64-bit number in decimal has 20 digits (18446744073709551615).
183   // Hence, 30 digits should be more than enough to represent it in decimal
184   // (including the null-terminator).
185   char buf[30] = { '\0' };
186   internal::itoa_r(static_cast<intptr_t>(value), 10, 1, buf);
187   handler->HandleOutput(buf);
188 }
189 #endif  // defined(HAVE_DLADDR) || defined(USE_SYMBOLIZE)
190 
191 #if defined(USE_SYMBOLIZE)
OutputFrameId(size_t frame_id,BacktraceOutputHandler * handler)192 void OutputFrameId(size_t frame_id, BacktraceOutputHandler* handler) {
193   handler->HandleOutput("#");
194   OutputValue(frame_id, handler);
195 }
196 #endif  // defined(USE_SYMBOLIZE)
197 
ProcessBacktrace(span<const void * const> traces,cstring_view prefix_string,BacktraceOutputHandler * handler)198 void ProcessBacktrace(span<const void* const> traces,
199                       cstring_view prefix_string,
200                       BacktraceOutputHandler* handler) {
201   // NOTE: This code MUST be async-signal safe (it's used by in-process
202   // stack dumping signal handler). NO malloc or stdio is allowed here.
203 
204   // Don't exceed kMaxTraces or GetDwarfCompileUnitOffsets can go OOB.
205   traces = traces.first(std::min(traces.size(), StackTrace::kMaxTraces));
206 
207 #if defined(USE_SYMBOLIZE)
208 #if BUILDFLAG(ENABLE_STACK_TRACE_LINE_NUMBERS)
209   std::array<uint64_t, StackTrace::kMaxTraces> cu_offsets = {};
210   GetDwarfCompileUnitOffsets(traces.data(), cu_offsets.data(), traces.size());
211 #endif
212 
213   for (size_t i = 0; i < traces.size(); ++i) {
214     if (!prefix_string.empty())
215       handler->HandleOutput(prefix_string.c_str());
216 
217     OutputFrameId(i, handler);
218     handler->HandleOutput(" ");
219     OutputPointer(traces[i], handler);
220     handler->HandleOutput(" ");
221 
222     std::array<char, 1024> buf = {};
223 
224     // Subtract by one as return address of function may be in the next function
225     // when a function is annotated as noreturn.
226     //
227     // SAFETY: The pointer here is not dereferenced, it is a program counter and
228     // it is used to look up an object file/function. It is treated as a
229     // `uintptr_t` inside Symbolize().
230     const void* address =
231         UNSAFE_BUFFERS(static_cast<const char*>(traces[i]) - 1);
232     if (google::Symbolize(const_cast<void*>(address), buf.data(), buf.size())) {
233       handler->HandleOutput(buf.data());
234 #if BUILDFLAG(ENABLE_STACK_TRACE_LINE_NUMBERS)
235       // Only output the source line number if the offset was found. Otherwise,
236       // it takes far too long in debug mode when there are lots of symbols.
237       if (GetDwarfSourceLineNumber(address, cu_offsets[i], buf.data(),
238                                    buf.size())) {
239         handler->HandleOutput(" [");
240         handler->HandleOutput(buf.data());
241         handler->HandleOutput("]");
242       }
243 #endif
244     } else {
245       handler->HandleOutput("<unknown>");
246     }
247 
248     handler->HandleOutput("\n");
249   }
250 #else
251   bool printed = false;
252 
253   // Below part is async-signal unsafe (uses malloc), so execute it only
254   // when we are not executing the signal handler.
255   if (in_signal_handler == 0 &&
256       IsValueInRangeForNumericType<int>(traces.size())) {
257 #if defined(HAVE_DLADDR)
258     Dl_info dl_info;
259     for (size_t i = 0; i < traces.size(); ++i) {
260       if (!prefix_string.empty()) {
261         handler->HandleOutput(prefix_string.c_str());
262       }
263 
264       OutputValue(i, handler);
265       handler->HandleOutput(" ");
266 
267       const bool dl_info_found = dladdr(traces[i], &dl_info) != 0;
268       if (dl_info_found) {
269         // SAFETY: dl_info::dli_fname is a NUL-terminated cstring.
270         auto dli_fname = UNSAFE_BUFFERS(base::cstring_view(dl_info.dli_fname));
271         if (size_t last_sep = dli_fname.rfind('/');
272             last_sep != base::cstring_view::npos) {
273           dli_fname.remove_prefix(last_sep + 1u);
274         }
275         handler->HandleOutput(dli_fname.c_str());
276       } else {
277         handler->HandleOutput("???");
278       }
279       handler->HandleOutput(" ");
280       OutputPointer(traces[i], handler);
281 
282       handler->HandleOutput("\n");
283     }
284     printed = true;
285 #else   // defined(HAVE_DLADDR)
286     auto trace_symbols =
287         // SAFETY: backtrace_symbols returns an allocated array of the same size
288         // as the input array, which is traces.size().
289         UNSAFE_BUFFERS(base::HeapArray<char*, FreeDeleter>::FromOwningPointer(
290             backtrace_symbols(const_cast<void* const*>(traces.data()),
291                               static_cast<int>(traces.size())),
292             traces.size()));
293     if (!trace_symbols.empty()) {
294       for (char* s : trace_symbols) {
295         auto trace_symbol = std::string(s);
296         DemangleSymbols(&trace_symbol);
297         if (!prefix_string.empty())
298           handler->HandleOutput(prefix_string.c_str());
299         handler->HandleOutput(trace_symbol.c_str());
300         handler->HandleOutput("\n");
301       }
302 
303       printed = true;
304     }
305 #endif  // defined(HAVE_DLADDR)
306   }
307 
308   if (!printed) {
309     for (const void* const trace : traces) {
310       handler->HandleOutput(" [");
311       OutputPointer(trace, handler);
312       handler->HandleOutput("]\n");
313     }
314   }
315 #endif  // defined(USE_SYMBOLIZE)
316 }
317 #endif  // defined(HAVE_BACKTRACE)
318 
PrintToStderr(const char * output)319 void PrintToStderr(const char* output) {
320   // NOTE: This code MUST be async-signal safe (it's used by in-process
321   // stack dumping signal handler). NO malloc or stdio is allowed here.
322   std::ignore = HANDLE_EINTR(write(STDERR_FILENO, output, strlen(output)));
323 }
324 
325 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
AlarmSignalHandler(int signal,siginfo_t * info,void * void_context)326 void AlarmSignalHandler(int signal, siginfo_t* info, void* void_context) {
327   // We have seen rare cases on AMD linux where the default signal handler
328   // either does not run or a thread (Probably an AMD driver thread) prevents
329   // the termination of the gpu process. We catch this case when the alarm fires
330   // and then call exit_group() to kill all threads of the process. This has
331   // resolved the zombie gpu process issues we have seen on our context lost
332   // test.
333   // Note that many different calls were tried to kill the process when it is in
334   // this state. Only 'exit_group' was found to cause termination and it is
335   // speculated that only this works because only this exit kills all threads in
336   // the process (not simply the current thread).
337   // See: http://crbug.com/1396451.
338   PrintToStderr(
339       "Warning: Default signal handler failed to terminate process.\n");
340   PrintToStderr("Calling exit_group() directly to prevent timeout.\n");
341   // See: https://man7.org/linux/man-pages/man2/exit_group.2.html
342   syscall(SYS_exit_group, EXIT_FAILURE);
343 }
344 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) ||
345         // BUILDFLAG(IS_CHROMEOS)
346 
StackDumpSignalHandler(int signal,siginfo_t * info,void * void_context)347 void StackDumpSignalHandler(int signal, siginfo_t* info, void* void_context) {
348   // NOTE: This code MUST be async-signal safe.
349   // NO malloc or stdio is allowed here.
350 
351 #if !BUILDFLAG(IS_NACL)
352   // Give a registered callback a chance to recover from this signal
353   //
354   // V8 uses guard regions to guarantee memory safety in WebAssembly. This means
355   // some signals might be expected if they originate from Wasm code while
356   // accessing the guard region. We give V8 the chance to handle and recover
357   // from these signals first.
358   if (try_handle_signal != nullptr &&
359       try_handle_signal(signal, info, void_context)) {
360     // The first chance handler took care of this. The SA_RESETHAND flag
361     // replaced this signal handler upon entry, but we want to stay
362     // installed. Thus, we reinstall ourselves before returning.
363     struct sigaction action;
364     memset(&action, 0, sizeof(action));
365     action.sa_flags = static_cast<int>(SA_RESETHAND | SA_SIGINFO);
366     action.sa_sigaction = &StackDumpSignalHandler;
367     sigemptyset(&action.sa_mask);
368 
369     sigaction(signal, &action, nullptr);
370     return;
371   }
372 #endif
373 
374 // Do not take the "in signal handler" code path on Mac in a DCHECK-enabled
375 // build, as this prevents seeing a useful (symbolized) stack trace on a crash
376 // or DCHECK() failure. While it may not be fully safe to run the stack symbol
377 // printing code, in practice it's better to provide meaningful stack traces -
378 // and the risk is low given we're likely crashing already.
379 #if !BUILDFLAG(IS_APPLE) || !DCHECK_IS_ON()
380   // Record the fact that we are in the signal handler now, so that the rest
381   // of StackTrace can behave in an async-signal-safe manner.
382   in_signal_handler = 1;
383 #endif
384 
385   if (BeingDebugged())
386     BreakDebugger();
387 
388   PrintToStderr("Received signal ");
389   char buf[1024] = { 0 };
390   internal::itoa_r(signal, 10, 0, buf);
391   PrintToStderr(buf);
392   if (signal == SIGBUS) {
393     if (info->si_code == BUS_ADRALN)
394       PrintToStderr(" BUS_ADRALN ");
395     else if (info->si_code == BUS_ADRERR)
396       PrintToStderr(" BUS_ADRERR ");
397     else if (info->si_code == BUS_OBJERR)
398       PrintToStderr(" BUS_OBJERR ");
399     else
400       PrintToStderr(" <unknown> ");
401   } else if (signal == SIGFPE) {
402     if (info->si_code == FPE_FLTDIV)
403       PrintToStderr(" FPE_FLTDIV ");
404     else if (info->si_code == FPE_FLTINV)
405       PrintToStderr(" FPE_FLTINV ");
406     else if (info->si_code == FPE_FLTOVF)
407       PrintToStderr(" FPE_FLTOVF ");
408     else if (info->si_code == FPE_FLTRES)
409       PrintToStderr(" FPE_FLTRES ");
410     else if (info->si_code == FPE_FLTSUB)
411       PrintToStderr(" FPE_FLTSUB ");
412     else if (info->si_code == FPE_FLTUND)
413       PrintToStderr(" FPE_FLTUND ");
414     else if (info->si_code == FPE_INTDIV)
415       PrintToStderr(" FPE_INTDIV ");
416     else if (info->si_code == FPE_INTOVF)
417       PrintToStderr(" FPE_INTOVF ");
418     else
419       PrintToStderr(" <unknown> ");
420   } else if (signal == SIGILL) {
421     if (info->si_code == ILL_BADSTK)
422       PrintToStderr(" ILL_BADSTK ");
423     else if (info->si_code == ILL_COPROC)
424       PrintToStderr(" ILL_COPROC ");
425     else if (info->si_code == ILL_ILLOPN)
426       PrintToStderr(" ILL_ILLOPN ");
427     else if (info->si_code == ILL_ILLADR)
428       PrintToStderr(" ILL_ILLADR ");
429     else if (info->si_code == ILL_ILLTRP)
430       PrintToStderr(" ILL_ILLTRP ");
431     else if (info->si_code == ILL_PRVOPC)
432       PrintToStderr(" ILL_PRVOPC ");
433     else if (info->si_code == ILL_PRVREG)
434       PrintToStderr(" ILL_PRVREG ");
435     else
436       PrintToStderr(" <unknown> ");
437   } else if (signal == SIGSEGV) {
438     if (info->si_code == SEGV_MAPERR)
439       PrintToStderr(" SEGV_MAPERR ");
440     else if (info->si_code == SEGV_ACCERR)
441       PrintToStderr(" SEGV_ACCERR ");
442 #if defined(ARCH_CPU_X86_64) && \
443     (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS))
444     else if (info->si_code == SI_KERNEL)
445       PrintToStderr(" SI_KERNEL");
446 #endif
447     else
448       PrintToStderr(" <unknown> ");
449   }
450   if (signal == SIGBUS || signal == SIGFPE ||
451       signal == SIGILL || signal == SIGSEGV) {
452     internal::itoa_r(reinterpret_cast<intptr_t>(info->si_addr), 16, 12, buf);
453     PrintToStderr(buf);
454   }
455   PrintToStderr("\n");
456 
457 #if BUILDFLAG(CFI_ENFORCEMENT_TRAP)
458   if (signal == SIGILL && info->si_code == ILL_ILLOPN) {
459     PrintToStderr(
460         "CFI: Most likely a control flow integrity violation; for more "
461         "information see:\n");
462     PrintToStderr(
463         "https://www.chromium.org/developers/testing/control-flow-integrity\n");
464   }
465 #endif  // BUILDFLAG(CFI_ENFORCEMENT_TRAP)
466 
467 #if defined(ARCH_CPU_X86_64) && \
468     (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS))
469   if (signal == SIGSEGV && info->si_code == SI_KERNEL) {
470     PrintToStderr(
471         " Possibly a General Protection Fault, can be due to a non-canonical "
472         "address dereference. See \"Intel 64 and IA-32 Architectures Software "
473         "Developer’s Manual\", Volume 1, Section 3.3.7.1.\n");
474   }
475 #endif
476 
477   debug::StackTrace().Print();
478 
479 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
480 #if ARCH_CPU_X86_FAMILY
481   ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context);
482   auto gregs = base::span(context->uc_mcontext.gregs);
483 
484   struct Register {
485     const char* label;
486     greg_t value;
487   };
488   const auto registers = std::to_array<Register>({
489 #if ARCH_CPU_32_BITS
490       {"  gs: ", gregs[REG_GS]},     {"  fs: ", gregs[REG_FS]},
491       {"  es: ", gregs[REG_ES]},     {"  ds: ", gregs[REG_DS]},
492       {" edi: ", gregs[REG_EDI]},    {" esi: ", gregs[REG_ESI]},
493       {" ebp: ", gregs[REG_EBP]},    {" esp: ", gregs[REG_ESP]},
494       {" ebx: ", gregs[REG_EBX]},    {" edx: ", gregs[REG_EDX]},
495       {" ecx: ", gregs[REG_ECX]},    {" eax: ", gregs[REG_EAX]},
496       {" trp: ", gregs[REG_TRAPNO]}, {" err: ", gregs[REG_ERR]},
497       {"  ip: ", gregs[REG_EIP]},    {"  cs: ", gregs[REG_CS]},
498       {" efl: ", gregs[REG_EFL]},    {" usp: ", gregs[REG_UESP]},
499       {"  ss: ", gregs[REG_SS]},
500 #elif ARCH_CPU_64_BITS
501       {"  r8: ", gregs[REG_R8]},     {"  r9: ", gregs[REG_R9]},
502       {" r10: ", gregs[REG_R10]},    {" r11: ", gregs[REG_R11]},
503       {" r12: ", gregs[REG_R12]},    {" r13: ", gregs[REG_R13]},
504       {" r14: ", gregs[REG_R14]},    {" r15: ", gregs[REG_R15]},
505       {"  di: ", gregs[REG_RDI]},    {"  si: ", gregs[REG_RSI]},
506       {"  bp: ", gregs[REG_RBP]},    {"  bx: ", gregs[REG_RBX]},
507       {"  dx: ", gregs[REG_RDX]},    {"  ax: ", gregs[REG_RAX]},
508       {"  cx: ", gregs[REG_RCX]},    {"  sp: ", gregs[REG_RSP]},
509       {"  ip: ", gregs[REG_RIP]},    {" efl: ", gregs[REG_EFL]},
510       {" cgf: ", gregs[REG_CSGSFS]}, {" erf: ", gregs[REG_ERR]},
511       {" trp: ", gregs[REG_TRAPNO]}, {" msk: ", gregs[REG_OLDMASK]},
512       {" cr2: ", gregs[REG_CR2]},
513 #endif  // ARCH_CPU_32_BITS
514   });
515 
516 #if ARCH_CPU_32_BITS
517   const int kRegisterPadding = 8;
518 #elif ARCH_CPU_64_BITS
519   const int kRegisterPadding = 16;
520 #endif
521 
522   for (size_t i = 0; i < std::size(registers); i++) {
523     PrintToStderr(registers[i].label);
524     internal::itoa_r(registers[i].value, 16, kRegisterPadding, buf);
525     PrintToStderr(buf);
526 
527     if ((i + 1) % 4 == 0)
528       PrintToStderr("\n");
529   }
530   PrintToStderr("\n");
531 #endif  // ARCH_CPU_X86_FAMILY
532 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
533 
534   PrintToStderr("[end of stack trace]\n");
535 
536   if (::signal(signal, SIG_DFL) == SIG_ERR) {
537     _exit(EXIT_FAILURE);
538   }
539 
540 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
541   // Set an alarm to trigger in case the default handler does not terminate
542   // the process. See 'AlarmSignalHandler' for more details.
543   struct sigaction action;
544   memset(&action, 0, sizeof(action));
545   action.sa_flags = static_cast<int>(SA_RESETHAND);
546   action.sa_sigaction = &AlarmSignalHandler;
547   sigemptyset(&action.sa_mask);
548   sigaction(SIGALRM, &action, nullptr);
549   // 'alarm' function is signal handler safe.
550   // https://man7.org/linux/man-pages/man7/signal-safety.7.html
551   // This delay is set to be long enough for the real signal handler to fire but
552   // shorter than chrome's process watchdog timer.
553   constexpr unsigned int kAlarmSignalDelaySeconds = 5;
554   alarm(kAlarmSignalDelaySeconds);
555 
556   // The following is mostly from
557   // third_party/crashpad/crashpad/util/posix/signals.cc as re-raising signals
558   // is complicated.
559 
560   // If we can raise a signal with siginfo on this platform, do so. This ensures
561   // that we preserve the siginfo information for asynchronous signals (i.e.
562   // signals that do not re-raise autonomously), such as signals delivered via
563   // kill() and asynchronous hardware faults such as SEGV_MTEAERR, which would
564   // otherwise be lost when re-raising the signal via raise().
565   long retval = syscall(SYS_rt_tgsigqueueinfo, getpid(), syscall(SYS_gettid),
566                         info->si_signo, info);
567   if (retval == 0) {
568     return;
569   }
570 
571   // Kernels without commit 66dd34ad31e5 ("signal: allow to send any siginfo to
572   // itself"), which was first released in kernel version 3.9, did not permit a
573   // process to send arbitrary signals to itself, and will reject the
574   // rt_tgsigqueueinfo syscall with EPERM. If that happens, follow the non-Linux
575   // code path. Any other errno is unexpected and will cause us to exit.
576   if (errno != EPERM) {
577     _exit(EXIT_FAILURE);
578   }
579 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) ||
580         // BUILDFLAG(IS_CHROMEOS)
581 
582   // Explicitly re-raise the signal even if it might have re-raised itself on
583   // return. Because signal handlers normally execute with their signal blocked,
584   // this raise() cannot immediately deliver the signal. Delivery is deferred
585   // until the signal handler returns and the signal becomes unblocked. The
586   // re-raised signal will appear with the same context as where it was
587   // initially triggered.
588   if (raise(signal) != 0) {
589     _exit(EXIT_FAILURE);
590   }
591 }
592 
593 class PrintBacktraceOutputHandler : public BacktraceOutputHandler {
594  public:
595   PrintBacktraceOutputHandler() = default;
596 
597   PrintBacktraceOutputHandler(const PrintBacktraceOutputHandler&) = delete;
598   PrintBacktraceOutputHandler& operator=(const PrintBacktraceOutputHandler&) =
599       delete;
600 
HandleOutput(const char * output)601   void HandleOutput(const char* output) override {
602     // NOTE: This code MUST be async-signal safe (it's used by in-process
603     // stack dumping signal handler). NO malloc or stdio is allowed here.
604     PrintToStderr(output);
605   }
606 };
607 
608 class StreamBacktraceOutputHandler : public BacktraceOutputHandler {
609  public:
StreamBacktraceOutputHandler(std::ostream * os)610   explicit StreamBacktraceOutputHandler(std::ostream* os) : os_(os) {
611   }
612 
613   StreamBacktraceOutputHandler(const StreamBacktraceOutputHandler&) = delete;
614   StreamBacktraceOutputHandler& operator=(const StreamBacktraceOutputHandler&) =
615       delete;
616 
HandleOutput(const char * output)617   void HandleOutput(const char* output) override { (*os_) << output; }
618 
619  private:
620   raw_ptr<std::ostream> os_;
621 };
622 
WarmUpBacktrace()623 void WarmUpBacktrace() {
624   // Warm up stack trace infrastructure. It turns out that on the first
625   // call glibc initializes some internal data structures using pthread_once,
626   // and even backtrace() can call malloc(), leading to hangs.
627   //
628   // Example stack trace snippet (with tcmalloc):
629   //
630   // #8  0x0000000000a173b5 in tc_malloc
631   //             at ./third_party/tcmalloc/chromium/src/debugallocation.cc:1161
632   // #9  0x00007ffff7de7900 in _dl_map_object_deps at dl-deps.c:517
633   // #10 0x00007ffff7ded8a9 in dl_open_worker at dl-open.c:262
634   // #11 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
635   // #12 0x00007ffff7ded31a in _dl_open (file=0x7ffff625e298 "libgcc_s.so.1")
636   //             at dl-open.c:639
637   // #13 0x00007ffff6215602 in do_dlopen at dl-libc.c:89
638   // #14 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
639   // #15 0x00007ffff62156c4 in dlerror_run at dl-libc.c:48
640   // #16 __GI___libc_dlopen_mode at dl-libc.c:165
641   // #17 0x00007ffff61ef8f5 in init
642   //             at ../sysdeps/x86_64/../ia64/backtrace.c:53
643   // #18 0x00007ffff6aad400 in pthread_once
644   //             at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S:104
645   // #19 0x00007ffff61efa14 in __GI___backtrace
646   //             at ../sysdeps/x86_64/../ia64/backtrace.c:104
647   // #20 0x0000000000752a54 in base::debug::StackTrace::StackTrace
648   //             at base/debug/stack_trace_posix.cc:175
649   // #21 0x00000000007a4ae5 in
650   //             base::(anonymous namespace)::StackDumpSignalHandler
651   //             at base/process_util_posix.cc:172
652   // #22 <signal handler called>
653   StackTrace stack_trace;
654 }
655 
656 #if defined(USE_SYMBOLIZE)
657 
658 // class SandboxSymbolizeHelper.
659 //
660 // The purpose of this class is to prepare and install a "file open" callback
661 // needed by the stack trace symbolization code
662 // (base/third_party/symbolize/symbolize.h) so that it can function properly
663 // in a sandboxed process.  The caveat is that this class must be instantiated
664 // before the sandboxing is enabled so that it can get the chance to open all
665 // the object files that are loaded in the virtual address space of the current
666 // process.
667 class SandboxSymbolizeHelper {
668  public:
669   // Returns the singleton instance.
GetInstance()670   static SandboxSymbolizeHelper* GetInstance() {
671     return Singleton<SandboxSymbolizeHelper,
672                      LeakySingletonTraits<SandboxSymbolizeHelper>>::get();
673   }
674 
675   SandboxSymbolizeHelper(const SandboxSymbolizeHelper&) = delete;
676   SandboxSymbolizeHelper& operator=(const SandboxSymbolizeHelper&) = delete;
677 
678  private:
679   friend struct DefaultSingletonTraits<SandboxSymbolizeHelper>;
680 
SandboxSymbolizeHelper()681   SandboxSymbolizeHelper()
682       : is_initialized_(false) {
683     Init();
684   }
685 
~SandboxSymbolizeHelper()686   ~SandboxSymbolizeHelper() {
687     UnregisterCallback();
688     CloseObjectFiles();
689   }
690 
691   // Returns a O_RDONLY file descriptor for |file_path| if it was opened
692   // successfully during the initialization.  The file is repositioned at
693   // offset 0.
694   // IMPORTANT: This function must be async-signal-safe because it can be
695   // called from a signal handler (symbolizing stack frames for a crash).
GetFileDescriptor(const char * file_path)696   int GetFileDescriptor(const char* file_path) {
697     int fd = -1;
698 
699 #if !defined(OFFICIAL_BUILD) || !defined(NO_UNWIND_TABLES)
700     if (file_path) {
701       // The assumption here is that iterating over std::map<std::string,
702       // base::ScopedFD> does not allocate dynamic memory, hence it is
703       // async-signal-safe.
704       for (const auto& filepath_fd : modules_) {
705         if (strcmp(filepath_fd.first.c_str(), file_path) == 0) {
706           // POSIX.1-2004 requires an implementation to guarantee that dup()
707           // is async-signal-safe.
708           fd = HANDLE_EINTR(dup(filepath_fd.second.get()));
709           break;
710         }
711       }
712       // POSIX.1-2004 requires an implementation to guarantee that lseek()
713       // is async-signal-safe.
714       if (fd >= 0 && lseek(fd, 0, SEEK_SET) < 0) {
715         // Failed to seek.
716         fd = -1;
717       }
718     }
719 #endif  // !defined(OFFICIAL_BUILD) || !defined(NO_UNWIND_TABLES)
720 
721     return fd;
722   }
723 
724   // Searches for the object file (from /proc/self/maps) that contains
725   // the specified pc.  If found, sets |start_address| to the start address
726   // of where this object file is mapped in memory, sets the module base
727   // address into |base_address|, copies the object file name into
728   // |out_file_name|, and attempts to open the object file.  If the object
729   // file is opened successfully, returns the file descriptor.  Otherwise,
730   // returns -1.
731   // IMPORTANT: This function must be async-signal-safe because it can be
732   // called from a signal handler (symbolizing stack frames for a crash).
OpenObjectFileContainingPc(uint64_t pc,uint64_t & start_address,uint64_t & base_address,char * file_path_ptr,size_t file_path_size)733   static int OpenObjectFileContainingPc(uint64_t pc,
734                                         uint64_t& start_address,
735                                         uint64_t& base_address,
736                                         char* file_path_ptr,
737                                         size_t file_path_size) {
738     auto file_path =
739         // SAFETY: This function is given as a function pointer to
740         // google::InstallSymbolizeOpenObjectFileCallback. It provides
741         // `file_path_size` as the size of the string in `file_path_ptr`,
742         // including a NUL terminator. Via code inspection we can see that
743         // `file_path_ptr` can be null, in which case `file_path_size` is zero.
744         UNSAFE_BUFFERS(base::span(file_path_ptr, file_path_size));
745 
746     // This method can only be called after the singleton is instantiated.
747     // This is ensured by the following facts:
748     // * This is the only static method in this class, it is private, and
749     //   the class has no friends (except for the DefaultSingletonTraits).
750     //   The compiler guarantees that it can only be called after the
751     //   singleton is instantiated.
752     // * This method is used as a callback for the stack tracing code and
753     //   the callback registration is done in the constructor, so logically
754     //   it cannot be called before the singleton is created.
755     SandboxSymbolizeHelper* instance = GetInstance();
756 
757     // Cannot use STL iterators here, since debug iterators use locks.
758     // NOLINTNEXTLINE(modernize-loop-convert)
759     for (size_t i = 0; i < instance->regions_.size(); ++i) {
760       const MappedMemoryRegion& region = instance->regions_[i];
761       // We overwrite the file_path with the if `pc` is within a
762       // MemoryMappedRegion.
763       if (region.start <= pc && pc < region.end) {
764         start_address = region.start;
765         base_address = region.base;
766         if (!file_path.empty()) {
767           strlcpy(file_path, region.path);
768         }
769         return instance->GetFileDescriptor(region.path.c_str());
770       }
771     }
772     return -1;
773   }
774 
775   // This class is copied from
776   // third_party/crashpad/crashpad/util/linux/scoped_pr_set_dumpable.h.
777   // It aims at ensuring the process is dumpable before opening /proc/self/mem.
778   // If the process is already dumpable, this class doesn't do anything.
779   class ScopedPrSetDumpable {
780    public:
781     // Uses `PR_SET_DUMPABLE` to make the current process dumpable.
782     //
783     // Restores the dumpable flag to its original value on destruction. If the
784     // original value couldn't be determined, the destructor attempts to
785     // restore the flag to 0 (non-dumpable).
ScopedPrSetDumpable()786     explicit ScopedPrSetDumpable() {
787       int result = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
788       was_dumpable_ = result > 0;
789 
790       if (!was_dumpable_) {
791         std::ignore = prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
792       }
793     }
794 
795     ScopedPrSetDumpable(const ScopedPrSetDumpable&) = delete;
796     ScopedPrSetDumpable& operator=(const ScopedPrSetDumpable&) = delete;
797 
~ScopedPrSetDumpable()798     ~ScopedPrSetDumpable() {
799       if (!was_dumpable_) {
800         std::ignore = prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
801       }
802     }
803 
804    private:
805     bool was_dumpable_;
806   };
807 
808   // Set the base address for each memory region by reading ELF headers in
809   // process memory.
SetBaseAddressesForMemoryRegions()810   void SetBaseAddressesForMemoryRegions() {
811     base::ScopedFD mem_fd;
812     {
813       ScopedPrSetDumpable s;
814       mem_fd = base::ScopedFD(
815           HANDLE_EINTR(open("/proc/self/mem", O_RDONLY | O_CLOEXEC)));
816       if (!mem_fd.is_valid()) {
817         return;
818       }
819     }
820 
821     auto safe_memcpy = [&mem_fd](void* dst, uintptr_t src, size_t size) {
822       return HANDLE_EINTR(pread(mem_fd.get(), dst, size,
823                                 static_cast<off_t>(src))) == ssize_t(size);
824     };
825 
826     uintptr_t cur_base = 0;
827     for (auto& r : regions_) {
828       ElfW(Ehdr) ehdr;
829       static_assert(SELFMAG <= sizeof(ElfW(Ehdr)), "SELFMAG too large");
830       if ((r.permissions & MappedMemoryRegion::READ) &&
831           safe_memcpy(&ehdr, r.start, sizeof(ElfW(Ehdr))) &&
832           memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0) {
833         switch (ehdr.e_type) {
834           case ET_EXEC:
835             cur_base = 0;
836             break;
837           case ET_DYN:
838             // Find the segment containing file offset 0. This will correspond
839             // to the ELF header that we just read. Normally this will have
840             // virtual address 0, but this is not guaranteed. We must subtract
841             // the virtual address from the address where the ELF header was
842             // mapped to get the base address.
843             //
844             // If we fail to find a segment for file offset 0, use the address
845             // of the ELF header as the base address.
846             cur_base = r.start;
847             for (unsigned i = 0; i != ehdr.e_phnum; ++i) {
848               ElfW(Phdr) phdr;
849               if (safe_memcpy(&phdr, r.start + ehdr.e_phoff + i * sizeof(phdr),
850                               sizeof(phdr)) &&
851                   phdr.p_type == PT_LOAD && phdr.p_offset == 0) {
852                 cur_base = r.start - phdr.p_vaddr;
853                 break;
854               }
855             }
856             break;
857           default:
858             // ET_REL or ET_CORE. These aren't directly executable, so they
859             // don't affect the base address.
860             break;
861         }
862       }
863 
864       r.base = cur_base;
865     }
866   }
867 
868   // Parses /proc/self/maps in order to compile a list of all object file names
869   // for the modules that are loaded in the current process.
870   // Returns true on success.
CacheMemoryRegions()871   bool CacheMemoryRegions() {
872     // Reads /proc/self/maps.
873     std::string contents;
874     if (!ReadProcMaps(&contents)) {
875       LOG(ERROR) << "Failed to read /proc/self/maps";
876       return false;
877     }
878 
879     // Parses /proc/self/maps.
880     if (!ParseProcMaps(contents, &regions_)) {
881       LOG(ERROR) << "Failed to parse the contents of /proc/self/maps";
882       return false;
883     }
884 
885     SetBaseAddressesForMemoryRegions();
886 
887     is_initialized_ = true;
888     return true;
889   }
890 
891   // Opens all object files and caches their file descriptors.
OpenSymbolFiles()892   void OpenSymbolFiles() {
893     // Pre-opening and caching the file descriptors of all loaded modules is
894     // not safe for production builds.  Hence it is only done in non-official
895     // builds.  For more details, take a look at: http://crbug.com/341966.
896 #if !defined(OFFICIAL_BUILD) || !defined(NO_UNWIND_TABLES)
897     // Open the object files for all read-only executable regions and cache
898     // their file descriptors.
899     std::vector<MappedMemoryRegion>::const_iterator it;
900     for (it = regions_.begin(); it != regions_.end(); ++it) {
901       const MappedMemoryRegion& region = *it;
902       // Only interesed in read-only executable regions.
903       if ((region.permissions & MappedMemoryRegion::READ) ==
904               MappedMemoryRegion::READ &&
905           (region.permissions & MappedMemoryRegion::WRITE) == 0 &&
906           (region.permissions & MappedMemoryRegion::EXECUTE) ==
907               MappedMemoryRegion::EXECUTE) {
908         if (region.path.empty()) {
909           // Skip regions with empty file names.
910           continue;
911         }
912         if (region.path[0] == '[') {
913           // Skip pseudo-paths, like [stack], [vdso], [heap], etc ...
914           continue;
915         }
916         if (base::EndsWith(region.path, " (deleted)",
917                            base::CompareCase::SENSITIVE)) {
918           // Skip deleted files.
919           continue;
920         }
921         // Avoid duplicates.
922         if (modules_.find(region.path) == modules_.end()) {
923           int fd = open(region.path.c_str(), O_RDONLY | O_CLOEXEC);
924           if (fd >= 0) {
925             modules_.emplace(region.path, base::ScopedFD(fd));
926           } else {
927             PLOG(WARNING) << "Failed to open file: " << region.path;
928           }
929         }
930       }
931     }
932 #endif  // !defined(OFFICIAL_BUILD) || !defined(NO_UNWIND_TABLES)
933   }
934 
935   // Initializes and installs the symbolization callback.
Init()936   void Init() {
937     if (CacheMemoryRegions()) {
938       OpenSymbolFiles();
939       google::InstallSymbolizeOpenObjectFileCallback(
940           &OpenObjectFileContainingPc);
941     }
942   }
943 
944   // Unregister symbolization callback.
UnregisterCallback()945   void UnregisterCallback() {
946     if (is_initialized_) {
947       google::InstallSymbolizeOpenObjectFileCallback(nullptr);
948       is_initialized_ = false;
949     }
950   }
951 
952   // Closes all file descriptors owned by this instance.
CloseObjectFiles()953   void CloseObjectFiles() {
954 #if !defined(OFFICIAL_BUILD) || !defined(NO_UNWIND_TABLES)
955     modules_.clear();
956 #endif  // !defined(OFFICIAL_BUILD) || !defined(NO_UNWIND_TABLES)
957   }
958 
959   // Set to true upon successful initialization.
960   bool is_initialized_;
961 
962 #if !defined(OFFICIAL_BUILD) || !defined(NO_UNWIND_TABLES)
963   // Mapping from file name to file descriptor.  Includes file descriptors
964   // for all successfully opened object files and the file descriptor for
965   // /proc/self/maps.  This code is not safe for production builds.
966   std::map<std::string, base::ScopedFD> modules_;
967 #endif  // !defined(OFFICIAL_BUILD) || !defined(NO_UNWIND_TABLES)
968 
969   // Cache for the process memory regions.  Produced by parsing the contents
970   // of /proc/self/maps cache.
971   std::vector<MappedMemoryRegion> regions_;
972 };
973 #endif  // USE_SYMBOLIZE
974 
975 }  // namespace
976 
EnableInProcessStackDumping()977 bool EnableInProcessStackDumping() {
978 #if defined(USE_SYMBOLIZE)
979   SandboxSymbolizeHelper::GetInstance();
980 #endif  // USE_SYMBOLIZE
981 
982   // When running in an application, our code typically expects SIGPIPE
983   // to be ignored.  Therefore, when testing that same code, it should run
984   // with SIGPIPE ignored as well.
985   struct sigaction sigpipe_action;
986   memset(&sigpipe_action, 0, sizeof(sigpipe_action));
987   sigpipe_action.sa_handler = SIG_IGN;
988   sigemptyset(&sigpipe_action.sa_mask);
989   bool success = (sigaction(SIGPIPE, &sigpipe_action, nullptr) == 0);
990 
991   // Avoid hangs during backtrace initialization, see above.
992   WarmUpBacktrace();
993 
994   struct sigaction action;
995   memset(&action, 0, sizeof(action));
996   action.sa_flags = static_cast<int>(SA_RESETHAND | SA_SIGINFO);
997   action.sa_sigaction = &StackDumpSignalHandler;
998   sigemptyset(&action.sa_mask);
999 
1000   success &= (sigaction(SIGILL, &action, nullptr) == 0);
1001   success &= (sigaction(SIGABRT, &action, nullptr) == 0);
1002   success &= (sigaction(SIGFPE, &action, nullptr) == 0);
1003   success &= (sigaction(SIGBUS, &action, nullptr) == 0);
1004   success &= (sigaction(SIGSEGV, &action, nullptr) == 0);
1005 // On Linux, SIGSYS is reserved by the kernel for seccomp-bpf sandboxing.
1006 #if !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS)
1007   success &= (sigaction(SIGSYS, &action, nullptr) == 0);
1008 #endif  // !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS)
1009 
1010   return success;
1011 }
1012 
1013 #if !BUILDFLAG(IS_NACL)
SetStackDumpFirstChanceCallback(bool (* handler)(int,siginfo_t *,void *))1014 bool SetStackDumpFirstChanceCallback(bool (*handler)(int, siginfo_t*, void*)) {
1015   DCHECK(try_handle_signal == nullptr || handler == nullptr);
1016   try_handle_signal = handler;
1017 
1018 #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
1019     defined(THREAD_SANITIZER) || defined(LEAK_SANITIZER) ||    \
1020     defined(UNDEFINED_SANITIZER)
1021   struct sigaction installed_handler;
1022   CHECK_EQ(sigaction(SIGSEGV, NULL, &installed_handler), 0);
1023   // If the installed handler does not point to StackDumpSignalHandler, then
1024   // allow_user_segv_handler is 0.
1025   if (installed_handler.sa_sigaction != StackDumpSignalHandler) {
1026     LOG(WARNING)
1027         << "WARNING: sanitizers are preventing signal handler installation. "
1028         << "WebAssembly trap handlers are disabled.\n";
1029     return false;
1030   }
1031 #endif
1032   return true;
1033 }
1034 #endif
1035 
CollectStackTrace(span<const void * > trace)1036 size_t CollectStackTrace(span<const void*> trace) {
1037   // NOTE: This code MUST be async-signal safe (it's used by in-process
1038   // stack dumping signal handler). NO malloc or stdio is allowed here.
1039 
1040 #if defined(NO_UNWIND_TABLES) && BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
1041   // If we do not have unwind tables, then try tracing using frame pointers.
1042   return base::debug::TraceStackFramePointers(trace, 0);
1043 #elif defined(HAVE_BACKTRACE)
1044   // Though the backtrace API man page does not list any possible negative
1045   // return values, we take no chance.
1046   return base::saturated_cast<size_t>(
1047       backtrace(const_cast<void**>(trace.data()),
1048                 base::saturated_cast<int>(trace.size())));
1049 #else
1050   return 0;
1051 #endif
1052 }
1053 
1054 // static
PrintMessageWithPrefix(cstring_view prefix_string,cstring_view message)1055 void StackTrace::PrintMessageWithPrefix(cstring_view prefix_string,
1056                                         cstring_view message) {
1057   // NOTE: This code MUST be async-signal safe (it's used by in-process
1058   // stack dumping signal handler). NO malloc or stdio is allowed here.
1059   if (!prefix_string.empty()) {
1060     PrintToStderr(prefix_string.c_str());
1061   }
1062   PrintToStderr(message.c_str());
1063 }
1064 
PrintWithPrefixImpl(cstring_view prefix_string) const1065 void StackTrace::PrintWithPrefixImpl(cstring_view prefix_string) const {
1066 // NOTE: This code MUST be async-signal safe (it's used by in-process
1067 // stack dumping signal handler). NO malloc or stdio is allowed here.
1068 #if defined(HAVE_BACKTRACE)
1069   PrintBacktraceOutputHandler handler;
1070   ProcessBacktrace(addresses(), prefix_string, &handler);
1071 #endif
1072 }
1073 
1074 #if defined(HAVE_BACKTRACE)
OutputToStreamWithPrefixImpl(std::ostream * os,cstring_view prefix_string) const1075 void StackTrace::OutputToStreamWithPrefixImpl(
1076     std::ostream* os,
1077     cstring_view prefix_string) const {
1078   StreamBacktraceOutputHandler handler(os);
1079   ProcessBacktrace(addresses(), prefix_string, &handler);
1080 }
1081 #endif
1082 
1083 namespace internal {
1084 
1085 // NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
1086 // Modified to use bounds-checked containers.
itoa_r(intptr_t i,int base,size_t padding,base::span<char> buf)1087 void itoa_r(intptr_t i, int base, size_t padding, base::span<char> buf) {
1088   // Make sure we can write at least one NUL byte.
1089   if (buf.empty()) {
1090     return;
1091   }
1092 
1093   if (base < 2 || base > 16) {
1094     buf[0u] = '\000';
1095     return;
1096   }
1097 
1098   auto writer = base::SpanWriter(buf);
1099   size_t start = 0u;
1100 
1101   uintptr_t j = static_cast<uintptr_t>(i);
1102 
1103   // Handle negative numbers (only for base 10).
1104   if (i < 0 && base == 10) {
1105     // This does "j = -i" while avoiding integer overflow.
1106     j = static_cast<uintptr_t>(-(i + 1)) + 1;
1107 
1108     // Make sure we can write the '-' character.
1109     if (!writer.Write('-')) {
1110       buf[0u] = '\000';
1111       return;
1112     }
1113     start += 1u;  // The number starts after the sign.
1114   }
1115 
1116   // Loop until we have converted the entire number. Output at least one
1117   // character (i.e. '0').
1118   constexpr std::string_view digits = "0123456789abcdef";
1119   do {
1120     // Output the next digit.
1121     if (!writer.Write(digits[j % static_cast<uintptr_t>(base)])) {
1122       buf[0] = '\000';
1123       return;
1124     }
1125     j /= static_cast<uintptr_t>(base);
1126 
1127     if (padding > 0)
1128       padding--;
1129   } while (j > 0 || padding > 0);
1130 
1131   // Terminate the output with a NUL character.
1132   if (!writer.Write('\000')) {
1133     buf[0] = '\000';
1134     return;
1135   }
1136 
1137   // Conversion to ASCII actually resulted in the digits being in reverse order.
1138   // We can't easily generate them in forward order, as we can't tell the number
1139   // of characters needed until we are done converting. So, now, we reverse the
1140   // string (except for the possible "-" sign and the NUL terminator).
1141   std::ranges::reverse(buf.first(writer.num_written() - 1u).subspan(start));
1142 }
1143 
1144 }  // namespace internal
1145 
1146 }  // namespace base::debug
1147