| // -*- mode: c++ -*- |
| |
| // Copyright (c) 2011 Google Inc. All Rights Reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| // Original author: Ted Mielczarek <ted.mielczarek@gmail.com> |
| |
| #include "common/linux/elf_symbols_to_module.h" |
| |
| #include <cxxabi.h> |
| #include <elf.h> |
| #include <string.h> |
| |
| #include "common/byte_cursor.h" |
| #include "common/module.h" |
| |
| namespace google_breakpad { |
| |
| class ELFSymbolIterator { |
| public: |
| // The contents of an ELF symbol, adjusted for the host's endianness, |
| // word size, and so on. Corresponds to the data in Elf32_Sym / Elf64_Sym. |
| struct Symbol { |
| // True if this iterator has reached the end of the symbol array. When |
| // this is set, the other members of this structure are not valid. |
| bool at_end; |
| |
| // The number of this symbol within the list. |
| size_t index; |
| |
| // The current symbol's name offset. This is the offset within the |
| // string table. |
| size_t name_offset; |
| |
| // The current symbol's value, size, info and shndx fields. |
| uint64_t value; |
| uint64_t size; |
| unsigned char info; |
| uint16_t shndx; |
| }; |
| |
| // Create an ELFSymbolIterator walking the symbols in BUFFER. Treat the |
| // symbols as big-endian if BIG_ENDIAN is true, as little-endian |
| // otherwise. Assume each symbol has a 'value' field whose size is |
| // VALUE_SIZE. |
| // |
| ELFSymbolIterator(const ByteBuffer *buffer, bool big_endian, |
| size_t value_size) |
| : value_size_(value_size), cursor_(buffer, big_endian) { |
| // Actually, weird sizes could be handled just fine, but they're |
| // probably mistakes --- expressed in bits, say. |
| assert(value_size == 4 || value_size == 8); |
| symbol_.index = 0; |
| Fetch(); |
| } |
| |
| // Move to the next symbol. This function's behavior is undefined if |
| // at_end() is true when it is called. |
| ELFSymbolIterator &operator++() { Fetch(); symbol_.index++; return *this; } |
| |
| // Dereferencing this iterator produces a reference to an Symbol structure |
| // that holds the current symbol's values. The symbol is owned by this |
| // SymbolIterator, and will be invalidated at the next call to operator++. |
| const Symbol &operator*() const { return symbol_; } |
| const Symbol *operator->() const { return &symbol_; } |
| |
| private: |
| // Read the symbol at cursor_, and set symbol_ appropriately. |
| void Fetch() { |
| // Elf32_Sym and Elf64_Sym have different layouts. |
| unsigned char other; |
| if (value_size_ == 4) { |
| // Elf32_Sym |
| cursor_ |
| .Read(4, false, &symbol_.name_offset) |
| .Read(4, false, &symbol_.value) |
| .Read(4, false, &symbol_.size) |
| .Read(1, false, &symbol_.info) |
| .Read(1, false, &other) |
| .Read(2, false, &symbol_.shndx); |
| } else { |
| // Elf64_Sym |
| cursor_ |
| .Read(4, false, &symbol_.name_offset) |
| .Read(1, false, &symbol_.info) |
| .Read(1, false, &other) |
| .Read(2, false, &symbol_.shndx) |
| .Read(8, false, &symbol_.value) |
| .Read(8, false, &symbol_.size); |
| } |
| symbol_.at_end = !cursor_; |
| } |
| |
| // The size of symbols' value field, in bytes. |
| size_t value_size_; |
| |
| // A byte cursor traversing buffer_. |
| ByteCursor cursor_; |
| |
| // Values for the symbol this iterator refers to. |
| Symbol symbol_; |
| }; |
| |
| const char *SymbolString(ptrdiff_t offset, ByteBuffer& strings) { |
| if (offset < 0 || (size_t) offset >= strings.Size()) { |
| // Return the null string. |
| offset = 0; |
| } |
| return reinterpret_cast<const char *>(strings.start + offset); |
| } |
| |
| bool ELFSymbolsToModule(const uint8_t *symtab_section, |
| size_t symtab_size, |
| const uint8_t *string_section, |
| size_t string_size, |
| const bool big_endian, |
| size_t value_size, |
| Module *module) { |
| ByteBuffer symbols(symtab_section, symtab_size); |
| // Ensure that the string section is null-terminated. |
| if (string_section[string_size - 1] != '\0') { |
| const void* null_terminator = memrchr(string_section, '\0', string_size); |
| string_size = reinterpret_cast<const uint8_t*>(null_terminator) |
| - string_section; |
| } |
| ByteBuffer strings(string_section, string_size); |
| |
| // The iterator walking the symbol table. |
| ELFSymbolIterator iterator(&symbols, big_endian, value_size); |
| |
| while(!iterator->at_end) { |
| if (ELF32_ST_TYPE(iterator->info) == STT_FUNC && |
| iterator->shndx != SHN_UNDEF) { |
| Module::Extern *ext = new Module::Extern(iterator->value); |
| ext->name = SymbolString(iterator->name_offset, strings); |
| #if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle. |
| int status = 0; |
| char* demangled = |
| abi::__cxa_demangle(ext->name.c_str(), NULL, NULL, &status); |
| if (demangled) { |
| if (status == 0) |
| ext->name = demangled; |
| free(demangled); |
| } |
| #endif |
| module->AddExtern(ext); |
| } |
| ++iterator; |
| } |
| return true; |
| } |
| |
| } // namespace google_breakpad |