summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'libunwindstack/ElfInterface.cpp')
-rw-r--r--libunwindstack/ElfInterface.cpp203
1 files changed, 187 insertions, 16 deletions
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 087457c02..75abc85f7 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -20,9 +20,102 @@
20#include <memory> 20#include <memory>
21#include <string> 21#include <string>
22 22
23#include "ElfInterface.h" 23#include <7zCrc.h>
24#include "Memory.h" 24#include <Xz.h>
25#include "Regs.h" 25#include <XzCrc64.h>
26
27#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
33#include "DwarfDebugFrame.h"
34#include "DwarfEhFrame.h"
35#include "Symbols.h"
36
37namespace unwindstack {
38
39ElfInterface::~ElfInterface() {
40 for (auto symbol : symbols_) {
41 delete symbol;
42 }
43}
44
45Memory* ElfInterface::CreateGnuDebugdataMemory() {
46 if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) {
47 return nullptr;
48 }
49
50 // TODO: Only call these initialization functions once.
51 CrcGenerateTable();
52 Crc64GenerateTable();
53
54 std::vector<uint8_t> src(gnu_debugdata_size_);
55 if (!memory_->Read(gnu_debugdata_offset_, src.data(), gnu_debugdata_size_)) {
56 gnu_debugdata_offset_ = 0;
57 gnu_debugdata_size_ = static_cast<uint64_t>(-1);
58 return nullptr;
59 }
60
61 ISzAlloc alloc;
62 CXzUnpacker state;
63 alloc.Alloc = [](void*, size_t size) { return malloc(size); };
64 alloc.Free = [](void*, void* ptr) { return free(ptr); };
65
66 XzUnpacker_Construct(&state, &alloc);
67
68 std::unique_ptr<MemoryBuffer> dst(new MemoryBuffer);
69 int return_val;
70 size_t src_offset = 0;
71 size_t dst_offset = 0;
72 ECoderStatus status;
73 dst->Resize(5 * gnu_debugdata_size_);
74 do {
75 size_t src_remaining = src.size() - src_offset;
76 size_t dst_remaining = dst->Size() - dst_offset;
77 if (dst_remaining < 2 * gnu_debugdata_size_) {
78 dst->Resize(dst->Size() + 2 * gnu_debugdata_size_);
79 dst_remaining += 2 * gnu_debugdata_size_;
80 }
81 return_val = XzUnpacker_Code(&state, dst->GetPtr(dst_offset), &dst_remaining, &src[src_offset],
82 &src_remaining, CODER_FINISH_ANY, &status);
83 src_offset += src_remaining;
84 dst_offset += dst_remaining;
85 } while (return_val == SZ_OK && status == CODER_STATUS_NOT_FINISHED);
86 XzUnpacker_Free(&state);
87 if (return_val != SZ_OK || !XzUnpacker_IsStreamWasFinished(&state)) {
88 gnu_debugdata_offset_ = 0;
89 gnu_debugdata_size_ = static_cast<uint64_t>(-1);
90 return nullptr;
91 }
92
93 // Shrink back down to the exact size.
94 dst->Resize(dst_offset);
95
96 return dst.release();
97}
98
99template <typename AddressType>
100void ElfInterface::InitHeadersWithTemplate() {
101 if (eh_frame_offset_ != 0) {
102 eh_frame_.reset(new DwarfEhFrame<AddressType>(memory_));
103 if (!eh_frame_->Init(eh_frame_offset_, eh_frame_size_)) {
104 eh_frame_.reset(nullptr);
105 eh_frame_offset_ = 0;
106 eh_frame_size_ = static_cast<uint64_t>(-1);
107 }
108 }
109
110 if (debug_frame_offset_ != 0) {
111 debug_frame_.reset(new DwarfDebugFrame<AddressType>(memory_));
112 if (!debug_frame_->Init(debug_frame_offset_, debug_frame_size_)) {
113 debug_frame_.reset(nullptr);
114 debug_frame_offset_ = 0;
115 debug_frame_size_ = static_cast<uint64_t>(-1);
116 }
117 }
118}
26 119
27template <typename EhdrType, typename PhdrType, typename ShdrType> 120template <typename EhdrType, typename PhdrType, typename ShdrType>
28bool ElfInterface::ReadAllHeaders() { 121bool ElfInterface::ReadAllHeaders() {
@@ -34,7 +127,13 @@ bool ElfInterface::ReadAllHeaders() {
34 if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr)) { 127 if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr)) {
35 return false; 128 return false;
36 } 129 }
37 return ReadSectionHeaders<EhdrType, ShdrType>(ehdr); 130
131 // We could still potentially unwind without the section header
132 // information, so ignore any errors.
133 if (!ReadSectionHeaders<EhdrType, ShdrType>(ehdr)) {
134 log(0, "Malformed section header found, ignoring...");
135 }
136 return true;
38} 137}
39 138
40template <typename EhdrType, typename PhdrType> 139template <typename EhdrType, typename PhdrType>
@@ -124,12 +223,39 @@ bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
124 } 223 }
125 224
126 // Skip the first header, it's always going to be NULL. 225 // Skip the first header, it's always going to be NULL.
226 offset += ehdr.e_shentsize;
127 for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) { 227 for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
128 if (!memory_->ReadField(offset, &shdr, &shdr.sh_type, sizeof(shdr.sh_type))) { 228 if (!memory_->ReadField(offset, &shdr, &shdr.sh_type, sizeof(shdr.sh_type))) {
129 return false; 229 return false;
130 } 230 }
131 231
132 if (shdr.sh_type == SHT_PROGBITS) { 232 if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
233 if (!memory_->Read(offset, &shdr, sizeof(shdr))) {
234 return false;
235 }
236 // Need to go get the information about the section that contains
237 // the string terminated names.
238 ShdrType str_shdr;
239 if (shdr.sh_link >= ehdr.e_shnum) {
240 return false;
241 }
242 uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize;
243 if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_type, sizeof(str_shdr.sh_type))) {
244 return false;
245 }
246 if (str_shdr.sh_type != SHT_STRTAB) {
247 return false;
248 }
249 if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_offset,
250 sizeof(str_shdr.sh_offset))) {
251 return false;
252 }
253 if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_size, sizeof(str_shdr.sh_size))) {
254 return false;
255 }
256 symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize,
257 str_shdr.sh_offset, str_shdr.sh_size));
258 } else if (shdr.sh_type == SHT_PROGBITS && sec_size != 0) {
133 // Look for the .debug_frame and .gnu_debugdata. 259 // Look for the .debug_frame and .gnu_debugdata.
134 if (!memory_->ReadField(offset, &shdr, &shdr.sh_name, sizeof(shdr.sh_name))) { 260 if (!memory_->ReadField(offset, &shdr, &shdr.sh_name, sizeof(shdr.sh_name))) {
135 return false; 261 return false;
@@ -137,18 +263,20 @@ bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
137 if (shdr.sh_name < sec_size) { 263 if (shdr.sh_name < sec_size) {
138 std::string name; 264 std::string name;
139 if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) { 265 if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) {
266 uint64_t* offset_ptr = nullptr;
267 uint64_t* size_ptr = nullptr;
140 if (name == ".debug_frame") { 268 if (name == ".debug_frame") {
141 if (memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) && 269 offset_ptr = &debug_frame_offset_;
142 memory_->ReadField(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) { 270 size_ptr = &debug_frame_size_;
143 debug_frame_offset_ = shdr.sh_offset;
144 debug_frame_size_ = shdr.sh_size;
145 }
146 } else if (name == ".gnu_debugdata") { 271 } else if (name == ".gnu_debugdata") {
147 if (memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) && 272 offset_ptr = &gnu_debugdata_offset_;
148 memory_->ReadField(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) { 273 size_ptr = &gnu_debugdata_size_;
149 gnu_debugdata_offset_ = shdr.sh_offset; 274 }
150 gnu_debugdata_size_ = shdr.sh_size; 275 if (offset_ptr != nullptr &&
151 } 276 memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) &&
277 memory_->ReadField(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
278 *offset_ptr = shdr.sh_offset;
279 *size_ptr = shdr.sh_size;
152 } 280 }
153 } 281 }
154 } 282 }
@@ -205,11 +333,47 @@ bool ElfInterface::GetSonameWithTemplate(std::string* soname) {
205 return true; 333 return true;
206} 334}
207 335
208bool ElfInterface::Step(uint64_t, Regs*, Memory*) { 336template <typename SymType>
337bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, std::string* name,
338 uint64_t* func_offset) {
339 if (symbols_.empty()) {
340 return false;
341 }
342
343 for (const auto symbol : symbols_) {
344 if (symbol->GetName<SymType>(addr, load_bias_, memory_, name, func_offset)) {
345 return true;
346 }
347 }
348 return false;
349}
350
351bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory) {
352 // Need to subtract off the load_bias to get the correct pc.
353 if (pc < load_bias_) {
354 return false;
355 }
356 pc -= load_bias_;
357
358 // Try the eh_frame first.
359 DwarfSection* eh_frame = eh_frame_.get();
360 if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory)) {
361 return true;
362 }
363
364 // Try the debug_frame next.
365 DwarfSection* debug_frame = debug_frame_.get();
366 if (debug_frame != nullptr && debug_frame->Step(pc, regs, process_memory)) {
367 return true;
368 }
369
209 return false; 370 return false;
210} 371}
211 372
212// Instantiate all of the needed template functions. 373// Instantiate all of the needed template functions.
374template void ElfInterface::InitHeadersWithTemplate<uint32_t>();
375template void ElfInterface::InitHeadersWithTemplate<uint64_t>();
376
213template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(); 377template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>();
214template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(); 378template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>();
215 379
@@ -221,3 +385,10 @@ template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf
221 385
222template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*); 386template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
223template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*); 387template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);
388
389template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, std::string*,
390 uint64_t*);
391template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*,
392 uint64_t*);
393
394} // namespace unwindstack