blob: df1642e18f3171bd0b63ce04cb13cfc4169ba5d6 [file] [log] [blame]
Christopher Ferris3958f802017-02-01 15:44:40 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <elf.h>
18#include <stdint.h>
19
20#include <memory>
21#include <string>
22
Christopher Ferrisbae69f12017-06-28 14:51:54 -070023#include <7zCrc.h>
24#include <Xz.h>
25#include <XzCrc64.h>
26
Christopher Ferrisd226a512017-07-14 10:37:19 -070027#include <unwindstack/DwarfSection.h>
28#include <unwindstack/ElfInterface.h>
29#include <unwindstack/Log.h>
30#include <unwindstack/Memory.h>
31#include <unwindstack/Regs.h>
32
Christopher Ferris61d40972017-06-12 19:14:20 -070033#include "DwarfDebugFrame.h"
34#include "DwarfEhFrame.h"
Christopher Ferrisc9dee842017-11-03 14:50:27 -070035#include "DwarfEhFrameWithHdr.h"
Christopher Ferris8098b1c2017-06-20 13:54:08 -070036#include "Symbols.h"
37
Christopher Ferrisd226a512017-07-14 10:37:19 -070038namespace unwindstack {
39
Christopher Ferris8098b1c2017-06-20 13:54:08 -070040ElfInterface::~ElfInterface() {
41 for (auto symbol : symbols_) {
42 delete symbol;
43 }
44}
Christopher Ferris3958f802017-02-01 15:44:40 -080045
Christopher Ferrisbae69f12017-06-28 14:51:54 -070046Memory* ElfInterface::CreateGnuDebugdataMemory() {
47 if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) {
48 return nullptr;
49 }
50
51 // TODO: Only call these initialization functions once.
52 CrcGenerateTable();
53 Crc64GenerateTable();
54
55 std::vector<uint8_t> src(gnu_debugdata_size_);
Josh Gaoef35aa52017-10-18 11:44:51 -070056 if (!memory_->ReadFully(gnu_debugdata_offset_, src.data(), gnu_debugdata_size_)) {
Christopher Ferrisbae69f12017-06-28 14:51:54 -070057 gnu_debugdata_offset_ = 0;
58 gnu_debugdata_size_ = static_cast<uint64_t>(-1);
59 return nullptr;
60 }
61
62 ISzAlloc alloc;
63 CXzUnpacker state;
64 alloc.Alloc = [](void*, size_t size) { return malloc(size); };
65 alloc.Free = [](void*, void* ptr) { return free(ptr); };
66
67 XzUnpacker_Construct(&state, &alloc);
68
69 std::unique_ptr<MemoryBuffer> dst(new MemoryBuffer);
70 int return_val;
71 size_t src_offset = 0;
72 size_t dst_offset = 0;
73 ECoderStatus status;
74 dst->Resize(5 * gnu_debugdata_size_);
75 do {
76 size_t src_remaining = src.size() - src_offset;
77 size_t dst_remaining = dst->Size() - dst_offset;
78 if (dst_remaining < 2 * gnu_debugdata_size_) {
79 dst->Resize(dst->Size() + 2 * gnu_debugdata_size_);
80 dst_remaining += 2 * gnu_debugdata_size_;
81 }
82 return_val = XzUnpacker_Code(&state, dst->GetPtr(dst_offset), &dst_remaining, &src[src_offset],
83 &src_remaining, CODER_FINISH_ANY, &status);
84 src_offset += src_remaining;
85 dst_offset += dst_remaining;
86 } while (return_val == SZ_OK && status == CODER_STATUS_NOT_FINISHED);
87 XzUnpacker_Free(&state);
88 if (return_val != SZ_OK || !XzUnpacker_IsStreamWasFinished(&state)) {
89 gnu_debugdata_offset_ = 0;
90 gnu_debugdata_size_ = static_cast<uint64_t>(-1);
91 return nullptr;
92 }
93
94 // Shrink back down to the exact size.
95 dst->Resize(dst_offset);
96
97 return dst.release();
98}
99
Christopher Ferris61d40972017-06-12 19:14:20 -0700100template <typename AddressType>
101void ElfInterface::InitHeadersWithTemplate() {
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700102 if (eh_frame_hdr_offset_ != 0) {
103 eh_frame_.reset(new DwarfEhFrameWithHdr<AddressType>(memory_));
104 if (!eh_frame_->Init(eh_frame_hdr_offset_, eh_frame_hdr_size_)) {
105 // Even if the eh_frame_offset_ is non-zero, do not bother
106 // trying to read that since something has gone wrong.
107 eh_frame_.reset(nullptr);
108 eh_frame_hdr_offset_ = 0;
109 eh_frame_hdr_size_ = static_cast<uint64_t>(-1);
110 }
111 } else if (eh_frame_offset_ != 0) {
112 // If there is a eh_frame section without a eh_frame_hdr section.
Christopher Ferris61d40972017-06-12 19:14:20 -0700113 eh_frame_.reset(new DwarfEhFrame<AddressType>(memory_));
114 if (!eh_frame_->Init(eh_frame_offset_, eh_frame_size_)) {
115 eh_frame_.reset(nullptr);
116 eh_frame_offset_ = 0;
117 eh_frame_size_ = static_cast<uint64_t>(-1);
118 }
119 }
120
121 if (debug_frame_offset_ != 0) {
122 debug_frame_.reset(new DwarfDebugFrame<AddressType>(memory_));
123 if (!debug_frame_->Init(debug_frame_offset_, debug_frame_size_)) {
124 debug_frame_.reset(nullptr);
125 debug_frame_offset_ = 0;
126 debug_frame_size_ = static_cast<uint64_t>(-1);
127 }
128 }
129}
130
Christopher Ferris3958f802017-02-01 15:44:40 -0800131template <typename EhdrType, typename PhdrType, typename ShdrType>
Christopher Ferrise69f4702017-10-19 16:08:58 -0700132bool ElfInterface::ReadAllHeaders(uint64_t* load_bias) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800133 EhdrType ehdr;
Josh Gaoef35aa52017-10-18 11:44:51 -0700134 if (!memory_->ReadFully(0, &ehdr, sizeof(ehdr))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800135 return false;
136 }
137
Christopher Ferrise69f4702017-10-19 16:08:58 -0700138 if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr, load_bias)) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800139 return false;
140 }
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700141
142 // We could still potentially unwind without the section header
143 // information, so ignore any errors.
144 if (!ReadSectionHeaders<EhdrType, ShdrType>(ehdr)) {
145 log(0, "Malformed section header found, ignoring...");
146 }
147 return true;
Christopher Ferris3958f802017-02-01 15:44:40 -0800148}
149
150template <typename EhdrType, typename PhdrType>
Christopher Ferrisb7de5f52017-12-01 21:37:37 -0800151uint64_t ElfInterface::GetLoadBias(Memory* memory) {
152 EhdrType ehdr;
153 if (!memory->Read(0, &ehdr, sizeof(ehdr))) {
154 return false;
155 }
156
157 uint64_t offset = ehdr.e_phoff;
158 for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
159 PhdrType phdr;
160 if (!memory->Read(offset, &phdr, sizeof(phdr))) {
161 return 0;
162 }
163 if (phdr.p_type == PT_LOAD && phdr.p_offset == 0) {
164 return phdr.p_vaddr;
165 }
166 }
167 return 0;
168}
169
170template <typename EhdrType, typename PhdrType>
Christopher Ferrise69f4702017-10-19 16:08:58 -0700171bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800172 uint64_t offset = ehdr.e_phoff;
173 for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
174 PhdrType phdr;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700175 if (!memory_->ReadField(offset, &phdr, &phdr.p_type, sizeof(phdr.p_type))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800176 return false;
177 }
178
Christopher Ferrise69f4702017-10-19 16:08:58 -0700179 if (HandleType(offset, phdr.p_type, *load_bias)) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800180 continue;
181 }
182
183 switch (phdr.p_type) {
184 case PT_LOAD:
185 {
186 // Get the flags first, if this isn't an executable header, ignore it.
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700187 if (!memory_->ReadField(offset, &phdr, &phdr.p_flags, sizeof(phdr.p_flags))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800188 return false;
189 }
190 if ((phdr.p_flags & PF_X) == 0) {
191 continue;
192 }
193
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700194 if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800195 return false;
196 }
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700197 if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800198 return false;
199 }
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700200 if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800201 return false;
202 }
203 pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
204 static_cast<size_t>(phdr.p_memsz)};
205 if (phdr.p_offset == 0) {
Christopher Ferrise69f4702017-10-19 16:08:58 -0700206 *load_bias = phdr.p_vaddr;
Christopher Ferris3958f802017-02-01 15:44:40 -0800207 }
208 break;
209 }
210
211 case PT_GNU_EH_FRAME:
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700212 if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800213 return false;
214 }
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700215 // This is really the pointer to the .eh_frame_hdr section.
216 eh_frame_hdr_offset_ = phdr.p_offset;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700217 if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800218 return false;
219 }
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700220 eh_frame_hdr_size_ = phdr.p_memsz;
Christopher Ferris3958f802017-02-01 15:44:40 -0800221 break;
222
223 case PT_DYNAMIC:
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700224 if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800225 return false;
226 }
227 dynamic_offset_ = phdr.p_offset;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700228 if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800229 return false;
230 }
231 dynamic_size_ = phdr.p_memsz;
232 break;
233 }
234 }
235 return true;
236}
237
238template <typename EhdrType, typename ShdrType>
239bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
240 uint64_t offset = ehdr.e_shoff;
241 uint64_t sec_offset = 0;
242 uint64_t sec_size = 0;
243
244 // Get the location of the section header names.
245 // If something is malformed in the header table data, we aren't going
246 // to terminate, we'll simply ignore this part.
247 ShdrType shdr;
248 if (ehdr.e_shstrndx < ehdr.e_shnum) {
249 uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700250 if (memory_->ReadField(sh_offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) &&
251 memory_->ReadField(sh_offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800252 sec_offset = shdr.sh_offset;
253 sec_size = shdr.sh_size;
254 }
255 }
256
257 // Skip the first header, it's always going to be NULL.
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700258 offset += ehdr.e_shentsize;
Christopher Ferris3958f802017-02-01 15:44:40 -0800259 for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700260 if (!memory_->ReadField(offset, &shdr, &shdr.sh_type, sizeof(shdr.sh_type))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800261 return false;
262 }
263
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700264 if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
Josh Gaoef35aa52017-10-18 11:44:51 -0700265 if (!memory_->ReadFully(offset, &shdr, sizeof(shdr))) {
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700266 return false;
267 }
268 // Need to go get the information about the section that contains
269 // the string terminated names.
270 ShdrType str_shdr;
271 if (shdr.sh_link >= ehdr.e_shnum) {
272 return false;
273 }
274 uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize;
275 if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_type, sizeof(str_shdr.sh_type))) {
276 return false;
277 }
278 if (str_shdr.sh_type != SHT_STRTAB) {
279 return false;
280 }
281 if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_offset,
282 sizeof(str_shdr.sh_offset))) {
283 return false;
284 }
285 if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_size, sizeof(str_shdr.sh_size))) {
286 return false;
287 }
288 symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize,
289 str_shdr.sh_offset, str_shdr.sh_size));
290 } else if (shdr.sh_type == SHT_PROGBITS && sec_size != 0) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800291 // Look for the .debug_frame and .gnu_debugdata.
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700292 if (!memory_->ReadField(offset, &shdr, &shdr.sh_name, sizeof(shdr.sh_name))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800293 return false;
294 }
295 if (shdr.sh_name < sec_size) {
296 std::string name;
297 if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) {
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700298 uint64_t* offset_ptr = nullptr;
299 uint64_t* size_ptr = nullptr;
Christopher Ferris3958f802017-02-01 15:44:40 -0800300 if (name == ".debug_frame") {
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700301 offset_ptr = &debug_frame_offset_;
302 size_ptr = &debug_frame_size_;
Christopher Ferris3958f802017-02-01 15:44:40 -0800303 } else if (name == ".gnu_debugdata") {
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700304 offset_ptr = &gnu_debugdata_offset_;
305 size_ptr = &gnu_debugdata_size_;
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700306 } else if (name == ".eh_frame") {
307 offset_ptr = &eh_frame_offset_;
308 size_ptr = &eh_frame_size_;
309 } else if (eh_frame_hdr_offset_ == 0 && name == ".eh_frame_hdr") {
310 offset_ptr = &eh_frame_hdr_offset_;
311 size_ptr = &eh_frame_hdr_size_;
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700312 }
313 if (offset_ptr != nullptr &&
314 memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) &&
315 memory_->ReadField(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
316 *offset_ptr = shdr.sh_offset;
317 *size_ptr = shdr.sh_size;
Christopher Ferris3958f802017-02-01 15:44:40 -0800318 }
319 }
320 }
321 }
322 }
323 return true;
324}
325
326template <typename DynType>
327bool ElfInterface::GetSonameWithTemplate(std::string* soname) {
328 if (soname_type_ == SONAME_INVALID) {
329 return false;
330 }
331 if (soname_type_ == SONAME_VALID) {
332 *soname = soname_;
333 return true;
334 }
335
336 soname_type_ = SONAME_INVALID;
337
338 uint64_t soname_offset = 0;
339 uint64_t strtab_offset = 0;
340 uint64_t strtab_size = 0;
341
342 // Find the soname location from the dynamic headers section.
343 DynType dyn;
344 uint64_t offset = dynamic_offset_;
345 uint64_t max_offset = offset + dynamic_size_;
346 for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) {
Josh Gaoef35aa52017-10-18 11:44:51 -0700347 if (!memory_->ReadFully(offset, &dyn, sizeof(dyn))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800348 return false;
349 }
350
351 if (dyn.d_tag == DT_STRTAB) {
352 strtab_offset = dyn.d_un.d_ptr;
353 } else if (dyn.d_tag == DT_STRSZ) {
354 strtab_size = dyn.d_un.d_val;
355 } else if (dyn.d_tag == DT_SONAME) {
356 soname_offset = dyn.d_un.d_val;
357 } else if (dyn.d_tag == DT_NULL) {
358 break;
359 }
360 }
361
362 soname_offset += strtab_offset;
363 if (soname_offset >= strtab_offset + strtab_size) {
364 return false;
365 }
366 if (!memory_->ReadString(soname_offset, &soname_)) {
367 return false;
368 }
369 soname_type_ = SONAME_VALID;
370 *soname = soname_;
371 return true;
372}
373
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700374template <typename SymType>
Christopher Ferrise69f4702017-10-19 16:08:58 -0700375bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, uint64_t load_bias, std::string* name,
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700376 uint64_t* func_offset) {
377 if (symbols_.empty()) {
378 return false;
379 }
380
381 for (const auto symbol : symbols_) {
Christopher Ferrise69f4702017-10-19 16:08:58 -0700382 if (symbol->GetName<SymType>(addr, load_bias, memory_, name, func_offset)) {
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700383 return true;
384 }
385 }
386 return false;
387}
388
Christopher Ferrise7b66242017-12-15 11:17:45 -0800389bool ElfInterface::Step(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* process_memory,
390 bool* finished) {
391 // Adjust the load bias to get the real relative pc.
392 if (pc < load_bias) {
393 return false;
394 }
395 uint64_t adjusted_pc = pc - load_bias;
396
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700397 // Try the eh_frame first.
398 DwarfSection* eh_frame = eh_frame_.get();
Christopher Ferrise7b66242017-12-15 11:17:45 -0800399 if (eh_frame != nullptr && eh_frame->Step(adjusted_pc, regs, process_memory, finished)) {
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700400 return true;
401 }
402
403 // Try the debug_frame next.
404 DwarfSection* debug_frame = debug_frame_.get();
Christopher Ferrise7b66242017-12-15 11:17:45 -0800405 if (debug_frame != nullptr && debug_frame->Step(adjusted_pc, regs, process_memory, finished)) {
406 return true;
407 }
408
409 // Finally try the gnu_debugdata interface, but always use a zero load bias.
410 if (gnu_debugdata_interface_ != nullptr &&
411 gnu_debugdata_interface_->Step(pc, 0, regs, process_memory, finished)) {
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700412 return true;
413 }
Christopher Ferris3958f802017-02-01 15:44:40 -0800414 return false;
415}
416
Christopher Ferris3f805ac2017-08-30 13:15:19 -0700417// This is an estimation of the size of the elf file using the location
418// of the section headers and size. This assumes that the section headers
419// are at the end of the elf file. If the elf has a load bias, the size
420// will be too large, but this is acceptable.
421template <typename EhdrType>
422void ElfInterface::GetMaxSizeWithTemplate(Memory* memory, uint64_t* size) {
423 EhdrType ehdr;
Josh Gaoef35aa52017-10-18 11:44:51 -0700424 if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) {
Christopher Ferris3f805ac2017-08-30 13:15:19 -0700425 return;
426 }
427 if (ehdr.e_shnum == 0) {
428 return;
429 }
430 *size = ehdr.e_shoff + ehdr.e_shentsize * ehdr.e_shnum;
431}
432
Christopher Ferris3958f802017-02-01 15:44:40 -0800433// Instantiate all of the needed template functions.
Christopher Ferris61d40972017-06-12 19:14:20 -0700434template void ElfInterface::InitHeadersWithTemplate<uint32_t>();
435template void ElfInterface::InitHeadersWithTemplate<uint64_t>();
436
Christopher Ferrise69f4702017-10-19 16:08:58 -0700437template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(uint64_t*);
438template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(uint64_t*);
Christopher Ferris3958f802017-02-01 15:44:40 -0800439
Christopher Ferrise69f4702017-10-19 16:08:58 -0700440template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&, uint64_t*);
441template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&, uint64_t*);
Christopher Ferris3958f802017-02-01 15:44:40 -0800442
443template bool ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
444template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
445
446template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
447template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700448
Christopher Ferrise69f4702017-10-19 16:08:58 -0700449template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, uint64_t, std::string*,
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700450 uint64_t*);
Christopher Ferrise69f4702017-10-19 16:08:58 -0700451template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, uint64_t, std::string*,
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700452 uint64_t*);
Christopher Ferrisd226a512017-07-14 10:37:19 -0700453
Christopher Ferris3f805ac2017-08-30 13:15:19 -0700454template void ElfInterface::GetMaxSizeWithTemplate<Elf32_Ehdr>(Memory*, uint64_t*);
455template void ElfInterface::GetMaxSizeWithTemplate<Elf64_Ehdr>(Memory*, uint64_t*);
456
Christopher Ferrisb7de5f52017-12-01 21:37:37 -0800457template uint64_t ElfInterface::GetLoadBias<Elf32_Ehdr, Elf32_Phdr>(Memory*);
458template uint64_t ElfInterface::GetLoadBias<Elf64_Ehdr, Elf64_Phdr>(Memory*);
459
Christopher Ferrisd226a512017-07-14 10:37:19 -0700460} // namespace unwindstack