diff options
author | Christopher Ferris <cferris@google.com> | 2018-01-24 08:52:47 -0800 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2018-01-24 13:20:03 -0800 |
commit | 2e8c6e26e6a66186b3350a99d394a9deebd57fe9 (patch) | |
tree | 7d7f52e2461a6409057c61c4770c5b825af737ec /libunwindstack/ElfInterface.cpp | |
parent | c0e01d629de69f7ea5f10a98346dd4560e4fa688 (diff) | |
download | unwinding-2e8c6e26e6a66186b3350a99d394a9deebd57fe9.tar.gz |
Small behavioral changes to the unwinder.
- Be a little more lenient when reading the cies/fdes. If next entry data
winds up incorrect, don't fail, simply stop processing the entries. This
only applies when reading all of the cies/fdes at once.
- Fail to init an eh_frame with no entries and fallback to assuming the
eh_frame has no header instead.
- Change the step to always try debug_frame first which has the most
accurate information.
- Add small unit tests and a couple of offline unit tests to verify
this behavior.
These changes are needed to support offline unwinding since it depends
on this new behavior.
Bug: 65682279
Test: Ran new unit tests.
Change-Id: I3529f1b0c8e14cd7409494e5de2f3c9e78d0855e
Diffstat (limited to 'libunwindstack/ElfInterface.cpp')
-rw-r--r-- | libunwindstack/ElfInterface.cpp | 33 |
1 files changed, 19 insertions, 14 deletions
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp index 0e3ab2c..17cc16a 100644 --- a/libunwindstack/ElfInterface.cpp +++ b/libunwindstack/ElfInterface.cpp @@ -126,22 +126,26 @@ void ElfInterface::InitHeadersWithTemplate() { if (eh_frame_hdr_offset_ != 0) { eh_frame_.reset(new DwarfEhFrameWithHdr<AddressType>(memory_)); if (!eh_frame_->Init(eh_frame_hdr_offset_, eh_frame_hdr_size_)) { - // Even if the eh_frame_offset_ is non-zero, do not bother - // trying to read that since something has gone wrong. eh_frame_.reset(nullptr); - eh_frame_hdr_offset_ = 0; - eh_frame_hdr_size_ = static_cast<uint64_t>(-1); } - } else if (eh_frame_offset_ != 0) { - // If there is a eh_frame section without a eh_frame_hdr section. + } + + if (eh_frame_.get() == nullptr && eh_frame_offset_ != 0) { + // If there is an eh_frame section without an eh_frame_hdr section, + // or using the frame hdr object failed to init. eh_frame_.reset(new DwarfEhFrame<AddressType>(memory_)); if (!eh_frame_->Init(eh_frame_offset_, eh_frame_size_)) { eh_frame_.reset(nullptr); - eh_frame_offset_ = 0; - eh_frame_size_ = static_cast<uint64_t>(-1); } } + if (eh_frame_.get() == nullptr) { + eh_frame_hdr_offset_ = 0; + eh_frame_hdr_size_ = static_cast<uint64_t>(-1); + eh_frame_offset_ = 0; + eh_frame_size_ = static_cast<uint64_t>(-1); + } + if (debug_frame_offset_ != 0) { debug_frame_.reset(new DwarfDebugFrame<AddressType>(memory_)); if (!debug_frame_->Init(debug_frame_offset_, debug_frame_size_)) { @@ -436,15 +440,16 @@ bool ElfInterface::Step(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* pro } uint64_t adjusted_pc = pc - load_bias; - // Try the eh_frame first. - DwarfSection* eh_frame = eh_frame_.get(); - if (eh_frame != nullptr && eh_frame->Step(adjusted_pc, regs, process_memory, finished)) { + // Try the debug_frame first since it contains the most specific unwind + // information. + DwarfSection* debug_frame = debug_frame_.get(); + if (debug_frame != nullptr && debug_frame->Step(adjusted_pc, regs, process_memory, finished)) { return true; } - // Try the debug_frame next. - DwarfSection* debug_frame = debug_frame_.get(); - if (debug_frame != nullptr && debug_frame->Step(adjusted_pc, regs, process_memory, finished)) { + // Try the eh_frame next. + DwarfSection* eh_frame = eh_frame_.get(); + if (eh_frame != nullptr && eh_frame->Step(adjusted_pc, regs, process_memory, finished)) { return true; } |