Cache uwnind frame headers as they are found.

Summary:
This improves unwind performance quite substantially, and follows
a somewhat similar approach used in libgcc_s as described in the
thread here:

https://gcc.gnu.org/ml/gcc/2005-02/msg00625.html

On certain extremely exception heavy internal tests, the time
drops from about 80 minutes to about five minutes.

Subscribers: libcxx-commits

Tags: #libc

Differential Revision: https://reviews.llvm.org/D75954

Cr-Mirrored-From: https://chromium.googlesource.com/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: c53c2058ffb8ff877702bb2dded31c85c1dfe66d
diff --git a/src/AddressSpace.hpp b/src/AddressSpace.hpp
index 83af9ae..a4564cb 100644
--- a/src/AddressSpace.hpp
+++ b/src/AddressSpace.hpp
@@ -452,6 +452,11 @@
     #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
   #endif
 
+#include "FrameHeaderCache.hpp"
+
+// There should be just one of these per process.
+static FrameHeaderCache ProcessFrameHeaderCache;
+
 static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
                                dl_iterate_cb_data *cbdata) {
   if (phdr->p_type == PT_LOAD) {
@@ -466,10 +471,13 @@
   return false;
 }
 
-int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t, void *data) {
+int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t pinfo_size,
+                             void *data) {
   auto cbdata = static_cast<dl_iterate_cb_data *>(data);
   if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr)
     return 0;
+  if (ProcessFrameHeaderCache.find(pinfo, pinfo_size, data))
+    return 1;
 
   Elf_Addr image_base = calculateImageBase(pinfo);
   bool found_obj = false;
@@ -496,8 +504,10 @@
     } else if (!found_obj) {
       found_obj = checkAddrInSegment(phdr, image_base, cbdata);
     }
-    if (found_obj && found_hdr)
+    if (found_obj && found_hdr) {
+      ProcessFrameHeaderCache.add(cbdata->sects);
       return 1;
+    }
   }
   cbdata->sects->dwarf_section_length = 0;
   return 0;