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