PageRenderTime 56ms CodeModel.GetById 16ms app.highlight 32ms RepoModel.GetById 2ms app.codeStats 0ms

/thirdparty/breakpad/common/linux/elf_symbols_to_module.cc

http://github.com/tomahawk-player/tomahawk
C++ | 168 lines | 87 code | 22 blank | 59 comment | 13 complexity | 564e4ccc43e830d6a2ee42a69a545847 MD5 | raw file
  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@gmail.com>
 32
 33#include "common/linux/elf_symbols_to_module.h"
 34
 35#include <elf.h>
 36#include <string.h>
 37
 38#include "common/byte_cursor.h"
 39#include "common/module.h"
 40
 41namespace google_breakpad {
 42
 43class ELFSymbolIterator {
 44public:
 45  // The contents of an ELF symbol, adjusted for the host's endianness,
 46  // word size, and so on. Corresponds to the data in Elf32_Sym / Elf64_Sym.
 47  struct Symbol {
 48    // True if this iterator has reached the end of the symbol array. When
 49    // this is set, the other members of this structure are not valid.
 50    bool at_end;
 51
 52    // The number of this symbol within the list.
 53    size_t index;
 54
 55    // The current symbol's name offset. This is the offset within the
 56    // string table.
 57    size_t name_offset;
 58
 59    // The current symbol's value, size, info and shndx fields.
 60    uint64_t value;
 61    uint64_t size;
 62    unsigned char info;
 63    uint16_t shndx;
 64  };
 65
 66  // Create an ELFSymbolIterator walking the symbols in BUFFER. Treat the
 67  // symbols as big-endian if BIG_ENDIAN is true, as little-endian
 68  // otherwise. Assume each symbol has a 'value' field whose size is
 69  // VALUE_SIZE.
 70  //
 71  ELFSymbolIterator(const ByteBuffer *buffer, bool big_endian,
 72                    size_t value_size)
 73    : value_size_(value_size), cursor_(buffer, big_endian) {
 74    // Actually, weird sizes could be handled just fine, but they're
 75    // probably mistakes --- expressed in bits, say.
 76    assert(value_size == 4 || value_size == 8);
 77    symbol_.index = 0;
 78    Fetch();
 79  }
 80
 81  // Move to the next symbol. This function's behavior is undefined if
 82  // at_end() is true when it is called.
 83  ELFSymbolIterator &operator++() { Fetch(); symbol_.index++; return *this; }
 84
 85  // Dereferencing this iterator produces a reference to an Symbol structure
 86  // that holds the current symbol's values. The symbol is owned by this
 87  // SymbolIterator, and will be invalidated at the next call to operator++.
 88  const Symbol &operator*() const { return symbol_; }
 89  const Symbol *operator->() const { return &symbol_; }
 90
 91private:
 92  // Read the symbol at cursor_, and set symbol_ appropriately.
 93  void Fetch() {
 94    // Elf32_Sym and Elf64_Sym have different layouts.
 95    unsigned char other;
 96    if (value_size_ == 4) {
 97      // Elf32_Sym
 98      cursor_
 99        .Read(4, false, &symbol_.name_offset)
100        .Read(4, false, &symbol_.value)
101        .Read(4, false, &symbol_.size)
102        .Read(1, false, &symbol_.info)
103        .Read(1, false, &other)
104        .Read(2, false, &symbol_.shndx);
105    } else {
106      // Elf64_Sym
107      cursor_
108        .Read(4, false, &symbol_.name_offset)
109        .Read(1, false, &symbol_.info)
110        .Read(1, false, &other)
111        .Read(2, false, &symbol_.shndx)
112        .Read(8, false, &symbol_.value)
113        .Read(8, false, &symbol_.size);
114    }
115    symbol_.at_end = !cursor_;
116  }
117
118  // The size of symbols' value field, in bytes.
119  size_t value_size_;
120
121  // A byte cursor traversing buffer_.
122  ByteCursor cursor_;
123
124  // Values for the symbol this iterator refers to.
125  Symbol symbol_;
126};
127
128const char *SymbolString(ptrdiff_t offset, ByteBuffer& strings) {
129  if (offset < 0 || (size_t) offset >= strings.Size()) {
130    // Return the null string.
131    offset = 0;
132  }
133  return reinterpret_cast<const char *>(strings.start + offset);
134}
135
136bool ELFSymbolsToModule(const uint8_t *symtab_section,
137                        size_t symtab_size,
138                        const uint8_t *string_section,
139                        size_t string_size,
140                        const bool big_endian,
141                        size_t value_size,
142                        Module *module) {
143  ByteBuffer symbols(symtab_section, symtab_size);
144  // Ensure that the string section is null-terminated.
145  if (string_section[string_size - 1] != '\0') {
146    const void* null_terminator = memrchr(string_section, '\0', string_size);
147    string_size = reinterpret_cast<const uint8_t*>(null_terminator)
148      - string_section;
149  }
150  ByteBuffer strings(string_section, string_size);
151
152  // The iterator walking the symbol table.
153  ELFSymbolIterator iterator(&symbols, big_endian, value_size);
154
155  while(!iterator->at_end) {
156    if (ELF32_ST_TYPE(iterator->info) == STT_FUNC &&
157        iterator->shndx != SHN_UNDEF) {
158      Module::Extern *ext = new Module::Extern;
159      ext->name = SymbolString(iterator->name_offset, strings);
160      ext->address = iterator->value;
161      module->AddExtern(ext);
162    }
163    ++iterator;
164  }
165  return true;
166}
167
168}  // namespace google_breakpad