xref: /openbsd-src/gnu/llvm/compiler-rt/lib/gwp_asan/optional/backtrace_linux_libc.cpp (revision d89ec533011f513df1010f142a111086a0785f09)
13cab2bb3Spatrick //===-- backtrace_linux_libc.cpp --------------------------------*- C++ -*-===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick 
93cab2bb3Spatrick #include <assert.h>
103cab2bb3Spatrick #include <execinfo.h>
113cab2bb3Spatrick #include <stddef.h>
123cab2bb3Spatrick #include <stdint.h>
133cab2bb3Spatrick #include <stdlib.h>
143cab2bb3Spatrick #include <string.h>
153cab2bb3Spatrick 
16*d89ec533Spatrick #include "gwp_asan/definitions.h"
173cab2bb3Spatrick #include "gwp_asan/optional/backtrace.h"
18*d89ec533Spatrick #include "gwp_asan/optional/printf.h"
193cab2bb3Spatrick #include "gwp_asan/options.h"
203cab2bb3Spatrick 
213cab2bb3Spatrick namespace {
Backtrace(uintptr_t * TraceBuffer,size_t Size)223cab2bb3Spatrick size_t Backtrace(uintptr_t *TraceBuffer, size_t Size) {
233cab2bb3Spatrick   static_assert(sizeof(uintptr_t) == sizeof(void *), "uintptr_t is not void*");
243cab2bb3Spatrick 
253cab2bb3Spatrick   return backtrace(reinterpret_cast<void **>(TraceBuffer), Size);
263cab2bb3Spatrick }
273cab2bb3Spatrick 
28*d89ec533Spatrick // We don't need any custom handling for the Segv backtrace - the libc unwinder
29*d89ec533Spatrick // has no problems with unwinding through a signal handler. Force inlining here
30*d89ec533Spatrick // to avoid the additional frame.
SegvBacktrace(uintptr_t * TraceBuffer,size_t Size,void *)31*d89ec533Spatrick GWP_ASAN_ALWAYS_INLINE size_t SegvBacktrace(uintptr_t *TraceBuffer, size_t Size,
32*d89ec533Spatrick                                             void * /*Context*/) {
33*d89ec533Spatrick   return Backtrace(TraceBuffer, Size);
34*d89ec533Spatrick }
35*d89ec533Spatrick 
PrintBacktrace(uintptr_t * Trace,size_t TraceLength,gwp_asan::Printf_t Printf)363cab2bb3Spatrick static void PrintBacktrace(uintptr_t *Trace, size_t TraceLength,
37*d89ec533Spatrick                            gwp_asan::Printf_t Printf) {
383cab2bb3Spatrick   if (TraceLength == 0) {
393cab2bb3Spatrick     Printf("  <not found (does your allocator support backtracing?)>\n\n");
403cab2bb3Spatrick     return;
413cab2bb3Spatrick   }
423cab2bb3Spatrick 
433cab2bb3Spatrick   char **BacktraceSymbols =
443cab2bb3Spatrick       backtrace_symbols(reinterpret_cast<void **>(Trace), TraceLength);
453cab2bb3Spatrick 
463cab2bb3Spatrick   for (size_t i = 0; i < TraceLength; ++i) {
473cab2bb3Spatrick     if (!BacktraceSymbols)
483cab2bb3Spatrick       Printf("  #%zu %p\n", i, Trace[i]);
493cab2bb3Spatrick     else
503cab2bb3Spatrick       Printf("  #%zu %s\n", i, BacktraceSymbols[i]);
513cab2bb3Spatrick   }
523cab2bb3Spatrick 
533cab2bb3Spatrick   Printf("\n");
543cab2bb3Spatrick   if (BacktraceSymbols)
553cab2bb3Spatrick     free(BacktraceSymbols);
563cab2bb3Spatrick }
573cab2bb3Spatrick } // anonymous namespace
583cab2bb3Spatrick 
593cab2bb3Spatrick namespace gwp_asan {
60*d89ec533Spatrick namespace backtrace {
61*d89ec533Spatrick 
getBacktraceFunction()62*d89ec533Spatrick options::Backtrace_t getBacktraceFunction() { return Backtrace; }
getPrintBacktraceFunction()63*d89ec533Spatrick PrintBacktrace_t getPrintBacktraceFunction() { return PrintBacktrace; }
getSegvBacktraceFunction()64*d89ec533Spatrick SegvBacktrace_t getSegvBacktraceFunction() { return SegvBacktrace; }
65*d89ec533Spatrick 
66*d89ec533Spatrick } // namespace backtrace
673cab2bb3Spatrick } // namespace gwp_asan
68