10b57cec5SDimitry Andric //===-- backtrace_linux_libc.cpp --------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include <assert.h>
100b57cec5SDimitry Andric #include <execinfo.h>
110b57cec5SDimitry Andric #include <stddef.h>
120b57cec5SDimitry Andric #include <stdint.h>
130b57cec5SDimitry Andric #include <stdlib.h>
140b57cec5SDimitry Andric #include <string.h>
150b57cec5SDimitry Andric
16*e8d8bef9SDimitry Andric #include "gwp_asan/definitions.h"
170b57cec5SDimitry Andric #include "gwp_asan/optional/backtrace.h"
18*e8d8bef9SDimitry Andric #include "gwp_asan/optional/printf.h"
190b57cec5SDimitry Andric #include "gwp_asan/options.h"
200b57cec5SDimitry Andric
210b57cec5SDimitry Andric namespace {
Backtrace(uintptr_t * TraceBuffer,size_t Size)2268d75effSDimitry Andric size_t Backtrace(uintptr_t *TraceBuffer, size_t Size) {
230b57cec5SDimitry Andric static_assert(sizeof(uintptr_t) == sizeof(void *), "uintptr_t is not void*");
240b57cec5SDimitry Andric
2568d75effSDimitry Andric return backtrace(reinterpret_cast<void **>(TraceBuffer), Size);
260b57cec5SDimitry Andric }
270b57cec5SDimitry Andric
28*e8d8bef9SDimitry Andric // We don't need any custom handling for the Segv backtrace - the libc unwinder
29*e8d8bef9SDimitry Andric // has no problems with unwinding through a signal handler. Force inlining here
30*e8d8bef9SDimitry Andric // to avoid the additional frame.
SegvBacktrace(uintptr_t * TraceBuffer,size_t Size,void *)31*e8d8bef9SDimitry Andric GWP_ASAN_ALWAYS_INLINE size_t SegvBacktrace(uintptr_t *TraceBuffer, size_t Size,
32*e8d8bef9SDimitry Andric void * /*Context*/) {
33*e8d8bef9SDimitry Andric return Backtrace(TraceBuffer, Size);
34*e8d8bef9SDimitry Andric }
35*e8d8bef9SDimitry Andric
PrintBacktrace(uintptr_t * Trace,size_t TraceLength,gwp_asan::Printf_t Printf)3668d75effSDimitry Andric static void PrintBacktrace(uintptr_t *Trace, size_t TraceLength,
37*e8d8bef9SDimitry Andric gwp_asan::Printf_t Printf) {
3868d75effSDimitry Andric if (TraceLength == 0) {
390b57cec5SDimitry Andric Printf(" <not found (does your allocator support backtracing?)>\n\n");
400b57cec5SDimitry Andric return;
410b57cec5SDimitry Andric }
420b57cec5SDimitry Andric
430b57cec5SDimitry Andric char **BacktraceSymbols =
4468d75effSDimitry Andric backtrace_symbols(reinterpret_cast<void **>(Trace), TraceLength);
450b57cec5SDimitry Andric
4668d75effSDimitry Andric for (size_t i = 0; i < TraceLength; ++i) {
470b57cec5SDimitry Andric if (!BacktraceSymbols)
480b57cec5SDimitry Andric Printf(" #%zu %p\n", i, Trace[i]);
490b57cec5SDimitry Andric else
500b57cec5SDimitry Andric Printf(" #%zu %s\n", i, BacktraceSymbols[i]);
510b57cec5SDimitry Andric }
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric Printf("\n");
540b57cec5SDimitry Andric if (BacktraceSymbols)
550b57cec5SDimitry Andric free(BacktraceSymbols);
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric } // anonymous namespace
580b57cec5SDimitry Andric
590b57cec5SDimitry Andric namespace gwp_asan {
60*e8d8bef9SDimitry Andric namespace backtrace {
61*e8d8bef9SDimitry Andric
getBacktraceFunction()62*e8d8bef9SDimitry Andric options::Backtrace_t getBacktraceFunction() { return Backtrace; }
getPrintBacktraceFunction()63*e8d8bef9SDimitry Andric PrintBacktrace_t getPrintBacktraceFunction() { return PrintBacktrace; }
getSegvBacktraceFunction()64*e8d8bef9SDimitry Andric SegvBacktrace_t getSegvBacktraceFunction() { return SegvBacktrace; }
65*e8d8bef9SDimitry Andric
66*e8d8bef9SDimitry Andric } // namespace backtrace
670b57cec5SDimitry Andric } // namespace gwp_asan
68