17339ca27SMitch Phillips //===-- backtrace_linux_libc.cpp --------------------------------*- C++ -*-===//
27339ca27SMitch Phillips //
37339ca27SMitch Phillips // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47339ca27SMitch Phillips // See https://llvm.org/LICENSE.txt for license information.
57339ca27SMitch Phillips // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67339ca27SMitch Phillips //
77339ca27SMitch Phillips //===----------------------------------------------------------------------===//
87339ca27SMitch Phillips
97339ca27SMitch Phillips #include <assert.h>
107339ca27SMitch Phillips #include <execinfo.h>
117339ca27SMitch Phillips #include <stddef.h>
127339ca27SMitch Phillips #include <stdint.h>
137339ca27SMitch Phillips #include <stdlib.h>
147339ca27SMitch Phillips #include <string.h>
157339ca27SMitch Phillips
16*a8520f69SMitch Phillips #include "gwp_asan/definitions.h"
177339ca27SMitch Phillips #include "gwp_asan/optional/backtrace.h"
18*a8520f69SMitch Phillips #include "gwp_asan/optional/printf.h"
197339ca27SMitch Phillips #include "gwp_asan/options.h"
207339ca27SMitch Phillips
217339ca27SMitch Phillips namespace {
Backtrace(uintptr_t * TraceBuffer,size_t Size)22352d1b59SMitch Phillips size_t Backtrace(uintptr_t *TraceBuffer, size_t Size) {
237339ca27SMitch Phillips static_assert(sizeof(uintptr_t) == sizeof(void *), "uintptr_t is not void*");
247339ca27SMitch Phillips
25352d1b59SMitch Phillips return backtrace(reinterpret_cast<void **>(TraceBuffer), Size);
267339ca27SMitch Phillips }
277339ca27SMitch Phillips
284f029d1bSMitch Phillips // We don't need any custom handling for the Segv backtrace - the libc unwinder
294f029d1bSMitch Phillips // has no problems with unwinding through a signal handler. Force inlining here
304f029d1bSMitch Phillips // to avoid the additional frame.
SegvBacktrace(uintptr_t * TraceBuffer,size_t Size,void *)314f029d1bSMitch Phillips GWP_ASAN_ALWAYS_INLINE size_t SegvBacktrace(uintptr_t *TraceBuffer, size_t Size,
324f029d1bSMitch Phillips void * /*Context*/) {
334f029d1bSMitch Phillips return Backtrace(TraceBuffer, Size);
344f029d1bSMitch Phillips }
354f029d1bSMitch Phillips
PrintBacktrace(uintptr_t * Trace,size_t TraceLength,gwp_asan::Printf_t Printf)36352d1b59SMitch Phillips static void PrintBacktrace(uintptr_t *Trace, size_t TraceLength,
37*a8520f69SMitch Phillips gwp_asan::Printf_t Printf) {
38352d1b59SMitch Phillips if (TraceLength == 0) {
397339ca27SMitch Phillips Printf(" <not found (does your allocator support backtracing?)>\n\n");
407339ca27SMitch Phillips return;
417339ca27SMitch Phillips }
427339ca27SMitch Phillips
437339ca27SMitch Phillips char **BacktraceSymbols =
44352d1b59SMitch Phillips backtrace_symbols(reinterpret_cast<void **>(Trace), TraceLength);
457339ca27SMitch Phillips
46352d1b59SMitch Phillips for (size_t i = 0; i < TraceLength; ++i) {
477339ca27SMitch Phillips if (!BacktraceSymbols)
487339ca27SMitch Phillips Printf(" #%zu %p\n", i, Trace[i]);
497339ca27SMitch Phillips else
507339ca27SMitch Phillips Printf(" #%zu %s\n", i, BacktraceSymbols[i]);
517339ca27SMitch Phillips }
527339ca27SMitch Phillips
537339ca27SMitch Phillips Printf("\n");
547339ca27SMitch Phillips if (BacktraceSymbols)
557339ca27SMitch Phillips free(BacktraceSymbols);
567339ca27SMitch Phillips }
577339ca27SMitch Phillips } // anonymous namespace
587339ca27SMitch Phillips
597339ca27SMitch Phillips namespace gwp_asan {
60*a8520f69SMitch Phillips namespace backtrace {
614f029d1bSMitch Phillips
getBacktraceFunction()62*a8520f69SMitch Phillips options::Backtrace_t getBacktraceFunction() { return Backtrace; }
getPrintBacktraceFunction()63*a8520f69SMitch Phillips PrintBacktrace_t getPrintBacktraceFunction() { return PrintBacktrace; }
getSegvBacktraceFunction()644f029d1bSMitch Phillips SegvBacktrace_t getSegvBacktraceFunction() { return SegvBacktrace; }
65*a8520f69SMitch Phillips
66*a8520f69SMitch Phillips } // namespace backtrace
677339ca27SMitch Phillips } // namespace gwp_asan
68