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