• 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], 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", &region.start,
263                    &region.end, permissions, &region.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 &regions)
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 &regions)
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, &regions))
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 &regions,
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 &region : 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