Merge "Update Android.bp"
diff --git a/include/libunwind_i.h b/include/libunwind_i.h
index 132f7ef..444a7b6 100644
--- a/include/libunwind_i.h
+++ b/include/libunwind_i.h
@@ -329,6 +329,8 @@
     bool valid;			/* true if the image is a valid elf image */
     bool load_attempted;	/* true if we've already attempted to load the elf */
     bool mapped;		/* true if the elf image was mmap'd in */
+    void* mini_debug_info_data;  /* decompressed .gnu_debugdata section */
+    size_t mini_debug_info_size;
     union
       {
         struct
diff --git a/include/tdep-aarch64/libunwind_i.h b/include/tdep-aarch64/libunwind_i.h
index d3d69ab..9104027 100644
--- a/include/tdep-aarch64/libunwind_i.h
+++ b/include/tdep-aarch64/libunwind_i.h
@@ -302,7 +302,7 @@
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (unw_tdep_context_t *uc, int reg);
 /* ANDROID support update. */
-extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image **ei,
 			       pid_t pid, unw_word_t ip,
 			       unsigned long *segbase, unsigned long *mapoff,
 			       char **path, void *as_arg);
diff --git a/include/tdep-arm/libunwind_i.h b/include/tdep-arm/libunwind_i.h
index c140c05..8ca1516 100644
--- a/include/tdep-arm/libunwind_i.h
+++ b/include/tdep-arm/libunwind_i.h
@@ -295,7 +295,7 @@
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (unw_tdep_context_t *uc, int reg);
 /* ANDROID support update. */
-extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image **ei,
 			       pid_t pid, unw_word_t ip,
 			       unsigned long *segbase, unsigned long *mapoff,
 			       char **path, void *as_arg);
diff --git a/include/tdep-hppa/libunwind_i.h b/include/tdep-hppa/libunwind_i.h
index ab737a8..4bffd76 100644
--- a/include/tdep-hppa/libunwind_i.h
+++ b/include/tdep-hppa/libunwind_i.h
@@ -285,7 +285,7 @@
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (ucontext_t *uc, int reg);
 /* ANDROID support update. */
-extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image **ei,
 			       pid_t pid, unw_word_t ip,
 			       unsigned long *segbase, unsigned long *mapoff,
 			       char **path, void *as_arg);
diff --git a/include/tdep-ia64/libunwind_i.h b/include/tdep-ia64/libunwind_i.h
index 41056c0..4b5a43b 100644
--- a/include/tdep-ia64/libunwind_i.h
+++ b/include/tdep-ia64/libunwind_i.h
@@ -268,7 +268,7 @@
 extern void *tdep_uc_addr (ucontext_t *uc, unw_regnum_t regnum,
 			   uint8_t *nat_bitnr);
 /* ANDROID support update. */
-extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image **ei,
 			       pid_t pid, unw_word_t ip,
 			       unsigned long *segbase, unsigned long *mapoff,
 			       char **path, void *as_arg);
diff --git a/include/tdep-mips/libunwind_i.h b/include/tdep-mips/libunwind_i.h
index c4059b2..fa4f39f 100644
--- a/include/tdep-mips/libunwind_i.h
+++ b/include/tdep-mips/libunwind_i.h
@@ -341,7 +341,7 @@
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (ucontext_t *uc, int reg);
 /* ANDROID support update. */
-extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image **ei,
 			       pid_t pid, unw_word_t ip,
 			       unsigned long *segbase, unsigned long *mapoff,
 			       char **path, void *as_arg);
diff --git a/include/tdep-ppc32/libunwind_i.h b/include/tdep-ppc32/libunwind_i.h
index c375b9b..ddf8f3a 100644
--- a/include/tdep-ppc32/libunwind_i.h
+++ b/include/tdep-ppc32/libunwind_i.h
@@ -306,7 +306,7 @@
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (ucontext_t * uc, int reg);
 /* ANDROID support update. */
-extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image **ei,
 			       pid_t pid, unw_word_t ip,
 			       unsigned long *segbase, unsigned long *mapoff,
 			       char **path, void *as_arg);
diff --git a/include/tdep-ppc64/libunwind_i.h b/include/tdep-ppc64/libunwind_i.h
index cbeb16a..fbb7a79 100644
--- a/include/tdep-ppc64/libunwind_i.h
+++ b/include/tdep-ppc64/libunwind_i.h
@@ -306,7 +306,7 @@
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (ucontext_t * uc, int reg);
 /* ANDROID support update. */
-extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image **ei,
 			       pid_t pid, unw_word_t ip,
 			       unsigned long *segbase, unsigned long *mapoff,
 			       char **path, void *as_arg);
diff --git a/include/tdep-sh/libunwind_i.h b/include/tdep-sh/libunwind_i.h
index 4a2afd7..e19e2ac 100644
--- a/include/tdep-sh/libunwind_i.h
+++ b/include/tdep-sh/libunwind_i.h
@@ -286,7 +286,7 @@
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (unw_tdep_context_t *uc, int reg);
 /* ANDROID support update. */
-extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image **ei,
 			       pid_t pid, unw_word_t ip,
 			       unsigned long *segbase, unsigned long *mapoff,
 			       char **path, void *as_arg);
diff --git a/include/tdep-x86/libunwind_i.h b/include/tdep-x86/libunwind_i.h
index f87bd71..96457e7 100644
--- a/include/tdep-x86/libunwind_i.h
+++ b/include/tdep-x86/libunwind_i.h
@@ -289,7 +289,7 @@
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (ucontext_t *uc, int reg);
 /* ANDROID support update. */
-extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image **ei,
 			       pid_t pid, unw_word_t ip,
 			       unsigned long *segbase, unsigned long *mapoff,
 			       char **path, void *as_arg);
diff --git a/include/tdep-x86_64/libunwind_i.h b/include/tdep-x86_64/libunwind_i.h
index 184989e..fd9cca4 100644
--- a/include/tdep-x86_64/libunwind_i.h
+++ b/include/tdep-x86_64/libunwind_i.h
@@ -235,7 +235,7 @@
 				     int need_unwind_info, void *arg);
 extern void *x86_64_r_uc_addr (ucontext_t *uc, int reg);
 /* ANDROID support update. */
-extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image **ei,
 			       pid_t pid, unw_word_t ip,
 			       unsigned long *segbase, unsigned long *mapoff,
 			       char **path, void *as_arg);
diff --git a/src/Los-common.c b/src/Los-common.c
index f52c1e2..f09e6f3 100644
--- a/src/Los-common.c
+++ b/src/Los-common.c
@@ -71,6 +71,9 @@
                 new_list->ei.u.memory.map = new_list;
               /* If it was mapped before, make sure to mark it unmapped now. */
               old_list->ei.mapped = false;
+              /* Clear the old mini debug info so we do not try to free it twice */
+              old_list->ei.mini_debug_info_data = NULL;
+              old_list->ei.mini_debug_info_size = 0;
               /* Don't bother breaking out of the loop, the next while check
                  is guaranteed to fail, causing us to break out of the loop
                  after advancing to the next map element. */
@@ -173,7 +176,7 @@
 }
 
 PROTECTED int
