xref: /aosp_15_r20/bionic/libc/bionic/execinfo.cpp (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1 /*
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 
41 struct StackState {
42   void** frames;
43   int frame_count;
44   int cur_frame = 0;
45 
StackStateStackState46   StackState(void** frames, int frame_count) : frames(frames), frame_count(frame_count) {}
47 };
48 
TraceFunction(_Unwind_Context * context,void * arg)49 static _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(__riscv)
77     // C instructions are the shortest at 2 bytes long. (Unlike thumb, it's
78     // non-trivial to recognize C instructions when going backwards in the
79     // instruction stream.)
80     ip -= 2;
81 #elif defined(__i386__) || defined(__x86_64__)
82     // It's difficult to decode exactly where the previous instruction is,
83     // so subtract 1 to estimate where the instruction lives.
84     ip--;
85 #endif
86   }
87 
88   StackState* state = static_cast<StackState*>(arg);
89   state->frames[state->cur_frame++] = reinterpret_cast<void*>(ip);
90   return (state->cur_frame >= state->frame_count) ? _URC_END_OF_STACK : _URC_NO_REASON;
91 }
92 
backtrace(void ** buffer,int size)93 int backtrace(void** buffer, int size) {
94   if (size <= 0) {
95     return 0;
96   }
97 
98   StackState state(buffer, size);
99   _Unwind_Backtrace(TraceFunction, &state);
100   return state.cur_frame;
101 }
102 
backtrace_symbols(void * const * buffer,int size)103 char** backtrace_symbols(void* const* buffer, int size) {
104   if (size <= 0) {
105     return nullptr;
106   }
107   // Do this calculation first in case the user passes in a bad value.
108   size_t ptr_size;
109   if (__builtin_mul_overflow(sizeof(char*), size, &ptr_size)) {
110     return nullptr;
111   }
112 
113   ScopedFd fd(memfd_create("backtrace_symbols_fd", MFD_CLOEXEC));
114   if (fd.get() == -1) {
115     return nullptr;
116   }
117   backtrace_symbols_fd(buffer, size, fd.get());
118 
119   // Get the size of the file.
120   off_t file_size = lseek(fd.get(), 0, SEEK_END);
121   if (file_size <= 0) {
122     return nullptr;
123   }
124 
125   // The interface for backtrace_symbols indicates that only the single
126   // returned pointer must be freed by the caller. Therefore, allocate a
127   // buffer that includes the memory for the strings and all of the pointers.
128   // Add one byte at the end just in case the file didn't end with a '\n'.
129   size_t symbol_data_size;
130   if (__builtin_add_overflow(ptr_size, file_size, &symbol_data_size) ||
131       __builtin_add_overflow(symbol_data_size, 1, &symbol_data_size)) {
132     return nullptr;
133   }
134 
135   uint8_t* symbol_data = reinterpret_cast<uint8_t*>(malloc(symbol_data_size));
136   if (symbol_data == nullptr) {
137     return nullptr;
138   }
139 
140   // Copy the string data into the buffer.
141   char* cur_string = reinterpret_cast<char*>(&symbol_data[ptr_size]);
142   // If this fails, the read won't read back the correct number of bytes.
143   lseek(fd.get(), 0, SEEK_SET);
144   ssize_t num_read = read(fd.get(), cur_string, file_size);
145   fd.reset(-1);
146   if (num_read != file_size) {
147     free(symbol_data);
148     return nullptr;
149   }
150 
151   // Make sure the last character in the file is '\n'.
152   if (cur_string[file_size] != '\n') {
153     cur_string[file_size++] = '\n';
154   }
155 
156   for (int i = 0; i < size; i++) {
157     (reinterpret_cast<char**>(symbol_data))[i] = cur_string;
158     cur_string = strchr(cur_string, '\n');
159     if (cur_string == nullptr) {
160       free(symbol_data);
161       return nullptr;
162     }
163     cur_string[0] = '\0';
164     cur_string++;
165   }
166   return reinterpret_cast<char**>(symbol_data);
167 }
168 
169 // This function should do no allocations if possible.
backtrace_symbols_fd(void * const * buffer,int size,int fd)170 void backtrace_symbols_fd(void* const* buffer, int size, int fd) {
171   if (size <= 0 || fd < 0) {
172     return;
173   }
174 
175   for (int frame_num = 0; frame_num < size; frame_num++) {
176     void* address = buffer[frame_num];
177     Dl_info info;
178     if (dladdr(address, &info) != 0) {
179       if (info.dli_fname != nullptr) {
180         write(fd, info.dli_fname, strlen(info.dli_fname));
181       }
182       if (info.dli_sname != nullptr) {
183         dprintf(fd, "(%s+0x%" PRIxPTR ") ", info.dli_sname,
184                 reinterpret_cast<uintptr_t>(address) - reinterpret_cast<uintptr_t>(info.dli_saddr));
185       } else {
186         dprintf(fd, "(+%p) ", info.dli_saddr);
187       }
188     }
189 
190     dprintf(fd, "[%p]\n", address);
191   }
192 }
193