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