Cache DWARF location rules for a given pc.
Decoding the DWARF opcodes is expensive so make sure we cache it.
This speeds unwinding in simpleperf by over a factor of 3x.
Add unit tests for this new behavior.
Bug: 77258731
Test: libbacktrace/libunwindstack unit tests on host and target.
Test: Ran debuggerd -b on various processes on target.
Change-Id: Ia516c0fa5d3e5f76746190bb4b6fdf49fd1c9388
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 5586e72..65eec65 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -55,21 +55,29 @@
}
bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
- last_error_.code = DWARF_ERROR_NONE;
- const DwarfFde* fde = GetFdeFromPc(pc);
- if (fde == nullptr || fde->cie == nullptr) {
- last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
- return false;
- }
+ // Lookup the pc in the cache.
+ auto it = loc_regs_.upper_bound(pc);
+ if (it == loc_regs_.end() || pc < it->second.pc_start) {
+ last_error_.code = DWARF_ERROR_NONE;
+ const DwarfFde* fde = GetFdeFromPc(pc);
+ if (fde == nullptr || fde->cie == nullptr) {
+ last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
+ return false;
+ }
- // Now get the location information for this pc.
- dwarf_loc_regs_t loc_regs;
- if (!GetCfaLocationInfo(pc, fde, &loc_regs)) {
- return false;
+ // Now get the location information for this pc.
+ dwarf_loc_regs_t loc_regs;
+ if (!GetCfaLocationInfo(pc, fde, &loc_regs)) {
+ return false;
+ }
+ loc_regs.cie = fde->cie;
+
+ // Store it in the cache.
+ it = loc_regs_.emplace(loc_regs.pc_end, std::move(loc_regs)).first;
}
// Now eval the actual registers.
- return Eval(fde->cie, process_memory, loc_regs, regs, finished);
+ return Eval(it->second.cie, process_memory, it->second, regs, finished);
}
template <typename AddressType>