Home | History | Annotate | Download | only in linux
      1 // -*- mode: c++ -*-
      2 
      3 // Copyright (c) 2011 Google Inc. All Rights Reserved.
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 // Original author: Ted Mielczarek <ted.mielczarek (at) gmail.com>
     32 
     33 #include "common/linux/elf_symbols_to_module.h"
     34 
     35 #include <cxxabi.h>
     36 #include <elf.h>
     37 #include <string.h>
     38 
     39 #include "common/byte_cursor.h"
     40 #include "common/module.h"
     41 
     42 namespace google_breakpad {
     43 
     44 class ELFSymbolIterator {
     45 public:
     46   // The contents of an ELF symbol, adjusted for the host's endianness,
     47   // word size, and so on. Corresponds to the data in Elf32_Sym / Elf64_Sym.
     48   struct Symbol {
     49     // True if this iterator has reached the end of the symbol array. When
     50     // this is set, the other members of this structure are not valid.
     51     bool at_end;
     52 
     53     // The number of this symbol within the list.
     54     size_t index;
     55 
     56     // The current symbol's name offset. This is the offset within the
     57     // string table.
     58     size_t name_offset;
     59 
     60     // The current symbol's value, size, info and shndx fields.
     61     uint64_t value;
     62     uint64_t size;
     63     unsigned char info;
     64     uint16_t shndx;
     65   };
     66 
     67   // Create an ELFSymbolIterator walking the symbols in BUFFER. Treat the
     68   // symbols as big-endian if BIG_ENDIAN is true, as little-endian
     69   // otherwise. Assume each symbol has a 'value' field whose size is
     70   // VALUE_SIZE.
     71   //
     72   ELFSymbolIterator(const ByteBuffer *buffer, bool big_endian,
     73                     size_t value_size)
     74     : value_size_(value_size), cursor_(buffer, big_endian) {
     75     // Actually, weird sizes could be handled just fine, but they're
     76     // probably mistakes --- expressed in bits, say.
     77     assert(value_size == 4 || value_size == 8);
     78     symbol_.index = 0;
     79     Fetch();
     80   }
     81 
     82   // Move to the next symbol. This function's behavior is undefined if
     83   // at_end() is true when it is called.
     84   ELFSymbolIterator &operator++() { Fetch(); symbol_.index++; return *this; }
     85 
     86   // Dereferencing this iterator produces a reference to an Symbol structure
     87   // that holds the current symbol's values. The symbol is owned by this
     88   // SymbolIterator, and will be invalidated at the next call to operator++.
     89   const Symbol &operator*() const { return symbol_; }
     90   const Symbol *operator->() const { return &symbol_; }
     91 
     92 private:
     93   // Read the symbol at cursor_, and set symbol_ appropriately.
     94   void Fetch() {
     95     // Elf32_Sym and Elf64_Sym have different layouts.
     96     unsigned char other;
     97     if (value_size_ == 4) {
     98       // Elf32_Sym
     99       cursor_
    100         .Read(4, false, &symbol_.name_offset)
    101         .Read(4, false, &symbol_.value)
    102         .Read(4, false, &symbol_.size)
    103         .Read(1, false, &symbol_.info)
    104         .Read(1, false, &other)
    105         .Read(2, false, &symbol_.shndx);
    106     } else {
    107       // Elf64_Sym
    108       cursor_
    109         .Read(4, false, &symbol_.name_offset)
    110         .Read(1, false, &symbol_.info)
    111         .Read(1, false, &other)
    112         .Read(2, false, &symbol_.shndx)
    113         .Read(8, false, &symbol_.value)
    114         .Read(8, false, &symbol_.size);
    115     }
    116     symbol_.at_end = !cursor_;
    117   }
    118 
    119   // The size of symbols' value field, in bytes.
    120   size_t value_size_;
    121 
    122   // A byte cursor traversing buffer_.
    123   ByteCursor cursor_;
    124 
    125   // Values for the symbol this iterator refers to.
    126   Symbol symbol_;
    127 };
    128 
    129 const char *SymbolString(ptrdiff_t offset, ByteBuffer& strings) {
    130   if (offset < 0 || (size_t) offset >= strings.Size()) {
    131     // Return the null string.
    132     offset = 0;
    133   }
    134   return reinterpret_cast<const char *>(strings.start + offset);
    135 }
    136 
    137 bool ELFSymbolsToModule(const uint8_t *symtab_section,
    138                         size_t symtab_size,
    139                         const uint8_t *string_section,
    140                         size_t string_size,
    141                         const bool big_endian,
    142                         size_t value_size,
    143                         Module *module) {
    144   ByteBuffer symbols(symtab_section, symtab_size);
    145   // Ensure that the string section is null-terminated.
    146   if (string_section[string_size - 1] != '\0') {
    147     const void* null_terminator = memrchr(string_section, '\0', string_size);
    148     string_size = reinterpret_cast<const uint8_t*>(null_terminator)
    149       - string_section;
    150   }
    151   ByteBuffer strings(string_section, string_size);
    152 
    153   // The iterator walking the symbol table.
    154   ELFSymbolIterator iterator(&symbols, big_endian, value_size);
    155 
    156   while(!iterator->at_end) {
    157     if (ELF32_ST_TYPE(iterator->info) == STT_FUNC &&
    158         iterator->shndx != SHN_UNDEF) {
    159       Module::Extern *ext = new Module::Extern(iterator->value);
    160       ext->name = SymbolString(iterator->name_offset, strings);
    161 #if !defined(__ANDROID__)  // Android NDK doesn't provide abi::__cxa_demangle.
    162       int status = 0;
    163       char* demangled =
    164           abi::__cxa_demangle(ext->name.c_str(), NULL, NULL, &status);
    165       if (demangled) {
    166         if (status == 0)
    167           ext->name = demangled;
    168         free(demangled);
    169       }
    170 #endif
    171       module->AddExtern(ext);
    172     }
    173     ++iterator;
    174   }
    175   return true;
    176 }
    177 
    178 }  // namespace google_breakpad
    179