Home | History | Annotate | Download | only in symbolize
      1 // Copyright (c) 2006, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 //
     30 // Author: Satoru Takabayashi
     31 // Stack-footprint reduction work done by Raksit Ashok
     32 //
     33 // Implementation note:
     34 //
     35 // We don't use heaps but only use stacks.  We want to reduce the
     36 // stack consumption so that the symbolizer can run on small stacks.
     37 //
     38 // Here are some numbers collected with GCC 4.1.0 on x86:
     39 // - sizeof(Elf32_Sym)  = 16
     40 // - sizeof(Elf32_Shdr) = 40
     41 // - sizeof(Elf64_Sym)  = 24
     42 // - sizeof(Elf64_Shdr) = 64
     43 //
     44 // This implementation is intended to be async-signal-safe but uses
     45 // some functions which are not guaranteed to be so, such as memchr()
     46 // and memmove().  We assume they are async-signal-safe.
     47 //
     48 
     49 #include "utilities.h"
     50 
     51 #if defined(HAVE_SYMBOLIZE)
     52 
     53 #include <limits>
     54 
     55 #include "symbolize.h"
     56 #include "demangle.h"
     57 
     58 _START_GOOGLE_NAMESPACE_
     59 
     60 // We don't use assert() since it's not guaranteed to be
     61 // async-signal-safe.  Instead we define a minimal assertion
     62 // macro. So far, we don't need pretty printing for __FILE__, etc.
     63 
     64 // A wrapper for abort() to make it callable in ? :.
     65 static int AssertFail() {
     66   abort();
     67   return 0;  // Should not reach.
     68 }
     69 
     70 #define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
     71 
     72 static SymbolizeCallback g_symbolize_callback = NULL;
     73 void InstallSymbolizeCallback(SymbolizeCallback callback) {
     74   g_symbolize_callback = callback;
     75 }
     76 
     77 // This function wraps the Demangle function to provide an interface
     78 // where the input symbol is demangled in-place.
     79 // To keep stack consumption low, we would like this function to not
     80 // get inlined.
     81 static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size) {
     82   char demangled[256];  // Big enough for sane demangled symbols.
     83   if (Demangle(out, demangled, sizeof(demangled))) {
     84     // Demangling succeeded. Copy to out if the space allows.
     85     int len = strlen(demangled);
     86     if (len + 1 <= out_size) {  // +1 for '\0'.
     87       SAFE_ASSERT(len < sizeof(demangled));
     88       memmove(out, demangled, len + 1);
     89     }
     90   }
     91 }
     92 
     93 _END_GOOGLE_NAMESPACE_
     94 
     95 #if defined(__ELF__)
     96 
     97 #include <dlfcn.h>
     98 #include <elf.h>
     99 #include <errno.h>
    100 #include <fcntl.h>
    101 #include <limits.h>
    102 #include <link.h>  // For ElfW() macro.
    103 #include <stdint.h>
    104 #include <stdio.h>
    105 #include <stdlib.h>
    106 #include <stddef.h>
    107 #include <string.h>
    108 #include <sys/stat.h>
    109 #include <sys/types.h>
    110 #include <unistd.h>
    111 
    112 #include "symbolize.h"
    113 #include "config.h"
    114 #include "glog/raw_logging.h"
    115 
    116 // Re-runs fn until it doesn't cause EINTR.
    117 #define NO_INTR(fn)   do {} while ((fn) < 0 && errno == EINTR)
    118 
    119 _START_GOOGLE_NAMESPACE_
    120 
    121 // Read up to "count" bytes from file descriptor "fd" into the buffer
    122 // starting at "buf" while handling short reads and EINTR.  On
    123 // success, return the number of bytes read.  Otherwise, return -1.
    124 static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) {
    125   SAFE_ASSERT(fd >= 0);
    126   SAFE_ASSERT(count >= 0 && count <= std::numeric_limits<ssize_t>::max());
    127   char *buf0 = reinterpret_cast<char *>(buf);
    128   ssize_t num_bytes = 0;
    129   while (num_bytes < count) {
    130     ssize_t len;
    131     NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
    132     if (len < 0) {  // There was an error other than EINTR.
    133       return -1;
    134     }
    135     if (len == 0) {  // Reached EOF.
    136       break;
    137     }
    138     num_bytes += len;
    139   }
    140   SAFE_ASSERT(num_bytes <= count);
    141   return num_bytes;
    142 }
    143 
    144 // Read up to "count" bytes from "offset" in the file pointed by file
    145 // descriptor "fd" into the buffer starting at "buf".  On success,
    146 // return the number of bytes read.  Otherwise, return -1.
    147 static ssize_t ReadFromOffset(const int fd, void *buf,
    148                               const size_t count, const off_t offset) {
    149   off_t off = lseek(fd, offset, SEEK_SET);
    150   if (off == (off_t)-1) {
    151     return -1;
    152   }
    153   return ReadPersistent(fd, buf, count);
    154 }
    155 
    156 // Try reading exactly "count" bytes from "offset" bytes in a file
    157 // pointed by "fd" into the buffer starting at "buf" while handling
    158 // short reads and EINTR.  On success, return true. Otherwise, return
    159 // false.
    160 static bool ReadFromOffsetExact(const int fd, void *buf,
    161                                 const size_t count, const off_t offset) {
    162   ssize_t len = ReadFromOffset(fd, buf, count, offset);
    163   return len == count;
    164 }
    165 
    166 // Returns elf_header.e_type if the file pointed by fd is an ELF binary.
    167 static int FileGetElfType(const int fd) {
    168   ElfW(Ehdr) elf_header;
    169   if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
    170     return -1;
    171   }
    172   if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) {
    173     return -1;
    174   }
    175   return elf_header.e_type;
    176 }
    177 
    178 // Read the section headers in the given ELF binary, and if a section
    179 // of the specified type is found, set the output to this section header
    180 // and return true.  Otherwise, return false.
    181 // To keep stack consumption low, we would like this function to not get
    182 // inlined.
    183 static ATTRIBUTE_NOINLINE bool
    184 GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const off_t sh_offset,
    185                        ElfW(Word) type, ElfW(Shdr) *out) {
    186   // Read at most 16 section headers at a time to save read calls.
    187   ElfW(Shdr) buf[16];
    188   for (int i = 0; i < sh_num;) {
    189     const ssize_t num_bytes_left = (sh_num - i) * sizeof(buf[0]);
    190     const ssize_t num_bytes_to_read =
    191         (sizeof(buf) > num_bytes_left) ? num_bytes_left : sizeof(buf);
    192     const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read,
    193                                        sh_offset + i * sizeof(buf[0]));
    194     SAFE_ASSERT(len % sizeof(buf[0]) == 0);
    195     const ssize_t num_headers_in_buf = len / sizeof(buf[0]);
    196     SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0]));
    197     for (int j = 0; j < num_headers_in_buf; ++j) {
    198       if (buf[j].sh_type == type) {
    199         *out = buf[j];
    200         return true;
    201       }
    202     }
    203     i += num_headers_in_buf;
    204   }
    205   return false;
    206 }
    207 
    208 // There is no particular reason to limit section name to 63 characters,
    209 // but there has (as yet) been no need for anything longer either.
    210 const int kMaxSectionNameLen = 64;
    211 
    212 // name_len should include terminating '\0'.
    213 bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
    214                             ElfW(Shdr) *out) {
    215   ElfW(Ehdr) elf_header;
    216   if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
    217     return false;
    218   }
    219 
    220   ElfW(Shdr) shstrtab;
    221   off_t shstrtab_offset = (elf_header.e_shoff +
    222                            elf_header.e_shentsize * elf_header.e_shstrndx);
    223   if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) {
    224     return false;
    225   }
    226 
    227   for (int i = 0; i < elf_header.e_shnum; ++i) {
    228     off_t section_header_offset = (elf_header.e_shoff +
    229                                    elf_header.e_shentsize * i);
    230     if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
    231       return false;
    232     }
    233     char header_name[kMaxSectionNameLen];
    234     if (sizeof(header_name) < name_len) {
    235       RAW_LOG(WARNING, "Section name '%s' is too long (%"PRIuS"); "
    236               "section will not be found (even if present).", name, name_len);
    237       // No point in even trying.
    238       return false;
    239     }
    240     off_t name_offset = shstrtab.sh_offset + out->sh_name;
    241     ssize_t n_read = ReadFromOffset(fd, &header_name, name_len, name_offset);
    242     if (n_read == -1) {
    243       return false;
    244     } else if (n_read != name_len) {
    245       // Short read -- name could be at end of file.
    246       continue;
    247     }
    248     if (memcmp(header_name, name, name_len) == 0) {
    249       return true;
    250     }
    251   }
    252   return false;
    253 }
    254 
    255 // Read a symbol table and look for the symbol containing the
    256 // pc. Iterate over symbols in a symbol table and look for the symbol
    257 // containing "pc".  On success, return true and write the symbol name
    258 // to out.  Otherwise, return false.
    259 // To keep stack consumption low, we would like this function to not get
    260 // inlined.
    261 static ATTRIBUTE_NOINLINE bool
    262 FindSymbol(uint64_t pc, const int fd, char *out, int out_size,
    263            uint64_t symbol_offset, const ElfW(Shdr) *strtab,
    264            const ElfW(Shdr) *symtab) {
    265   if (symtab == NULL) {
    266     return false;
    267   }
    268   const int num_symbols = symtab->sh_size / symtab->sh_entsize;
    269   for (int i = 0; i < num_symbols;) {
    270     off_t offset = symtab->sh_offset + i * symtab->sh_entsize;
    271 
    272     // If we are reading Elf64_Sym's, we want to limit this array to
    273     // 32 elements (to keep stack consumption low), otherwise we can
    274     // have a 64 element Elf32_Sym array.
    275 #if __WORDSIZE == 64
    276 #define NUM_SYMBOLS 32
    277 #else
    278 #define NUM_SYMBOLS 64
    279 #endif
    280 
    281     // Read at most NUM_SYMBOLS symbols at once to save read() calls.
    282     ElfW(Sym) buf[NUM_SYMBOLS];
    283     const ssize_t len = ReadFromOffset(fd, &buf, sizeof(buf), offset);
    284     SAFE_ASSERT(len % sizeof(buf[0]) == 0);
    285     const ssize_t num_symbols_in_buf = len / sizeof(buf[0]);
    286     SAFE_ASSERT(num_symbols_in_buf <= sizeof(buf)/sizeof(buf[0]));
    287     for (int j = 0; j < num_symbols_in_buf; ++j) {
    288       const ElfW(Sym)& symbol = buf[j];
    289       uint64_t start_address = symbol.st_value;
    290       start_address += symbol_offset;
    291       uint64_t end_address = start_address + symbol.st_size;
    292       if (symbol.st_value != 0 &&  // Skip null value symbols.
    293           symbol.st_shndx != 0 &&  // Skip undefined symbols.
    294           start_address <= pc && pc < end_address) {
    295         ssize_t len1 = ReadFromOffset(fd, out, out_size,
    296                                       strtab->sh_offset + symbol.st_name);
    297         if (len1 <= 0 || memchr(out, '\0', out_size) == NULL) {
    298           return false;
    299         }
    300         return true;  // Obtained the symbol name.
    301       }
    302     }
    303     i += num_symbols_in_buf;
    304   }
    305   return false;
    306 }
    307 
    308 // Get the symbol name of "pc" from the file pointed by "fd".  Process
    309 // both regular and dynamic symbol tables if necessary.  On success,
    310 // write the symbol name to "out" and return true.  Otherwise, return
    311 // false.
    312 static bool GetSymbolFromObjectFile(const int fd, uint64_t pc,
    313                                     char *out, int out_size,
    314                                     uint64_t map_start_address) {
    315   // Read the ELF header.
    316   ElfW(Ehdr) elf_header;
    317   if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
    318     return false;
    319   }
    320 
    321   uint64_t symbol_offset = 0;
    322   if (elf_header.e_type == ET_DYN) {  // DSO needs offset adjustment.
    323     symbol_offset = map_start_address;
    324   }
    325 
    326   ElfW(Shdr) symtab, strtab;
    327 
    328   // Consult a regular symbol table first.
    329   if (!GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
    330                               SHT_SYMTAB, &symtab)) {
    331     return false;
    332   }
    333   if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
    334                            symtab.sh_link * sizeof(symtab))) {
    335     return false;
    336   }
    337   if (FindSymbol(pc, fd, out, out_size, symbol_offset,
    338                  &strtab, &symtab)) {
    339     return true;  // Found the symbol in a regular symbol table.
    340   }
    341 
    342   // If the symbol is not found, then consult a dynamic symbol table.
    343   if (!GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
    344                               SHT_DYNSYM, &symtab)) {
    345     return false;
    346   }
    347   if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
    348                            symtab.sh_link * sizeof(symtab))) {
    349     return false;
    350   }
    351   if (FindSymbol(pc, fd, out, out_size, symbol_offset,
    352                  &strtab, &symtab)) {
    353     return true;  // Found the symbol in a dynamic symbol table.
    354   }
    355 
    356   return false;
    357 }
    358 
    359 namespace {
    360 // Thin wrapper around a file descriptor so that the file descriptor
    361 // gets closed for sure.
    362 struct FileDescriptor {
    363   const int fd_;
    364   explicit FileDescriptor(int fd) : fd_(fd) {}
    365   ~FileDescriptor() {
    366     if (fd_ >= 0) {
    367       NO_INTR(close(fd_));
    368     }
    369   }
    370   int get() { return fd_; }
    371 
    372  private:
    373   explicit FileDescriptor(const FileDescriptor&);
    374   void operator=(const FileDescriptor&);
    375 };
    376 
    377 // Helper class for reading lines from file.
    378 //
    379 // Note: we don't use ProcMapsIterator since the object is big (it has
    380 // a 5k array member) and uses async-unsafe functions such as sscanf()
    381 // and snprintf().
    382 class LineReader {
    383  public:
    384   explicit LineReader(int fd, char *buf, int buf_len) : fd_(fd),
    385     buf_(buf), buf_len_(buf_len), bol_(buf), eol_(buf), eod_(buf) {
    386   }
    387 
    388   // Read '\n'-terminated line from file.  On success, modify "bol"
    389   // and "eol", then return true.  Otherwise, return false.
    390   //
    391   // Note: if the last line doesn't end with '\n', the line will be
    392   // dropped.  It's an intentional behavior to make the code simple.
    393   bool ReadLine(const char **bol, const char **eol) {
    394     if (BufferIsEmpty()) {  // First time.
    395       const ssize_t num_bytes = ReadPersistent(fd_, buf_, buf_len_);
    396       if (num_bytes <= 0) {  // EOF or error.
    397         return false;
    398       }
    399       eod_ = buf_ + num_bytes;
    400       bol_ = buf_;
    401     } else {
    402       bol_ = eol_ + 1;  // Advance to the next line in the buffer.
    403       SAFE_ASSERT(bol_ <= eod_);  // "bol_" can point to "eod_".
    404       if (!HasCompleteLine()) {
    405         const int incomplete_line_length = eod_ - bol_;
    406         // Move the trailing incomplete line to the beginning.
    407         memmove(buf_, bol_, incomplete_line_length);
    408         // Read text from file and append it.
    409         char * const append_pos = buf_ + incomplete_line_length;
    410         const int capacity_left = buf_len_ - incomplete_line_length;
    411         const ssize_t num_bytes = ReadPersistent(fd_, append_pos,
    412                                                  capacity_left);
    413         if (num_bytes <= 0) {  // EOF or error.
    414           return false;
    415         }
    416         eod_ = append_pos + num_bytes;
    417         bol_ = buf_;
    418       }
    419     }
    420     eol_ = FindLineFeed();
    421     if (eol_ == NULL) {  // '\n' not found.  Malformed line.
    422       return false;
    423     }
    424     *eol_ = '\0';  // Replace '\n' with '\0'.
    425 
    426     *bol = bol_;
    427     *eol = eol_;
    428     return true;
    429   }
    430 
    431   // Beginning of line.
    432   const char *bol() {
    433     return bol_;
    434   }
    435 
    436   // End of line.
    437   const char *eol() {
    438     return eol_;
    439   }
    440 
    441  private:
    442   explicit LineReader(const LineReader&);
    443   void operator=(const LineReader&);
    444 
    445   char *FindLineFeed() {
    446     return reinterpret_cast<char *>(memchr(bol_, '\n', eod_ - bol_));
    447   }
    448 
    449   bool BufferIsEmpty() {
    450     return buf_ == eod_;
    451   }
    452 
    453   bool HasCompleteLine() {
    454     return !BufferIsEmpty() && FindLineFeed() != NULL;
    455   }
    456 
    457   const int fd_;
    458   char * const buf_;
    459   const int buf_len_;
    460   char *bol_;
    461   char *eol_;
    462   const char *eod_;  // End of data in "buf_".
    463 };
    464 }  // namespace
    465 
    466 // Place the hex number read from "start" into "*hex".  The pointer to
    467 // the first non-hex character or "end" is returned.
    468 static char *GetHex(const char *start, const char *end, uint64_t *hex) {
    469   *hex = 0;
    470   const char *p;
    471   for (p = start; p < end; ++p) {
    472     int ch = *p;
    473     if ((ch >= '0' && ch <= '9') ||
    474         (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
    475       *hex = (*hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9);
    476     } else {  // Encountered the first non-hex character.
    477       break;
    478     }
    479   }
    480   SAFE_ASSERT(p <= end);
    481   return const_cast<char *>(p);
    482 }
    483 
    484 // Search for the object file (from /proc/self/maps) that contains
    485 // the specified pc. If found, open this file and return the file handle,
    486 // and also set start_address to the start address of where this object
    487 // file is mapped to in memory. Otherwise, return -1.
    488 static ATTRIBUTE_NOINLINE int
    489 OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
    490                                              uint64_t &start_address) {
    491   int object_fd;
    492 
    493   // Open /proc/self/maps.
    494   int maps_fd;
    495   NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
    496   FileDescriptor wrapped_maps_fd(maps_fd);
    497   if (wrapped_maps_fd.get() < 0) {
    498     return -1;
    499   }
    500 
    501   // Iterate over maps and look for the map containing the pc.  Then
    502   // look into the symbol tables inside.
    503   char buf[1024];  // Big enough for line of sane /proc/self/maps
    504   LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf));
    505   while (true) {
    506     const char *cursor;
    507     const char *eol;
    508     if (!reader.ReadLine(&cursor, &eol)) {  // EOF or malformed line.
    509       return -1;
    510     }
    511 
    512     // Start parsing line in /proc/self/maps.  Here is an example:
    513     //
    514     // 08048000-0804c000 r-xp 00000000 08:01 2142121    /bin/cat
    515     //
    516     // We want start address (08048000), end address (0804c000), flags
    517     // (r-xp) and file name (/bin/cat).
    518 
    519     // Read start address.
    520     cursor = GetHex(cursor, eol, &start_address);
    521     if (cursor == eol || *cursor != '-') {
    522       return -1;  // Malformed line.
    523     }
    524     ++cursor;  // Skip '-'.
    525 
    526     // Read end address.
    527     uint64_t end_address;
    528     cursor = GetHex(cursor, eol, &end_address);
    529     if (cursor == eol || *cursor != ' ') {
    530       return -1;  // Malformed line.
    531     }
    532     ++cursor;  // Skip ' '.
    533 
    534     // Check start and end addresses.
    535     if (!(start_address <= pc && pc < end_address)) {
    536       continue;  // We skip this map.  PC isn't in this map.
    537     }
    538 
    539     // Read flags.  Skip flags until we encounter a space or eol.
    540     const char * const flags_start = cursor;
    541     while (cursor < eol && *cursor != ' ') {
    542       ++cursor;
    543     }
    544     // We expect at least four letters for flags (ex. "r-xp").
    545     if (cursor == eol || cursor < flags_start + 4) {
    546       return -1;  // Malformed line.
    547     }
    548 
    549     // Check flags.  We are only interested in "r-x" maps.
    550     if (memcmp(flags_start, "r-x", 3) != 0) {  // Not a "r-x" map.
    551       continue;  // We skip this map.
    552     }
    553     ++cursor;  // Skip ' '.
    554 
    555     // Skip to file name.  "cursor" now points to file offset.  We need to
    556     // skip at least three spaces for file offset, dev, and inode.
    557     int num_spaces = 0;
    558     while (cursor < eol) {
    559       if (*cursor == ' ') {
    560         ++num_spaces;
    561       } else if (num_spaces >= 3) {
    562         // The first non-space character after  skipping three spaces
    563         // is the beginning of the file name.
    564         break;
    565       }
    566       ++cursor;
    567     }
    568     if (cursor == eol) {
    569       return -1;  // Malformed line.
    570     }
    571 
    572     // Finally, "cursor" now points to file name of our interest.
    573     NO_INTR(object_fd = open(cursor, O_RDONLY));
    574     if (object_fd < 0) {
    575       return -1;
    576     }
    577     return object_fd;
    578   }
    579 }
    580 
    581 // The implementation of our symbolization routine.  If it
    582 // successfully finds the symbol containing "pc" and obtains the
    583 // symbol name, returns true and write the symbol name to "out".
    584 // Otherwise, returns false. If Callback function is installed via
    585 // InstallSymbolizeCallback(), the function is also called in this function,
    586 // and "out" is used as its output.
    587 // To keep stack consumption low, we would like this function to not
    588 // get inlined.
    589 static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
    590                                                     int out_size) {
    591   uint64_t pc0 = reinterpret_cast<uintptr_t>(pc);
    592   uint64_t start_address = 0;
    593 
    594   int object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0,
    595                                                                start_address);
    596   if (object_fd == -1) {
    597     return false;
    598   }
    599   FileDescriptor wrapped_object_fd(object_fd);
    600   int elf_type = FileGetElfType(wrapped_object_fd.get());
    601   if (elf_type == -1) {
    602     return false;
    603   }
    604   if (g_symbolize_callback) {
    605     // Run the call back if it's installed.
    606     // Note: relocation (and much of the rest of this code) will be
    607     // wrong for prelinked shared libraries and PIE executables.
    608     uint64 relocation = (elf_type == ET_DYN) ? start_address : 0;
    609     int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
    610                                                  pc, out, out_size,
    611                                                  relocation);
    612     if (num_bytes_written > 0) {
    613       out += num_bytes_written;
    614       out_size -= num_bytes_written;
    615     }
    616   }
    617   if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
    618                                out, out_size, start_address)) {
    619     return false;
    620   }
    621 
    622   // Symbolization succeeded.  Now we try to demangle the symbol.
    623   DemangleInplace(out, out_size);
    624   return true;
    625 }
    626 
    627 _END_GOOGLE_NAMESPACE_
    628 
    629 #elif defined(OS_MACOSX) && defined(HAVE_DLADDR)
    630 
    631 #include <dlfcn.h>
    632 #include <string.h>
    633 
    634 _START_GOOGLE_NAMESPACE_
    635 
    636 static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
    637                                                     int out_size) {
    638   Dl_info info;
    639   if (dladdr(pc, &info)) {
    640     if (strlen(info.dli_sname) < out_size) {
    641       strcpy(out, info.dli_sname);
    642       // Symbolization succeeded.  Now we try to demangle the symbol.
    643       DemangleInplace(out, out_size);
    644       return true;
    645     }
    646   }
    647   return false;
    648 }
    649 
    650 _END_GOOGLE_NAMESPACE_
    651 
    652 #else
    653 # error BUG: HAVE_SYMBOLIZE was wrongly set
    654 #endif
    655 
    656 _START_GOOGLE_NAMESPACE_
    657 
    658 bool Symbolize(void *pc, char *out, int out_size) {
    659   SAFE_ASSERT(out_size >= 0);
    660   return SymbolizeAndDemangle(pc, out, out_size);
    661 }
    662 
    663 _END_GOOGLE_NAMESPACE_
    664 
    665 #else  /* HAVE_SYMBOLIZE */
    666 
    667 #include <assert.h>
    668 
    669 #include "config.h"
    670 
    671 _START_GOOGLE_NAMESPACE_
    672 
    673 // TODO: Support other environments.
    674 bool Symbolize(void *pc, char *out, int out_size) {
    675   assert(0);
    676   return false;
    677 }
    678 
    679 _END_GOOGLE_NAMESPACE_
    680 
    681 #endif
    682