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];
113 unw_word_t offset;
114 unw_get_proc_name(&cursor, mangled, kMax, &offset);
115
116 int ok = -1;
117 char *demangled = abi::__cxa_demangle(mangled, nullptr, nullptr, &ok);
118 printf(" %s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset);
119 if (ok)
120 {
121 free(demangled);
122 }
123 }
124 printf("\n");
125 }
126
127 static void Handler(int sig)
128 {
129 printf("\nSignal %d:\n", sig);
130
131 if (gCrashHandlerCallback)
132 {
133 (*gCrashHandlerCallback)();
134 }
135
136 PrintStackBacktrace();
137
138 // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
139 _Exit(sig);
140 }
141
142 # elif defined(ANGLE_PLATFORM_POSIX)
143
144 // Can control this at a higher level if required.
145 # define ANGLE_HAS_ADDR2LINE
146
147 # if defined(ANGLE_HAS_ADDR2LINE)
148 namespace
149 {
150 // The following code was adapted from Chromium's "stack_trace_posix.cc".
151 // Describes a region of mapped memory and the path of the file mapped.
152 struct MappedMemoryRegion
153 {
154 enum Permission
155 {
156 READ = 1 << 0,
157 WRITE = 1 << 1,
158 EXECUTE = 1 << 2,
159 PRIVATE = 1 << 3, // If set, region is private, otherwise it is shared.
160 };
161
162 // The address range [start,end) of mapped memory.
163 uintptr_t start;
164 uintptr_t end;
165
166 // Byte offset into |path| of the range mapped into memory.
167 unsigned long long offset;
168
169 // Image base, if this mapping corresponds to an ELF image.
170 uintptr_t base;
171
172 // Bitmask of read/write/execute/private/shared permissions.
173 uint8_t permissions;
174
175 // Name of the file mapped into memory.
176 //
177 // NOTE: path names aren't guaranteed to point at valid files. For example,
178 // "[heap]" and "[stack]" are used to represent the location of the process'
179 // heap and stack, respectively.
180 std::string path;
181 };
182
183 using MemoryRegionArray = std::vector<MappedMemoryRegion>;
184
185 bool ReadProcMaps(std::string *proc_maps)
186 {
187 // seq_file only writes out a page-sized amount on each call. Refer to header
188 // file for details.
189 const long kReadSize = sysconf(_SC_PAGESIZE);
190
191 int fd(HANDLE_EINTR(open("/proc/self/maps", O_RDONLY)));
192 if (fd == -1)
193 {
194 fprintf(stderr, "Couldn't open /proc/self/maps\n");
195 return false;
196 }
197 proc_maps->clear();
198
199 while (true)
200 {
201 // To avoid a copy, resize |proc_maps| so read() can write directly into it.
202 // Compute |buffer| afterwards since resize() may reallocate.
203 size_t pos = proc_maps->size();
204 proc_maps->resize(pos + kReadSize);
205 void *buffer = &(*proc_maps)[pos];
206
207 ssize_t bytes_read = HANDLE_EINTR(read(fd, buffer, kReadSize));
208 if (bytes_read < 0)
209 {
210 fprintf(stderr, "Couldn't read /proc/self/maps\n");
211 proc_maps->clear();
212 close(fd);
213 return false;
214 }
215
216 // ... and don't forget to trim off excess bytes.
217 proc_maps->resize(pos + bytes_read);
218
219 if (bytes_read == 0)
220 break;
221 }
222
223 close(fd);
224 return true;
225 }
226
227 bool ParseProcMaps(const std::string &input, MemoryRegionArray *regions_out)
228 {
229 ASSERT(regions_out);
230 MemoryRegionArray regions;
231
232 // This isn't async safe nor terribly efficient, but it doesn't need to be at
233 // this point in time.
234 std::vector<std::string> lines = SplitString(input, "\n", TRIM_WHITESPACE, SPLIT_WANT_ALL);
235
236 for (size_t i = 0; i < lines.size(); ++i)
237 {
238 // Due to splitting on '\n' the last line should be empty.
239 if (i == lines.size() - 1)
240 {
241 if (!lines[i].empty())
242 {
243 fprintf(stderr, "ParseProcMaps: Last line not empty");
244 return false;
245 }
246 break;
247 }
248
249 MappedMemoryRegion region;
250 const char *line = lines[i].c_str();
251 char permissions[5] = {'\0'}; // Ensure NUL-terminated string.
252 uint8_t dev_major = 0;
253 uint8_t dev_minor = 0;
254 long inode = 0;
255 int path_index = 0;
256
257 // Sample format from man 5 proc:
258 //
259 // address perms offset dev inode pathname
260 // 08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm
261 //
262 // The final %n term captures the offset in the input string, which is used
263 // to determine the path name. It *does not* increment the return value.
264 // Refer to man 3 sscanf for details.
265 if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4c %llx %hhx:%hhx %ld %n", ®ion.start,
266 ®ion.end, permissions, ®ion.offset, &dev_major, &dev_minor, &inode,
267 &path_index) < 7)
268 {
269 fprintf(stderr, "ParseProcMaps: sscanf failed for line: %s\n", line);
270 return false;
271 }
272
273 region.permissions = 0;
274
275 if (permissions[0] == 'r')
276 region.permissions |= MappedMemoryRegion::READ;
277 else if (permissions[0] != '-')
278 return false;
279
280 if (permissions[1] == 'w')
281 region.permissions |= MappedMemoryRegion::WRITE;
282 else if (permissions[1] != '-')
283 return false;
284
285 if (permissions[2] == 'x')
286 region.permissions |= MappedMemoryRegion::EXECUTE;
287 else if (permissions[2] != '-')
288 return false;
289
290 if (permissions[3] == 'p')
291 region.permissions |= MappedMemoryRegion::PRIVATE;
292 else if (permissions[3] != 's' && permissions[3] != 'S') // Shared memory.
293 return false;
294
295 // Pushing then assigning saves us a string copy.
296 regions.push_back(region);
297 regions.back().path.assign(line + path_index);
298 }
299
300 regions_out->swap(regions);
301 return true;
302 }
303
304 // Set the base address for each memory region by reading ELF headers in
305 // process memory.
306 void SetBaseAddressesForMemoryRegions(MemoryRegionArray ®ions)
307 {
308 int mem_fd(HANDLE_EINTR(open("/proc/self/mem", O_RDONLY | O_CLOEXEC)));
309 if (mem_fd == -1)
310 return;
311
312 auto safe_memcpy = [&mem_fd](void *dst, uintptr_t src, size_t size) {
313 return HANDLE_EINTR(pread(mem_fd, dst, size, src)) == ssize_t(size);
314 };
315
316 uintptr_t cur_base = 0;
317 for (MappedMemoryRegion &r : regions)
318 {
319 ElfW(Ehdr) ehdr;
320 static_assert(SELFMAG <= sizeof(ElfW(Ehdr)), "SELFMAG too large");
321 if ((r.permissions & MappedMemoryRegion::READ) &&
322 safe_memcpy(&ehdr, r.start, sizeof(ElfW(Ehdr))) &&
323 memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0)
324 {
325 switch (ehdr.e_type)
326 {
327 case ET_EXEC:
328 cur_base = 0;
329 break;
330 case ET_DYN:
331 // Find the segment containing file offset 0. This will correspond
332 // to the ELF header that we just read. Normally this will have
333 // virtual address 0, but this is not guaranteed. We must subtract
334 // the virtual address from the address where the ELF header was
335 // mapped to get the base address.
336 //
337 // If we fail to find a segment for file offset 0, use the address
338 // of the ELF header as the base address.
339 cur_base = r.start;
340 for (unsigned i = 0; i != ehdr.e_phnum; ++i)
341 {
342 ElfW(Phdr) phdr;
343 if (safe_memcpy(&phdr, r.start + ehdr.e_phoff + i * sizeof(phdr),
344 sizeof(phdr)) &&
345 phdr.p_type == PT_LOAD && phdr.p_offset == 0)
346 {
347 cur_base = r.start - phdr.p_vaddr;
348 break;
349 }
350 }
351 break;
352 default:
353 // ET_REL or ET_CORE. These aren't directly executable, so they
354 // don't affect the base address.
355 break;
356 }
357 }
358
359 r.base = cur_base;
360 }
361
362 close(mem_fd);
363 }
364
365 // Parses /proc/self/maps in order to compile a list of all object file names
366 // for the modules that are loaded in the current process.
367 // Returns true on success.
368 bool CacheMemoryRegions(MemoryRegionArray ®ions)
369 {
370 // Reads /proc/self/maps.
371 std::string contents;
372 if (!ReadProcMaps(&contents))
373 {
374 fprintf(stderr, "CacheMemoryRegions: Failed to read /proc/self/maps\n");
375 return false;
376 }
377
378 // Parses /proc/self/maps.
379 if (!ParseProcMaps(contents, ®ions))
380 {
381 fprintf(stderr, "CacheMemoryRegions: Failed to parse the contents of /proc/self/maps\n");
382 return false;
383 }
384
385 SetBaseAddressesForMemoryRegions(regions);
386 return true;
387 }
388
389 constexpr size_t kAddr2LineMaxParameters = 50;
390 using Addr2LineCommandLine = angle::FixedVector<const char *, kAddr2LineMaxParameters>;
391
392 void CallAddr2Line(const Addr2LineCommandLine &commandLine)
393 {
394 pid_t pid = fork();
395 if (pid < 0)
396 {
397 std::cerr << "Error: Failed to fork()" << std::endl;
398 }
399 else if (pid > 0)
400 {
401 int status;
402 waitpid(pid, &status, 0);
403 // Ignore the status, since we aren't going to handle it anyway.
404 }
405 else
406 {
407 // Child process executes addr2line
408 //
409 // See comment in test_utils_posix.cpp::PosixProcess regarding const_cast.
410 execvp(commandLine[0], const_cast<char *const *>(commandLine.data()));
411 std::cerr << "Error: Child process returned from exevc()" << std::endl;
412 _exit(EXIT_FAILURE); // exec never returns
413 }
414 }
415
416 constexpr size_t kMaxAddressLen = 1024;
417 using AddressBuffer = angle::FixedVector<char, kMaxAddressLen>;
418
419 const char *ResolveAddress(const MemoryRegionArray ®ions,
420 const std::string &resolvedModule,
421 const char *address,
422 AddressBuffer &buffer)
423 {
424 size_t lastModuleSlash = resolvedModule.rfind('/');
425 ASSERT(lastModuleSlash != std::string::npos);
426 std::string baseModule = resolvedModule.substr(lastModuleSlash);
427
428 for (const MappedMemoryRegion ®ion : regions)
429 {
430 size_t pathSlashPos = region.path.rfind('/');
431 if (pathSlashPos != std::string::npos && region.path.substr(pathSlashPos) == baseModule)
432 {
433 uintptr_t scannedAddress;
434 int scanReturn = sscanf(address, "%" SCNxPTR, &scannedAddress);
435 ASSERT(scanReturn == 1);
436 scannedAddress -= region.base;
437 char printBuffer[255] = {};
438 size_t scannedSize = sprintf(printBuffer, "0x%" PRIXPTR, scannedAddress);
439 size_t bufferSize = buffer.size();
440 buffer.resize(bufferSize + scannedSize + 1, 0);
441 memcpy(&buffer[bufferSize], printBuffer, scannedSize);
442 return &buffer[bufferSize];
443 }
444 }
445
446 return address;
447 }
448 // This is only required when the current CWD does not match the initial CWD and could be replaced
449 // by storing the initial CWD state globally. It is only changed in vulkan_icd.cpp.
450 std::string RemoveOverlappingPath(const std::string &resolvedModule)
451 {
452 // Build path from CWD in case CWD matches executable directory
453 // but relative paths are from initial cwd.
454 const Optional<std::string> &cwd = angle::GetCWD();
455 if (!cwd.valid())
456 {
457 std::cerr << "Error getting CWD to print the backtrace." << std::endl;
458 return resolvedModule;
459 }
460 else
461 {
462 std::string absolutePath = cwd.value();
463 size_t lastPathSepLoc = resolvedModule.find_last_of(GetPathSeparator());
464 std::string relativePath = resolvedModule.substr(0, lastPathSepLoc);
465
466 // Remove "." from the relativePath path
467 // For example: ./out/LinuxDebug/angle_perftests
468 size_t pos = relativePath.find('.');
469 if (pos != std::string::npos)
470 {
471 // If found then erase it from string
472 relativePath.erase(pos, 1);
473 }
474
475 // Remove the overlapping relative path from the CWD so we can build the full
476 // absolute path.
477 // For example:
478 // absolutePath = /home/timvp/code/angle/out/LinuxDebug
479 // relativePath = /out/LinuxDebug
480 pos = absolutePath.find(relativePath);
481 if (pos != std::string::npos)
482 {
483 // If found then erase it from string
484 absolutePath.erase(pos, relativePath.length());
485 }
486 return absolutePath + GetPathSeparator() + resolvedModule;
487 }
488 }
489 } // anonymous namespace
490 # endif // defined(ANGLE_HAS_ADDR2LINE)
491
492 void PrintStackBacktrace()
493 {
494 printf("Backtrace:\n");
495
496 void *stack[64];
497 const int count = backtrace(stack, ArraySize(stack));
498 char **symbols = backtrace_symbols(stack, count);
499
500 # if defined(ANGLE_HAS_ADDR2LINE)
501
502 MemoryRegionArray regions;
503 CacheMemoryRegions(regions);
504
505 // Child process executes addr2line
506 constexpr size_t kAddr2LineFixedParametersCount = 6;
507 Addr2LineCommandLine commandLineArgs = {
508 "addr2line", "-s", "-p", "-f", "-C", "-e",
509 };
510 const char *currentModule = "";
511 std::string resolvedModule;
512 AddressBuffer addressBuffer;
513
514 for (int i = 0; i < count; i++)
515 {
516 char *symbol = symbols[i];
517
518 // symbol looks like the following:
519 //
520 // path/to/module(+localAddress) [address]
521 //
522 // If module is not an absolute path, it needs to be resolved.
523
524 char *module = symbol;
525 char *address = strchr(symbol, '[') + 1;
526
527 *strchr(module, '(') = 0;
528 *strchr(address, ']') = 0;
529
530 // If module is the same as last, continue batching addresses. If commandLineArgs has
531 // reached its capacity however, make the call to addr2line already. Note that there should
532 // be one entry left for the terminating nullptr at the end of the command line args.
533 if (strcmp(module, currentModule) == 0 &&
534 commandLineArgs.size() + 1 < commandLineArgs.max_size())
535 {
536 commandLineArgs.push_back(
537 ResolveAddress(regions, resolvedModule, address, addressBuffer));
538 continue;
539 }
540
541 // If there's a command batched, execute it before modifying currentModule (a pointer to
542 // which is stored in the command line args).
543 if (currentModule[0] != 0)
544 {
545 commandLineArgs.push_back(nullptr);
546 CallAddr2Line(commandLineArgs);
547 addressBuffer.clear();
548 }
549
550 // Reset the command line and remember this module as the current.
551 resolvedModule = currentModule = module;
552 commandLineArgs.resize(kAddr2LineFixedParametersCount);
553
554 // First check if the a relative path simply resolved to an absolute one from cwd,
555 // for abolute paths this resolves symlinks.
556 char *realPath = realpath(resolvedModule.c_str(), NULL);
557 if (realPath)
558 {
559 resolvedModule = std::string(realPath);
560 free(realPath);
561 }
562 // We need an absolute path to get to the executable and all of the various shared objects,
563 // but the caller may have used a relative path to launch the executable, so build one up if
564 // we don't see a leading '/'.
565 else if (resolvedModule.at(0) != GetPathSeparator())
566 {
567 // For some modules we receive a relative path from the build directory (executable
568 // directory) instead of the execution directory (current directory). This happens
569 // for libVkLayer_khronos_validation.so. If realpath fails to create an absolute
570 // path, try constructing one from the build directory.
571 // This will resolve paths like `angledata/../libVkLayer_khronos_validation.so` to
572 // `/home/user/angle/out/Debug/libVkLayer_khronos_validation.so`
573 std::string pathFromExecDir =
574 GetExecutableDirectory() + GetPathSeparator() + resolvedModule;
575 realPath = realpath(pathFromExecDir.c_str(), NULL);
576 if (realPath)
577 {
578 resolvedModule = std::string(realPath);
579 free(realPath);
580 }
581 else
582 {
583 // Try removing overlapping path as a last resort.
584 // This will resolve `./out/Debug/angle_end2end_tests` to
585 // `/home/user/angle/out/Debug/angle_end2end_tests` when CWD is
586 // `/home/user/angle/out/Debug`, which is caused by ScopedVkLoaderEnvironment.
587 // This is required for printing traces during vk::Renderer init.
588 // Since we do not store the initial CWD globally we need to reconstruct here
589 // by removing the overlapping path.
590 std::string removeOverlappingPath = RemoveOverlappingPath(resolvedModule);
591 realPath = realpath(removeOverlappingPath.c_str(), NULL);
592 if (realPath)
593 {
594 resolvedModule = std::string(realPath);
595 free(realPath);
596 }
597 else
598 {
599 WARN() << "Could not resolve path for module with relative path "
600 << resolvedModule;
601 }
602 }
603 }
604 else
605 {
606 WARN() << "Could not resolve path for module with absolute path " << resolvedModule;
607 }
608
609 const char *resolvedAddress =
610 ResolveAddress(regions, resolvedModule, address, addressBuffer);
611
612 commandLineArgs.push_back(resolvedModule.c_str());
613 commandLineArgs.push_back(resolvedAddress);
614 }
615
616 // Call addr2line for the last batch of addresses.
617 if (currentModule[0] != 0)
618 {
619 commandLineArgs.push_back(nullptr);
620 CallAddr2Line(commandLineArgs);
621 }
622 # else
623 for (int i = 0; i < count; i++)
624 {
625 Dl_info info;
626 if (dladdr(stack[i], &info) && info.dli_sname)
627 {
628 // Make sure this is large enough to hold the fully demangled names, otherwise we could
629 // segault/hang here. For example, Vulkan validation layer errors can be deep enough
630 // into the stack that very large symbol names are generated.
631 char demangled[4096];
632 size_t len = ArraySize(demangled);
633 int ok;
634
635 abi::__cxa_demangle(info.dli_sname, demangled, &len, &ok);
636 if (ok == 0)
637 {
638 printf(" %s\n", demangled);
639 continue;
640 }
641 }
642 printf(" %s\n", symbols[i]);
643 }
644 # endif // defined(ANGLE_HAS_ADDR2LINE)
645 }
646
647 static void Handler(int sig)
648 {
649 printf("\nSignal %d [%s]:\n", sig, strsignal(sig));
650
651 if (gCrashHandlerCallback)
652 {
653 (*gCrashHandlerCallback)();
654 }
655
656 PrintStackBacktrace();
657
658 // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
659 _Exit(sig);
660 }
661
662 # endif // defined(ANGLE_PLATFORM_APPLE)
663
664 static constexpr int kSignals[] = {
665 SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP,
666 };
667
668 void InitCrashHandler(CrashCallback *callback)
669 {
670 gCrashHandlerCallback = callback;
671 for (int sig : kSignals)
672 {
673 // Register our signal handler unless something's already done so (e.g. catchsegv).
674 void (*prev)(int) = signal(sig, Handler);
675 if (prev != SIG_DFL)
676 {
677 signal(sig, prev);
678 }
679 }
680 }
681
682 void TerminateCrashHandler()
683 {
684 gCrashHandlerCallback = nullptr;
685 for (int sig : kSignals)
686 {
687 void (*prev)(int) = signal(sig, SIG_DFL);
688 if (prev != Handler && prev != SIG_DFL)
689 {
690 signal(sig, prev);
691 }
692 }
693 }
694
695 #endif // defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_FUCHSIA)
696
697 } // namespace angle
698