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
(cherry picked from commit 3386ebade2d28fd3ef68c576bb0375bd226a1320)
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>