1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // crash_handler_posix:
7 // ANGLE's crash handling and stack walking code. Modified from Skia's:
8 // https://github.com/google/skia/blob/master/tools/CrashHandler.cpp
9 //
10
11 #include "util/test_utils.h"
12
13 #include "common/FixedVector.h"
14 #include "common/angleutils.h"
15 #include "common/string_utils.h"
16 #include "common/system_utils.h"
17
18 #include <fcntl.h>
19 #include <inttypes.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <sys/types.h>
23 #include <sys/wait.h>
24 #include <unistd.h>
25 #include <iostream>
26
27 #if !defined(ANGLE_PLATFORM_ANDROID) && !defined(ANGLE_PLATFORM_FUCHSIA)
28 # if defined(ANGLE_PLATFORM_APPLE)
29 // We only use local unwinding, so we can define this to select a faster implementation.
30 # define UNW_LOCAL_ONLY
31 # include <cxxabi.h>
32 # include <libunwind.h>
33 # include <signal.h>
34 # elif defined(ANGLE_PLATFORM_POSIX)
35 // We'd use libunwind here too, but it's a pain to get installed for
36 // both 32 and 64 bit on bots. Doesn't matter much: catchsegv is best anyway.
37 # include <cxxabi.h>
38 # include <dlfcn.h>
39 # include <execinfo.h>
40 # include <libgen.h>
41 # include <link.h>
42 # include <signal.h>
43 # include <string.h>
44 # endif // defined(ANGLE_PLATFORM_APPLE)
45 #endif // !defined(ANGLE_PLATFORM_ANDROID) && !defined(ANGLE_PLATFORM_FUCHSIA)
46
47 // This code snippet is coped from Chromium's base/posix/eintr_wrapper.h.
48 #if defined(NDEBUG)
49 # define HANDLE_EINTR(x) \
50 ({ \
51 decltype(x) eintr_wrapper_result; \
52 do \
53 { \
54 eintr_wrapper_result = (x); \
55 } while (eintr_wrapper_result == -1 && errno == EINTR); \
56 eintr_wrapper_result; \
57 })
58 #else
59 # define HANDLE_EINTR(x) \
60 ({ \
61 int eintr_wrapper_counter = 0; \
62 decltype(x) eintr_wrapper_result; \
63 do \
64 { \
65 eintr_wrapper_result = (x); \
66 } while (eintr_wrapper_result == -1 && errno == EINTR && \
67 eintr_wrapper_counter++ < 100); \
68 eintr_wrapper_result; \
69 })
70 #endif // NDEBUG
71
72 namespace angle
73 {
74 #if defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_FUCHSIA)
75
PrintStackBacktrace()76 void PrintStackBacktrace()
77 {
78 // No implementations yet.
79 }
80
InitCrashHandler(CrashCallback * callback)81 void InitCrashHandler(CrashCallback *callback)
82 {
83 // No implementations yet.
84 }
85
TerminateCrashHandler()86 void TerminateCrashHandler()
87 {
88 // No implementations yet.
89 }
90
91 #else
92 namespace
93 {
94 CrashCallback *gCrashHandlerCallback;
95 } // namespace
96
97 # if defined(ANGLE_PLATFORM_APPLE)
98
99 void PrintStackBacktrace()
100 {
101 printf("Backtrace:\n");
102
103 unw_context_t context;
104 unw_getcontext(&context);
105
106 unw_cursor_t cursor;
107 unw_init_local(&cursor, &context);
108
109 while (unw_step(&cursor) > 0)
110 {
111 static const size_t kMax = 256;
112 char mangled[kMax], demangled[kMax];
113 unw_word_t offset;
114 unw_get_proc_name(&cursor, mangled, kMax, &offset);
115
116 int ok;
117 size_t len = kMax;
118 abi::__cxa_demangle(mangled, demangled, &len, &ok);
119
120 printf(" %s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset);
121 }
122 printf("\n");
123 }
124
125 static void Handler(int sig)
126 {
127 if (gCrashHandlerCallback)
128 {
129 (*gCrashHandlerCallback)();
130 }
131
132 printf("\nSignal %d:\n", sig);
133 PrintStackBacktrace();
134
135 // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
136 _Exit(sig);
137 }
138
139 # elif defined(ANGLE_PLATFORM_POSIX)
140
141 // Can control this at a higher level if required.
142 # define ANGLE_HAS_ADDR2LINE
143
144 # if defined(ANGLE_HAS_ADDR2LINE)
145 namespace
146 {
147 // The following code was adapted from Chromium's "stack_trace_posix.cc".
148 // Describes a region of mapped memory and the path of the file mapped.
149 struct MappedMemoryRegion
150 {
151 enum Permission
152 {
153 READ = 1 << 0,
154 WRITE = 1 << 1,
155 EXECUTE = 1 << 2,
156 PRIVATE = 1 << 3, // If set, region is private, otherwise it is shared.
157 };
158
159 // The address range [start,end) of mapped memory.
160 uintptr_t start;
161 uintptr_t end;
162
163 // Byte offset into |path| of the range mapped into memory.
164 unsigned long long offset;
165
166 // Image base, if this mapping corresponds to an ELF image.
167 uintptr_t base;
168
169 // Bitmask of read/write/execute/private/shared permissions.
170 uint8_t permissions;
171
172 // Name of the file mapped into memory.
173 //
174 // NOTE: path names aren't guaranteed to point at valid files. For example,
175 // "[heap]" and "[stack]" are used to represent the location of the process'
176 // heap and stack, respectively.
177 std::string path;
178 };
179
180 using MemoryRegionArray = std::vector<MappedMemoryRegion>;
181
182 bool ReadProcMaps(std::string *proc_maps)
183 {
184 // seq_file only writes out a page-sized amount on each call. Refer to header
185 // file for details.
186 const long kReadSize = sysconf(_SC_PAGESIZE);
187
188 int fd(HANDLE_EINTR(open("/proc/self/maps", O_RDONLY)));
189 if (fd == -1)
190 {
191 fprintf(stderr, "Couldn't open /proc/self/maps\n");
192 return false;
193 }
194 proc_maps->clear();
195
196 while (true)
197 {
198 // To avoid a copy, resize |proc_maps| so read() can write directly into it.
199 // Compute |buffer| afterwards since resize() may reallocate.
200 size_t pos = proc_maps->size();
201 proc_maps->resize(pos + kReadSize);
202 void *buffer = &(*proc_maps)[pos];
203
204 ssize_t bytes_read = HANDLE_EINTR(read(fd, buffer, kReadSize));
205 if (bytes_read < 0)
206 {
207 fprintf(stderr, "Couldn't read /proc/self/maps\n");
208 proc_maps->clear();
209 close(fd);
210 return false;
211 }
212
213 // ... and don't forget to trim off excess bytes.
214 proc_maps->resize(pos + bytes_read);
215
216 if (bytes_read == 0)
217 break;
218 }
219
220 close(fd);
221 return true;
222 }
223
224 bool ParseProcMaps(const std::string &input, MemoryRegionArray *regions_out)
225 {
226 ASSERT(regions_out);
227 MemoryRegionArray regions;
228
229 // This isn't async safe nor terribly efficient, but it doesn't need to be at
230 // this point in time.
231 std::vector<std::string> lines = SplitString(input, "\n", TRIM_WHITESPACE, SPLIT_WANT_ALL);
232
233 for (size_t i = 0; i < lines.size(); ++i)
234 {
235 // Due to splitting on '\n' the last line should be empty.
236 if (i == lines.size() - 1)
237 {
238 if (!lines[i].empty())
239 {
240 fprintf(stderr, "ParseProcMaps: Last line not empty");
241 return false;
242 }
243 break;
244 }
245
246 MappedMemoryRegion region;
247 const char *line = lines[i].c_str();
248 char permissions[5] = {'\0'}; // Ensure NUL-terminated string.
249 uint8_t dev_major = 0;
250 uint8_t dev_minor = 0;
251 long inode = 0;
252 int path_index = 0;
253
254 // Sample format from man 5 proc:
255 //
256 // address perms offset dev inode pathname
257 // 08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm
258 //
259 // The final %n term captures the offset in the input string, which is used
260 // to determine the path name. It *does not* increment the return value.
261 // Refer to man 3 sscanf for details.
262 if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4c %llx %hhx:%hhx %ld %n", ®ion.start,
263 ®ion.end, permissions, ®ion.offset, &dev_major, &dev_minor, &inode,
264 &path_index) < 7)
265 {
266 fprintf(stderr, "ParseProcMaps: sscanf failed for line: %s\n", line);
267 return false;
268 }
269
270 region.permissions = 0;
271
272 if (permissions[0] == 'r')
273 region.permissions |= MappedMemoryRegion::READ;
274 else if (permissions[0] != '-')
275 return false;
276
277 if (permissions[1] == 'w')
278 region.permissions |= MappedMemoryRegion::WRITE;
279 else if (permissions[1] != '-')
280 return false;
281
282 if (permissions[2] == 'x')
283 region.permissions |= MappedMemoryRegion::EXECUTE;
284 else if (permissions[2] != '-')
285 return false;
286
287 if (permissions[3] == 'p')
288 region.permissions |= MappedMemoryRegion::PRIVATE;
289 else if (permissions[3] != 's' && permissions[3] != 'S') // Shared memory.
290 return false;
291
292 // Pushing then assigning saves us a string copy.
293 regions.push_back(region);
294 regions.back().path.assign(line + path_index);
295 }
296
297 regions_out->swap(regions);
298 return true;
299 }
300
301 // Set the base address for each memory region by reading ELF headers in
302 // process memory.
303 void SetBaseAddressesForMemoryRegions(MemoryRegionArray ®ions)
304 {
305 int mem_fd(HANDLE_EINTR(open("/proc/self/mem", O_RDONLY | O_CLOEXEC)));
306 if (mem_fd == -1)
307 return;
308
309 auto safe_memcpy = [&mem_fd](void *dst, uintptr_t src, size_t size) {
310 return HANDLE_EINTR(pread(mem_fd, dst, size, src)) == ssize_t(size);
311 };
312
313 uintptr_t cur_base = 0;
314 for (MappedMemoryRegion &r : regions)
315 {
316 ElfW(Ehdr) ehdr;
317 static_assert(SELFMAG <= sizeof(ElfW(Ehdr)), "SELFMAG too large");
318 if ((r.permissions & MappedMemoryRegion::READ) &&
319 safe_memcpy(&ehdr, r.start, sizeof(ElfW(Ehdr))) &&
320 memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0)
321 {
322 switch (ehdr.e_type)
323 {
324 case ET_EXEC:
325 cur_base = 0;
326 break;
327 case ET_DYN:
328 // Find the segment containing file offset 0. This will correspond
329 // to the ELF header that we just read. Normally this will have
330 // virtual address 0, but this is not guaranteed. We must subtract
331 // the virtual address from the address where the ELF header was
332 // mapped to get the base address.
333 //
334 // If we fail to find a segment for file offset 0, use the address
335 // of the ELF header as the base address.
336 cur_base = r.start;
337 for (unsigned i = 0; i != ehdr.e_phnum; ++i)
338 {
339 ElfW(Phdr) phdr;
340 if (safe_memcpy(&phdr, r.start + ehdr.e_phoff + i * sizeof(phdr),
341 sizeof(phdr)) &&
342 phdr.p_type == PT_LOAD && phdr.p_offset == 0)
343 {
344 cur_base = r.start - phdr.p_vaddr;
345 break;
346 }
347 }
348 break;
349 default:
350 // ET_REL or ET_CORE. These aren't directly executable, so they
351 // don't affect the base address.
352 break;
353 }
354 }
355
356 r.base = cur_base;
357 }
358
359 close(mem_fd);
360 }
361
362 // Parses /proc/self/maps in order to compile a list of all object file names
363 // for the modules that are loaded in the current process.
364 // Returns true on success.
365 bool CacheMemoryRegions(MemoryRegionArray ®ions)
366 {
367 // Reads /proc/self/maps.
368 std::string contents;
369 if (!ReadProcMaps(&contents))
370 {
371 fprintf(stderr, "CacheMemoryRegions: Failed to read /proc/self/maps\n");
372 return false;
373 }
374
375 // Parses /proc/self/maps.
376 if (!ParseProcMaps(contents, ®ions))
377 {
378 fprintf(stderr, "CacheMemoryRegions: Failed to parse the contents of /proc/self/maps\n");
379 return false;
380 }
381
382 SetBaseAddressesForMemoryRegions(regions);
383 return true;
384 }
385
386 constexpr size_t kAddr2LineMaxParameters = 50;
387 using Addr2LineCommandLine = angle::FixedVector<const char *, kAddr2LineMaxParameters>;
388
389 void CallAddr2Line(const Addr2LineCommandLine &commandLine)
390 {
391 pid_t pid = fork();
392 if (pid < 0)
393 {
394 std::cerr << "Error: Failed to fork()" << std::endl;
395 }
396 else if (pid > 0)
397 {
398 int status;
399 waitpid(pid, &status, 0);
400 // Ignore the status, since we aren't going to handle it anyway.
401 }
402 else
403 {
404 // Child process executes addr2line
405 //
406 // See comment in test_utils_posix.cpp::PosixProcess regarding const_cast.
407 execv(commandLine[0], const_cast<char *const *>(commandLine.data()));
408 std::cerr << "Error: Child process returned from exevc()" << std::endl;
409 _exit(EXIT_FAILURE); // exec never returns
410 }
411 }
412
413 constexpr size_t kMaxAddressLen = 1024;
414 using AddressBuffer = angle::FixedVector<char, kMaxAddressLen>;
415
416 const char *ResolveAddress(const MemoryRegionArray ®ions,
417 const std::string &resolvedModule,
418 const char *address,
419 AddressBuffer &buffer)
420 {
421 size_t lastModuleSlash = resolvedModule.rfind('/');
422 ASSERT(lastModuleSlash != std::string::npos);
423 std::string baseModule = resolvedModule.substr(lastModuleSlash);
424
425 for (const MappedMemoryRegion ®ion : regions)
426 {
427 size_t pathSlashPos = region.path.rfind('/');
428 if (pathSlashPos != std::string::npos && region.path.substr(pathSlashPos) == baseModule)
429 {
430 uintptr_t scannedAddress;
431 int scanReturn = sscanf(address, "%" SCNxPTR, &scannedAddress);
432 ASSERT(scanReturn == 1);
433 scannedAddress -= region.base;
434 char printBuffer[255] = {};
435 size_t scannedSize = sprintf(printBuffer, "0x%" PRIXPTR, scannedAddress);
436 size_t bufferSize = buffer.size();
437 buffer.resize(bufferSize + scannedSize + 1, 0);
438 memcpy(&buffer[bufferSize], printBuffer, scannedSize);
439 return &buffer[bufferSize];
440 }
441 }
442
443 return address;
444 }
445 } // anonymous namespace
446 # endif // defined(ANGLE_HAS_ADDR2LINE)
447
448 void PrintStackBacktrace()
449 {
450 printf("Backtrace:\n");
451
452 void *stack[64];
453 const int count = backtrace(stack, ArraySize(stack));
454 char **symbols = backtrace_symbols(stack, count);
455
456 # if defined(ANGLE_HAS_ADDR2LINE)
457
458 MemoryRegionArray regions;
459 CacheMemoryRegions(regions);
460
461 // Child process executes addr2line
462 constexpr size_t kAddr2LineFixedParametersCount = 6;
463 Addr2LineCommandLine commandLineArgs = {
464 "/usr/bin/addr2line", // execv requires an absolute path to find addr2line
465 "-s",
466 "-p",
467 "-f",
468 "-C",
469 "-e",
470 };
471 const char *currentModule = "";
472 std::string resolvedModule;
473 AddressBuffer addressBuffer;
474
475 for (int i = 0; i < count; i++)
476 {
477 char *symbol = symbols[i];
478
479 // symbol looks like the following:
480 //
481 // path/to/module(+localAddress) [address]
482 //
483 // If module is not an absolute path, it needs to be resolved.
484
485 char *module = symbol;
486 char *address = strchr(symbol, '[') + 1;
487
488 *strchr(module, '(') = 0;
489 *strchr(address, ']') = 0;
490
491 // If module is the same as last, continue batching addresses. If commandLineArgs has
492 // reached its capacity however, make the call to addr2line already. Note that there should
493 // be one entry left for the terminating nullptr at the end of the command line args.
494 if (strcmp(module, currentModule) == 0 &&
495 commandLineArgs.size() + 1 < commandLineArgs.max_size())
496 {
497 commandLineArgs.push_back(
498 ResolveAddress(regions, resolvedModule, address, addressBuffer));
499 continue;
500 }
501
502 // If there's a command batched, execute it before modifying currentModule (a pointer to
503 // which is stored in the command line args).
504 if (currentModule[0] != 0)
505 {
506 commandLineArgs.push_back(nullptr);
507 CallAddr2Line(commandLineArgs);
508 addressBuffer.clear();
509 }
510
511 // Reset the command line and remember this module as the current.
512 resolvedModule = currentModule = module;
513 commandLineArgs.resize(kAddr2LineFixedParametersCount);
514
515 // We need an absolute path to get to the executable and all of the various shared objects,
516 // but the caller may have used a relative path to launch the executable, so build one up if
517 // we don't see a leading '/'.
518 if (resolvedModule.at(0) != GetPathSeparator())
519 {
520 const Optional<std::string> &cwd = angle::GetCWD();
521 if (!cwd.valid())
522 {
523 std::cerr << "Error getting CWD to print the backtrace." << std::endl;
524 }
525 else
526 {
527 std::string absolutePath = cwd.value();
528 size_t lastPathSepLoc = resolvedModule.find_last_of(GetPathSeparator());
529 std::string relativePath = resolvedModule.substr(0, lastPathSepLoc);
530
531 // Remove "." from the relativePath path
532 // For example: ./out/LinuxDebug/angle_perftests
533 size_t pos = relativePath.find('.');
534 if (pos != std::string::npos)
535 {
536 // If found then erase it from string
537 relativePath.erase(pos, 1);
538 }
539
540 // Remove the overlapping relative path from the CWD so we can build the full
541 // absolute path.
542 // For example:
543 // absolutePath = /home/timvp/code/angle/out/LinuxDebug
544 // relativePath = /out/LinuxDebug
545 pos = absolutePath.find(relativePath);
546 if (pos != std::string::npos)
547 {
548 // If found then erase it from string
549 absolutePath.erase(pos, relativePath.length());
550 }
551 resolvedModule = absolutePath + GetPathSeparator() + resolvedModule;
552 }
553 }
554
555 // Check if this is a symlink. We assume the symlinks are relative to the target.
556 constexpr size_t kBufSize = 1000;
557 char linkBuf[kBufSize] = {};
558 ssize_t readLinkRet = readlink(resolvedModule.c_str(), linkBuf, kBufSize);
559 if (readLinkRet != -1)
560 {
561 ASSERT(strchr(linkBuf, '/') == nullptr);
562 size_t lastSlash = resolvedModule.rfind('/');
563 ASSERT(lastSlash != std::string::npos);
564 resolvedModule = resolvedModule.substr(0, lastSlash + 1) + linkBuf;
565 }
566
567 const char *resolvedAddress =
568 ResolveAddress(regions, resolvedModule, address, addressBuffer);
569
570 commandLineArgs.push_back(resolvedModule.c_str());
571 commandLineArgs.push_back(resolvedAddress);
572 }
573
574 // Call addr2line for the last batch of addresses.
575 if (currentModule[0] != 0)
576 {
577 commandLineArgs.push_back(nullptr);
578 CallAddr2Line(commandLineArgs);
579 }
580 # else
581 for (int i = 0; i < count; i++)
582 {
583 Dl_info info;
584 if (dladdr(stack[i], &info) && info.dli_sname)
585 {
586 // Make sure this is large enough to hold the fully demangled names, otherwise we could
587 // segault/hang here. For example, Vulkan validation layer errors can be deep enough
588 // into the stack that very large symbol names are generated.
589 char demangled[4096];
590 size_t len = ArraySize(demangled);
591 int ok;
592
593 abi::__cxa_demangle(info.dli_sname, demangled, &len, &ok);
594 if (ok == 0)
595 {
596 printf(" %s\n", demangled);
597 continue;
598 }
599 }
600 printf(" %s\n", symbols[i]);
601 }
602 # endif // defined(ANGLE_HAS_ADDR2LINE)
603 }
604
605 static void Handler(int sig)
606 {
607 if (gCrashHandlerCallback)
608 {
609 (*gCrashHandlerCallback)();
610 }
611
612 printf("\nSignal %d [%s]:\n", sig, strsignal(sig));
613 PrintStackBacktrace();
614
615 // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
616 _Exit(sig);
617 }
618
619 # endif // defined(ANGLE_PLATFORM_APPLE)
620
621 static constexpr int kSignals[] = {
622 SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP,
623 };
624
625 void InitCrashHandler(CrashCallback *callback)
626 {
627 gCrashHandlerCallback = callback;
628 for (int sig : kSignals)
629 {
630 // Register our signal handler unless something's already done so (e.g. catchsegv).
631 void (*prev)(int) = signal(sig, Handler);
632 if (prev != SIG_DFL)
633 {
634 signal(sig, prev);
635 }
636 }
637 }
638
639 void TerminateCrashHandler()
640 {
641 gCrashHandlerCallback = nullptr;
642 for (int sig : kSignals)
643 {
644 void (*prev)(int) = signal(sig, SIG_DFL);
645 if (prev != Handler && prev != SIG_DFL)
646 {
647 signal(sig, prev);
648 }
649 }
650 }
651
652 #endif // defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_FUCHSIA)
653
654 } // namespace angle
655