diff options
Diffstat (limited to 'libunwindstack/ElfInterface.cpp')
-rw-r--r-- | libunwindstack/ElfInterface.cpp | 203 |
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 | |||
37 | namespace unwindstack { | ||
38 | |||
39 | ElfInterface::~ElfInterface() { | ||
40 | for (auto symbol : symbols_) { | ||
41 | delete symbol; | ||
42 | } | ||
43 | } | ||
44 | |||
45 | Memory* 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 | |||
99 | template <typename AddressType> | ||
100 | void 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 | ||
27 | template <typename EhdrType, typename PhdrType, typename ShdrType> | 120 | template <typename EhdrType, typename PhdrType, typename ShdrType> |
28 | bool ElfInterface::ReadAllHeaders() { | 121 | bool 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 | ||
40 | template <typename EhdrType, typename PhdrType> | 139 | template <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 | ||
208 | bool ElfInterface::Step(uint64_t, Regs*, Memory*) { | 336 | template <typename SymType> |
337 | bool 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 | |||
351 | bool 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. |
374 | template void ElfInterface::InitHeadersWithTemplate<uint32_t>(); | ||
375 | template void ElfInterface::InitHeadersWithTemplate<uint64_t>(); | ||
376 | |||
213 | template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(); | 377 | template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(); |
214 | template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(); | 378 | template 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 | ||
222 | template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*); | 386 | template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*); |
223 | template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*); | 387 | template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*); |
388 | |||
389 | template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, std::string*, | ||
390 | uint64_t*); | ||
391 | template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*, | ||
392 | uint64_t*); | ||
393 | |||
394 | } // namespace unwindstack | ||