• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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", &region.start,
266                    &region.end, permissions, &region.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 &regions)
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 &regions)
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, &regions))
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 &regions,
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 &region : 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