blob: d129f7caeb1659203305cac486ba3c5e6a295691 [file] [log] [blame]
Christopher Ferris11526e22021-10-14 22:44:47 +00001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <dlfcn.h>
30#include <execinfo.h>
31#include <inttypes.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <sys/mman.h>
36#include <unistd.h>
37#include <unwind.h>
38
39#include "private/ScopedFd.h"
40
41struct StackState {
42 void** frames;
43 int frame_count;
44 int cur_frame = 0;
45
46 StackState(void** frames, int frame_count) : frames(frames), frame_count(frame_count) {}
47};
48
49static _Unwind_Reason_Code TraceFunction(_Unwind_Context* context, void* arg) {
50 // The instruction pointer is pointing at the instruction after the return
51 // call on all architectures.
52 // Modify the pc to point at the real function.
53 uintptr_t ip = _Unwind_GetIP(context);
54 if (ip != 0) {
55#if defined(__arm__)
56 // If the ip is suspiciously low, do nothing to avoid a segfault trying
57 // to access this memory.
58 if (ip >= 4096) {
59 // Check bits [15:11] of the first halfword assuming the instruction
60 // is 32 bits long. If the bits are any of these values, then our
61 // assumption was correct:
62 // b11101
63 // b11110
64 // b11111
65 // Otherwise, this is a 16 bit instruction.
66 uint16_t value = (*reinterpret_cast<uint16_t*>(ip - 2)) >> 11;
67 if (value == 0x1f || value == 0x1e || value == 0x1d) {
68 ip -= 4;
69 } else {
70 ip -= 2;
71 }
72 }
73#elif defined(__aarch64__)
74 // All instructions are 4 bytes long, skip back one instruction.
75 ip -= 4;
76#elif defined(__i386__) || defined(__x86_64__)
77 // It's difficult to decode exactly where the previous instruction is,
78 // so subtract 1 to estimate where the instruction lives.
79 ip--;
80#endif
81 }
82
83 StackState* state = static_cast<StackState*>(arg);
84 state->frames[state->cur_frame++] = reinterpret_cast<void*>(ip);
85 return (state->cur_frame >= state->frame_count) ? _URC_END_OF_STACK : _URC_NO_REASON;
86}
87
88int backtrace(void** buffer, int size) {
89 if (size <= 0) {
90 return 0;
91 }
92
93 StackState state(buffer, size);
94 _Unwind_Backtrace(TraceFunction, &state);
95 return state.cur_frame;
96}
97
98char** backtrace_symbols(void* const* buffer, int size) {
99 if (size <= 0) {
100 return nullptr;
101 }
102 // Do this calculation first in case the user passes in a bad value.
103 size_t ptr_size;
104 if (__builtin_mul_overflow(sizeof(char*), size, &ptr_size)) {
105 return nullptr;
106 }
107
108 ScopedFd fd(memfd_create("backtrace_symbols_fd", MFD_CLOEXEC));
109 if (fd.get() == -1) {
110 return nullptr;
111 }
112 backtrace_symbols_fd(buffer, size, fd.get());
113
114 // Get the size of the file.
115 off_t file_size = lseek(fd.get(), 0, SEEK_END);
116 if (file_size <= 0) {
117 return nullptr;
118 }
119
120 // The interface for backtrace_symbols indicates that only the single
121 // returned pointer must be freed by the caller. Therefore, allocate a
122 // buffer that includes the memory for the strings and all of the pointers.
123 // Add one byte at the end just in case the file didn't end with a '\n'.
124 size_t symbol_data_size;
125 if (__builtin_add_overflow(ptr_size, file_size, &symbol_data_size) ||
126 __builtin_add_overflow(symbol_data_size, 1, &symbol_data_size)) {
127 return nullptr;
128 }
129
130 uint8_t* symbol_data = reinterpret_cast<uint8_t*>(malloc(symbol_data_size));
131 if (symbol_data == nullptr) {
132 return nullptr;
133 }
134
135 // Copy the string data into the buffer.
136 char* cur_string = reinterpret_cast<char*>(&symbol_data[ptr_size]);
137 // If this fails, the read won't read back the correct number of bytes.
138 lseek(fd.get(), 0, SEEK_SET);
139 ssize_t num_read = read(fd.get(), cur_string, file_size);
140 fd.reset(-1);
141 if (num_read != file_size) {
142 free(symbol_data);
143 return nullptr;
144 }
145
146 // Make sure the last character in the file is '\n'.
147 if (cur_string[file_size] != '\n') {
148 cur_string[file_size++] = '\n';
149 }
150
151 for (int i = 0; i < size; i++) {
152 (reinterpret_cast<char**>(symbol_data))[i] = cur_string;
153 cur_string = strchr(cur_string, '\n');
154 if (cur_string == nullptr) {
155 free(symbol_data);
156 return nullptr;
157 }
158 cur_string[0] = '\0';
159 cur_string++;
160 }
161 return reinterpret_cast<char**>(symbol_data);
162}
163
164// This function should do no allocations if possible.
165void backtrace_symbols_fd(void* const* buffer, int size, int fd) {
166 if (size <= 0 || fd < 0) {
167 return;
168 }
169
170 for (int frame_num = 0; frame_num < size; frame_num++) {
171 void* address = buffer[frame_num];
172 Dl_info info;
173 if (dladdr(address, &info) != 0) {
174 if (info.dli_fname != nullptr) {
175 write(fd, info.dli_fname, strlen(info.dli_fname));
176 }
177 if (info.dli_sname != nullptr) {
178 dprintf(fd, "(%s+0x%" PRIxPTR ") ", info.dli_sname,
179 reinterpret_cast<uintptr_t>(address) - reinterpret_cast<uintptr_t>(info.dli_saddr));
180 } else {
181 dprintf(fd, "(+%p) ", info.dli_saddr);
182 }
183 }
184
185 dprintf(fd, "[%p]\n", address);
186 }
187}