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 <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 | |