1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "partition_alloc/partition_alloc_base/debug/stack_trace.h"
6
7 #include <fcntl.h>
8 #include <unistd.h>
9
10 #include <cstring>
11
12 #include "partition_alloc/partition_alloc_base/logging.h"
13 #include "partition_alloc/partition_alloc_base/posix/eintr_wrapper.h"
14 #include "partition_alloc/partition_alloc_base/strings/safe_sprintf.h"
15
16 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_APPLE)
17 #include <link.h> // For ElfW() macro.
18 #endif
19
20 #if BUILDFLAG(IS_APPLE)
21 #include <dlfcn.h>
22 #endif
23
24 namespace partition_alloc::internal::base::debug {
25
26 namespace {
27
28 #if !BUILDFLAG(IS_APPLE)
29
30 // On Android the 'open' function has two versions:
31 // int open(const char *pathname, int flags);
32 // int open(const char *pathname, int flags, mode_t mode);
33 //
34 // This doesn't play well with WrapEINTR template. This alias helps the compiler
35 // to make a decision.
OpenFile(const char * pathname,int flags)36 int OpenFile(const char* pathname, int flags) {
37 return open(pathname, flags);
38 }
39
40 constexpr size_t kBufferSize = 4096u;
41
42 enum {
43 kMapReadable = 1u,
44 kMapWritable = 2u,
45 kMapExecutable = 4u,
46 kMapPrivate = 8u,
47 };
48
ParseAddress(const char ** ptr,const char * end,uintptr_t * address_return)49 bool ParseAddress(const char** ptr,
50 const char* end,
51 uintptr_t* address_return) {
52 const char* start = *ptr;
53
54 // 0xNN = 2 characters
55 const char* max_address = start + sizeof(void*) * 2;
56 uintptr_t value = 0;
57
58 const char* p = start;
59 for (; p < end && p < max_address; ++p) {
60 if ('0' <= *p && *p <= '9') {
61 value = (value << 4) | (unsigned char)(*p - '0');
62 } else if ('a' <= *p && *p <= 'f') {
63 value = (value << 4) | (unsigned char)(*p - 'a' + 10);
64 } else {
65 break;
66 }
67 }
68 if (p == start) {
69 return false;
70 }
71 *ptr = p;
72 if (address_return) {
73 *address_return = value;
74 }
75 return true;
76 }
77
ParseInteger(const char ** ptr,const char * end)78 bool ParseInteger(const char** ptr, const char* end) {
79 const char* start = *ptr;
80
81 const char* p = start;
82 for (; p < end && '0' <= *p && *p <= '9'; ++p)
83 ;
84 *ptr = p;
85 return p > start;
86 }
87
ParsePermissions(const char ** ptr,const char * end,unsigned * permission_return)88 bool ParsePermissions(const char** ptr,
89 const char* end,
90 unsigned* permission_return) {
91 unsigned permission = 0u;
92 const char* p = *ptr;
93 if (p < end && (*p == 'r' || *p == '-')) {
94 permission |= (*p == 'r') ? kMapReadable : 0u;
95 ++p;
96 } else {
97 return false;
98 }
99 if (p < end && (*p == 'w' || *p == '-')) {
100 permission |= (*p == 'w') ? kMapWritable : 0u;
101 ++p;
102 } else {
103 return false;
104 }
105 if (p < end && (*p == 'x' || *p == '-')) {
106 permission |= (*p == 'w') ? kMapExecutable : 0u;
107 ++p;
108 } else {
109 return false;
110 }
111 if (p < end && (*p == 'p' || *p == '-' || *p == 's')) {
112 permission |= (*p == 'w') ? kMapPrivate : 0u;
113 ++p;
114 } else {
115 return false;
116 }
117 *ptr = p;
118 if (permission_return) {
119 *permission_return = permission;
120 }
121 return true;
122 }
123
ParseMapsLine(const char * line_start,const char * line_end,uintptr_t * start_address_return,uintptr_t * end_address_return,unsigned * permission_return,uintptr_t * offset_return,const char ** module_name)124 bool ParseMapsLine(const char* line_start,
125 const char* line_end,
126 uintptr_t* start_address_return,
127 uintptr_t* end_address_return,
128 unsigned* permission_return,
129 uintptr_t* offset_return,
130 const char** module_name) {
131 const char* ptr = line_start;
132 if (!ParseAddress(&ptr, line_end, start_address_return)) {
133 return false;
134 }
135 // Delimiter
136 if (ptr >= line_end || *ptr != '-') {
137 return false;
138 }
139 ++ptr;
140 if (!ParseAddress(&ptr, line_end, end_address_return)) {
141 return false;
142 }
143
144 // Delimiter
145 if (ptr >= line_end || *ptr != ' ') {
146 return false;
147 }
148 ++ptr;
149
150 // skip permissions.
151 if (!ParsePermissions(&ptr, line_end, permission_return)) {
152 return false;
153 }
154
155 // Delimiter
156 if (ptr >= line_end || *ptr != ' ') {
157 return false;
158 }
159 ++ptr;
160
161 // skip offset
162 if (ParseAddress(&ptr, line_end, offset_return)) {
163 if (ptr >= line_end || *ptr != ' ') {
164 return false;
165 }
166 ++ptr;
167
168 // skip dev
169 if (!ParseAddress(&ptr, line_end, nullptr)) {
170 return false;
171 }
172 if (ptr >= line_end || *ptr != ':') {
173 return false;
174 }
175 ++ptr;
176 if (!ParseAddress(&ptr, line_end, nullptr)) {
177 return false;
178 }
179
180 // Delimiter
181 if (ptr >= line_end || *ptr != ' ') {
182 return false;
183 }
184 ++ptr;
185
186 // skip inode
187 if (!ParseInteger(&ptr, line_end)) {
188 return false;
189 }
190 } else {
191 if (offset_return) {
192 *offset_return = 0u;
193 }
194 }
195 if (ptr >= line_end || *ptr != ' ') {
196 return false;
197 }
198 for (; ptr < line_end && *ptr == ' '; ++ptr)
199 ;
200 if (ptr <= line_end && module_name) {
201 *module_name = ptr;
202 }
203 return true;
204 }
205
206 #if !BUILDFLAG(IS_ANDROID)
207
ReadFromOffset(const int fd,void * buf,const size_t count,const size_t offset)208 ssize_t ReadFromOffset(const int fd,
209 void* buf,
210 const size_t count,
211 const size_t offset) {
212 char* buf0 = reinterpret_cast<char*>(buf);
213 size_t num_bytes = 0;
214 while (num_bytes < count) {
215 ssize_t len;
216 len = WrapEINTR(pread)(fd, buf0 + num_bytes, count - num_bytes,
217 static_cast<off_t>(offset + num_bytes));
218 if (len < 0) { // There was an error other than EINTR.
219 return -1;
220 }
221 if (len == 0) { // Reached EOF.
222 break;
223 }
224 num_bytes += static_cast<size_t>(len);
225 }
226 return static_cast<ssize_t>(num_bytes);
227 }
228
UpdateBaseAddress(unsigned permissions,uintptr_t start_address,uintptr_t * base_address)229 void UpdateBaseAddress(unsigned permissions,
230 uintptr_t start_address,
231 uintptr_t* base_address) {
232 // Determine the base address by reading ELF headers in process memory.
233 // Skip non-readable maps.
234 if (!(permissions & kMapReadable)) {
235 return;
236 }
237
238 int mem_fd = WrapEINTR(OpenFile)("/proc/self/mem", O_RDONLY);
239 if (mem_fd == -1) {
240 PA_RAW_LOG(ERROR, "Failed to open /proc/self/mem\n");
241 return;
242 }
243
244 ElfW(Ehdr) ehdr;
245 ssize_t len =
246 ReadFromOffset(mem_fd, &ehdr, sizeof(ElfW(Ehdr)), start_address);
247 if (len == sizeof(ElfW(Ehdr))) {
248 if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0) {
249 switch (ehdr.e_type) {
250 case ET_EXEC:
251 *base_address = 0;
252 break;
253 case ET_DYN:
254 // Find the segment containing file offset 0. This will correspond
255 // to the ELF header that we just read. Normally this will have
256 // virtual address 0, but this is not guaranteed. We must subtract
257 // the virtual address from the address where the ELF header was
258 // mapped to get the base address.
259 //
260 // If we fail to find a segment for file offset 0, use the address
261 // of the ELF header as the base address.
262 *base_address = start_address;
263 for (unsigned i = 0; i != ehdr.e_phnum; ++i) {
264 ElfW(Phdr) phdr;
265 len =
266 ReadFromOffset(mem_fd, &phdr, sizeof(ElfW(Phdr)),
267 start_address + ehdr.e_phoff + i * sizeof(phdr));
268 if (len == sizeof(ElfW(Phdr)) && phdr.p_type == PT_LOAD &&
269 phdr.p_offset == 0) {
270 *base_address = start_address - phdr.p_vaddr;
271 break;
272 }
273 }
274 break;
275 default:
276 // ET_REL or ET_CORE. These aren't directly executable, so they don't
277 // affect the base address.
278 break;
279 }
280 }
281 }
282 close(mem_fd);
283 }
284
285 #endif // !BUILDFLAG(IS_ANDROID)
286
PrintStackTraceInternal(const void ** trace,size_t count)287 void PrintStackTraceInternal(const void** trace, size_t count) {
288 int fd = WrapEINTR(OpenFile)("/proc/self/maps", O_RDONLY);
289 if (fd == -1) {
290 PA_RAW_LOG(ERROR, "Failed to open /proc/self/maps\n");
291 return;
292 }
293
294 char buffer[kBufferSize];
295 char* dest = buffer;
296 char* buffer_end = buffer + kBufferSize;
297 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_APPLE)
298 uintptr_t base_address = 0u;
299 #endif
300
301 while (dest < buffer_end) {
302 ssize_t bytes_read = WrapEINTR(read)(fd, dest, buffer_end - dest);
303 if (bytes_read == 0) {
304 break;
305 }
306 if (bytes_read < 0) {
307 PA_RAW_LOG(ERROR, "Failed to read /proc/self/maps\n");
308 break;
309 }
310
311 char* read_end = dest + bytes_read;
312 char* parsed = buffer;
313 char* line_start = buffer;
314 // It is difficult to remember entire memory regions and to use them
315 // to process stack traces. Instead, try to parse each line of
316 // /proc/self/maps and to process matched stack traces. This will
317 // make the order of the output stack traces different from the input.
318 for (char* line_end = buffer; line_end < read_end; ++line_end) {
319 if (*line_end == '\n') {
320 parsed = line_end + 1;
321 *line_end = '\0';
322 uintptr_t start_address = 0u;
323 uintptr_t end_address = 0u;
324 uintptr_t offset = 0u;
325 unsigned permissions = 0u;
326 const char* module_name = nullptr;
327 bool ok =
328 ParseMapsLine(line_start, line_end, &start_address, &end_address,
329 &permissions, &offset, &module_name);
330 if (ok) {
331 #if !BUILDFLAG(IS_ANDROID)
332 UpdateBaseAddress(permissions, start_address, &base_address);
333 #endif
334 if (module_name && *module_name != '\0') {
335 for (size_t i = 0; i < count; i++) {
336 #if BUILDFLAG(IS_ANDROID)
337 // Subtract one as return address of function may be in the next
338 // function when a function is annotated as noreturn.
339 uintptr_t address = reinterpret_cast<uintptr_t>(trace[i]) - 1;
340 uintptr_t base_address = start_address;
341 #else
342 uintptr_t address = reinterpret_cast<uintptr_t>(trace[i]);
343 #endif
344 if (start_address <= address && address < end_address) {
345 OutputStackTrace(i, address, base_address, module_name, offset);
346 }
347 }
348 }
349 } else {
350 PA_RAW_LOG(ERROR, "Parse failed.\n");
351 }
352 line_start = parsed;
353 }
354 }
355 if (parsed == buffer) {
356 // /proc/self/maps contains too long line (> kBufferSize).
357 PA_RAW_LOG(ERROR, "/proc/self/maps has too long line.\n");
358 break;
359 }
360 if (parsed < read_end) {
361 size_t left_chars = read_end - parsed;
362 memmove(buffer, parsed, left_chars);
363 dest = buffer + left_chars;
364 } else {
365 dest = buffer;
366 }
367 }
368 close(fd);
369 }
370 #endif // !BUILDFLAG(IS_APPLE)
371
372 #if BUILDFLAG(IS_APPLE)
373 // Since /proc/self/maps is not available, use dladdr() to obtain module
374 // names and offsets inside the modules from the given addresses.
PrintStackTraceInternal(const void * const * trace,size_t size)375 void PrintStackTraceInternal(const void* const* trace, size_t size) {
376 // NOTE: This code MUST be async-signal safe (it's used by in-process
377 // stack dumping signal handler). NO malloc or stdio is allowed here.
378
379 Dl_info dl_info;
380 for (size_t i = 0; i < size; ++i) {
381 const bool dl_info_found = dladdr(trace[i], &dl_info) != 0;
382 if (dl_info_found) {
383 const char* last_sep = strrchr(dl_info.dli_fname, '/');
384 const char* basename = last_sep ? last_sep + 1 : dl_info.dli_fname;
385
386 // Use atos with --offset to obtain symbols from the printed addresses,
387 // e.g.
388 // #01 0x0000000106225d6c (base_unittests+0x0000000001999d6c)
389 // bash-3.2$ atos -o out/default/base_unittests --offset
390 // 0x0000000001999d6c
391 // partition_alloc::internal::PartitionAllocTest_Basic_Test::TestBody()
392 // (in base_unittests) + 156
393 OutputStackTrace(i, reinterpret_cast<uintptr_t>(trace[i]),
394 reinterpret_cast<uintptr_t>(dl_info.dli_fbase), basename,
395 0u);
396 } else {
397 OutputStackTrace(i, reinterpret_cast<uintptr_t>(trace[i]), 0u, "???", 0u);
398 }
399 }
400 }
401 #endif // BUILDFLAG(IS_APPLE)
402
403 } // namespace
404
PrintStackTrace(const void ** trace,size_t count)405 void PrintStackTrace(const void** trace, size_t count) {
406 PrintStackTraceInternal(trace, count);
407 }
408
409 // stack_trace_android.cc defines its own OutputStackTrace.
410 #if !BUILDFLAG(IS_ANDROID)
OutputStackTrace(unsigned index,uintptr_t address,uintptr_t base_address,const char * module_name,uintptr_t)411 void OutputStackTrace(unsigned index,
412 uintptr_t address,
413 uintptr_t base_address,
414 const char* module_name,
415 uintptr_t) {
416 char buffer[256];
417 strings::SafeSPrintf(buffer, "#%02d 0x%0x (%s+0x%0x)\n", index, address,
418 module_name, address - base_address);
419 PA_RAW_LOG(INFO, buffer);
420 }
421 #endif // !BUILDFLAG(IS_ANDROID)
422
423 } // namespace partition_alloc::internal::base::debug
424