-local_get_elf_image (unw_addr_space_t as, struct elf_image *ei, unw_word_t ip,
+local_get_elf_image (unw_addr_space_t as, struct elf_image **ei, unw_word_t ip,
                      unsigned long *segbase, unsigned long *mapoff, char **path, void *as_arg)
 {
   struct map_info *map;
@@ -194,9 +197,9 @@
 
   if (map && elf_map_cached_image (as, as_arg, map, ip))
     {
-      *ei = map->ei;
+      *ei = &map->ei;
       *segbase = map->start;
-      if (ei->mapped)
+      if ((*ei)->mapped)
         *mapoff = map->offset;
       else
         /* Always use zero as the map offset for in memory maps. The
diff --git a/src/elfxx.c b/src/elfxx.c
index 7454778..efc1d51 100644
--- a/src/elfxx.c
+++ b/src/elfxx.c
@@ -479,6 +479,11 @@
   do {
     *dst_size *= 2;
     *dst = realloc(*dst, *dst_size);
+    if (*dst == NULL) {
+      Debug (1, "LZMA decompression failed due to failed realloc.\n");
+      XzUnpacker_Free(&state);
+      return false;
+    }
     src_remaining = src_size - src_offset;
     dst_remaining = *dst_size - dst_offset;
     int res = XzUnpacker_Code(&state,
@@ -553,14 +558,23 @@
   return false;
 }
 
-static bool
-elf_w (extract_minidebuginfo_mapped) (struct elf_image *ei, struct elf_image *mdi)
-{
+static bool elf_w (extract_minidebuginfo_mapped) (struct elf_image *ei, uint8_t** data, size_t* size) {
+  if (ei->mini_debug_info_data != NULL) {
+    // Return cached result.
+    *data = ei->mini_debug_info_data;
+    *size = ei->mini_debug_info_size;
+    return true;
+  }
   uint8_t *compressed = NULL;
   size_t compressed_len;
   if (elf_w (find_section_mapped) (ei, ".gnu_debugdata", &compressed, &compressed_len, NULL)) {
-    return elf_w (xz_decompress) (compressed, compressed_len,
-                                  (uint8_t**)&mdi->u.mapped.image, &mdi->u.mapped.size);
+    if (elf_w (xz_decompress) (compressed, compressed_len, data, size)) {
+      // Also cache the result for next time.
+      ei->mini_debug_info_data = *data;
+      ei->mini_debug_info_size = *size;
+      Debug (1, "Decompressed and cached .gnu_debugdata");
+      return true;
+    }
   }
   return false;
 }
@@ -584,10 +598,14 @@
 
   // If the ELF image doesn't contain a match, look up the symbol in
   // the MiniDebugInfo.
-  struct elf_image mdi;
-  if (ei->mapped && elf_w (extract_minidebuginfo_mapped) (ei, &mdi)) {
-    mdi.valid = elf_w (valid_object_mapped) (&mdi);
+  uint8_t* mdi_data;
+  size_t mdi_size;
+  if (ei->mapped && elf_w (extract_minidebuginfo_mapped) (ei, &mdi_data, &mdi_size)) {
+    struct elf_image mdi;
     mdi.mapped = true;
+    mdi.u.mapped.image = mdi_data;
+    mdi.u.mapped.size = mdi_size;
+    mdi.valid = elf_w (valid_object_mapped) (&mdi);
     // The ELF file might have been relocated after the debug
     // information has been compresses and embedded.
     ElfW(Addr) ei_text_address, mdi_text_address;
@@ -596,7 +614,6 @@
       load_offset += ei_text_address - mdi_text_address;
     }
     bool ret_val = elf_w (lookup_symbol) (as, ip, &mdi, load_offset, buf, buf_len, offp, &ehdr);
-    free(mdi.u.mapped.image);
     return ret_val;
   }
   return false;
@@ -606,13 +623,13 @@
     unw_addr_space_t as, pid_t pid, unw_word_t ip, char* buf, size_t buf_len,
     unw_word_t* offp, void* as_arg) {
   unsigned long segbase, mapoff;
-  struct elf_image ei;
+  struct elf_image* ei;
 
   if (tdep_get_elf_image(as, &ei, pid, ip, &segbase, &mapoff, NULL, as_arg) < 0) {
     return false;
   }
 
-  return elf_w (get_proc_name_in_image) (as, &ei, segbase, mapoff, ip, buf, buf_len, offp);
+  return elf_w (get_proc_name_in_image) (as, ei, segbase, mapoff, ip, buf, buf_len, offp);
 }
 
 HIDDEN bool elf_w (get_load_base) (struct elf_image* ei, unw_word_t mapoff, unw_word_t* load_base) {
diff --git a/src/mi/map.c b/src/mi/map.c
index b37ad14..2a297b8 100644
--- a/src/mi/map.c
+++ b/src/mi/map.c
@@ -122,6 +122,10 @@
         munmap (map->ei.u.mapped.image, map->ei.u.mapped.size);
       if (map->path)
         free (map->path);
+      if (map->ei.mini_debug_info_data) {
+        Debug(1, "Freed cached .gnu_debugdata");
+        free (map->ei.mini_debug_info_data);
+      }
       map_free_info (map);
     }
 }
diff --git a/src/os-common.c b/src/os-common.c
index 751c9d2..7e3d184 100644
--- a/src/os-common.c
+++ b/src/os-common.c
@@ -26,12 +26,12 @@
 #include "libunwind_i.h"
 #include "map_info.h"
 
-extern int local_get_elf_image (unw_addr_space_t as, struct elf_image *,
+extern int local_get_elf_image (unw_addr_space_t as, struct elf_image **,
                                 unw_word_t, unsigned long *, unsigned long *,
                                 char **, void *);
 
 PROTECTED int
-tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+tdep_get_elf_image (unw_addr_space_t as, struct elf_image **ei,
                     pid_t pid, unw_word_t ip,
                     unsigned long *segbase, unsigned long *mapoff, char **path,
                     void *as_arg)
@@ -48,9 +48,9 @@
   if (!elf_map_cached_image (as, as_arg, map, ip))
     return -UNW_ENOINFO;
 
-  *ei = map->ei;
+  *ei = &map->ei;
   *segbase = map->start;
-  if (ei->mapped)
+  if ((*ei)->mapped)
     *mapoff = map->offset;
   else
     /* Always use zero as the map offset for in memory maps. The
diff --git a/src/os-hpux.c b/src/os-hpux.c
index 2127c94..488641c 100644
--- a/src/os-hpux.c
+++ b/src/os-hpux.c
@@ -42,7 +42,7 @@
 }
 
 PROTECTED int
-tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+tdep_get_elf_image (unw_addr_space_t as, struct elf_image **ei,
                     pid_t pid, unw_word_t ip,
                     unsigned long *segbase, unsigned long *mapoff, char **path)
 {
@@ -119,7 +119,7 @@
 finish:
   if (map)
     {
-      *ei = map->ei;
+      *ei = &map->ei;
       *segbase = map->start;
       *mapoff = map->offset;
       if (path != NULL)
diff --git a/src/os-linux.c b/src/os-linux.c
index f65c98a..d52fdf0 100644
--- a/src/os-linux.c
+++ b/src/os-linux.c
@@ -62,6 +62,8 @@
       cur_map->ei.valid = false;
       cur_map->ei.load_attempted = false;
       cur_map->ei.mapped = false;
+      cur_map->ei.mini_debug_info_data = NULL;
+      cur_map->ei.mini_debug_info_size = 0;
 
       /* Indicate mapped memory of devices is special and should not
          be read or written. Use a special flag instead of zeroing the
diff --git a/src/ptrace/_UPT_find_proc_info.c b/src/ptrace/_UPT_find_proc_info.c
index acaa5f9..546f37e 100644
--- a/src/ptrace/_UPT_find_proc_info.c
+++ b/src/ptrace/_UPT_find_proc_info.c
@@ -37,7 +37,7 @@
 {
   /* ANDROID support update. */
   unsigned long segbase, mapoff;
-  struct elf_image ei;
+  struct elf_image* ei;
   int ret;
   char *path = NULL;
   /* End of ANDROID update. */
@@ -66,7 +66,7 @@
   if (tdep_get_elf_image (as, &ei, pid, ip, &segbase, &mapoff, &path, as_arg) < 0)
     return -UNW_ENOINFO;
 
-  ret = tdep_find_unwind_table (edi, &ei, as, path, segbase, mapoff, ip);
+  ret = tdep_find_unwind_table (edi, ei, as, path, segbase, mapoff, ip);
   free(path);
   if (ret < 0)
     return ret;