This patch to libbacktrace changes it to read the debug sections as
individual sections if they are very large or are far apart.  This
uses less memory in some cases, and fixes some cases on 32-bit
systems.  In particular this fixes one of the problems in
https://github.com/ianlancetaylor/libbacktrace/issues/29.
Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu.
Committed to master.

Ian

2020-05-09  Ian Lance Taylor  <i...@golang.org>

* elf.c (elf_add): If debug sections are very large or far apart,
read them individually rather than as a single view.
diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index 9a866eb5048..eb481c588e7 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -2659,10 +2659,13 @@ elf_add (struct backtrace_state *state, const char 
*filename, int descriptor,
   uint32_t debugaltlink_buildid_size;
   off_t min_offset;
   off_t max_offset;
+  off_t debug_size;
   struct backtrace_view debug_view;
   int debug_view_valid;
   unsigned int using_debug_view;
   uint16_t *zdebug_table;
+  struct backtrace_view split_debug_view[DEBUG_MAX];
+  unsigned char split_debug_view_valid[DEBUG_MAX];
   struct elf_ppc64_opd_data opd_data, *opd;
   struct dwarf_sections dwarf_sections;
 
@@ -2687,6 +2690,7 @@ elf_add (struct backtrace_state *state, const char 
*filename, int descriptor,
   debugaltlink_buildid_data = NULL;
   debugaltlink_buildid_size = 0;
   debug_view_valid = 0;
+  memset (&split_debug_view_valid[0], 0, sizeof split_debug_view_valid);
   opd = NULL;
 
   if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback,
@@ -3131,6 +3135,7 @@ elf_add (struct backtrace_state *state, const char 
*filename, int descriptor,
 
   min_offset = 0;
   max_offset = 0;
+  debug_size = 0;
   for (i = 0; i < (int) DEBUG_MAX; ++i)
     {
       off_t end;
@@ -3142,6 +3147,7 @@ elf_add (struct backtrace_state *state, const char 
*filename, int descriptor,
          end = sections[i].offset + sections[i].size;
          if (end > max_offset)
            max_offset = end;
+         debug_size += sections[i].size;
        }
       if (zsections[i].size != 0)
        {
@@ -3150,6 +3156,7 @@ elf_add (struct backtrace_state *state, const char 
*filename, int descriptor,
          end = zsections[i].offset + zsections[i].size;
          if (end > max_offset)
            max_offset = end;
+         debug_size += zsections[i].size;
        }
     }
   if (min_offset == 0 || max_offset == 0)
@@ -3159,11 +3166,45 @@ elf_add (struct backtrace_state *state, const char 
*filename, int descriptor,
       return 1;
     }
 
-  if (!backtrace_get_view (state, descriptor, min_offset,
-                          max_offset - min_offset,
-                          error_callback, data, &debug_view))
-    goto fail;
-  debug_view_valid = 1;
+  /* If the total debug section size is large, assume that there are
+     gaps between the sections, and read them individually.  */
+
+  if (max_offset - min_offset < 0x20000000
+      || max_offset - min_offset < debug_size + 0x10000)
+    {
+      if (!backtrace_get_view (state, descriptor, min_offset,
+                              max_offset - min_offset,
+                              error_callback, data, &debug_view))
+       goto fail;
+      debug_view_valid = 1;
+    }
+  else
+    {
+      memset (&split_debug_view[0], 0, sizeof split_debug_view);
+      for (i = 0; i < (int) DEBUG_MAX; ++i)
+       {
+         struct debug_section_info *dsec;
+
+         if (sections[i].size != 0)
+           dsec = &sections[i];
+         else if (zsections[i].size != 0)
+           dsec = &zsections[i];
+         else
+           continue;
+
+         if (!backtrace_get_view (state, descriptor, dsec->offset, dsec->size,
+                                  error_callback, data, &split_debug_view[i]))
+           goto fail;
+         split_debug_view_valid[i] = 1;
+
+         if (sections[i].size != 0)
+           sections[i].data = ((const unsigned char *)
+                               split_debug_view[i].data);
+         else
+           zsections[i].data = ((const unsigned char *)
+                                split_debug_view[i].data);
+       }
+    }
 
   /* We've read all we need from the executable.  */
   if (!backtrace_close (descriptor, error_callback, data))
@@ -3171,22 +3212,25 @@ elf_add (struct backtrace_state *state, const char 
*filename, int descriptor,
   descriptor = -1;
 
   using_debug_view = 0;
-  for (i = 0; i < (int) DEBUG_MAX; ++i)
+  if (debug_view_valid)
     {
-      if (sections[i].size == 0)
-       sections[i].data = NULL;
-      else
+      for (i = 0; i < (int) DEBUG_MAX; ++i)
        {
-         sections[i].data = ((const unsigned char *) debug_view.data
-                             + (sections[i].offset - min_offset));
-         ++using_debug_view;
-       }
+         if (sections[i].size == 0)
+           sections[i].data = NULL;
+         else
+           {
+             sections[i].data = ((const unsigned char *) debug_view.data
+                                 + (sections[i].offset - min_offset));
+             ++using_debug_view;
+           }
 
-      if (zsections[i].size == 0)
-       zsections[i].data = NULL;
-      else
-       zsections[i].data = ((const unsigned char *) debug_view.data
-                            + (zsections[i].offset - min_offset));
+         if (zsections[i].size == 0)
+           zsections[i].data = NULL;
+         else
+           zsections[i].data = ((const unsigned char *) debug_view.data
+                                + (zsections[i].offset - min_offset));
+       }
     }
 
   /* Uncompress the old format (--compress-debug-sections=zlib-gnu).  */
@@ -3218,6 +3262,13 @@ elf_add (struct backtrace_state *state, const char 
*filename, int descriptor,
          sections[i].data = uncompressed_data;
          sections[i].size = uncompressed_size;
          sections[i].compressed = 0;
+
+         if (split_debug_view_valid[i])
+           {
+             backtrace_release_view (state, &split_debug_view[i],
+                                     error_callback, data);
+             split_debug_view_valid[i] = 0;
+           }
        }
     }
 
@@ -3250,7 +3301,14 @@ elf_add (struct backtrace_state *state, const char 
*filename, int descriptor,
       sections[i].size = uncompressed_size;
       sections[i].compressed = 0;
 
-      --using_debug_view;
+      if (debug_view_valid)
+       --using_debug_view;
+      else if (split_debug_view_valid[i])
+       {
+         backtrace_release_view (state, &split_debug_view[i],
+                                 error_callback, data);
+         split_debug_view_valid[i] = 0;
+       }
     }
 
   if (zdebug_table != NULL)
@@ -3297,6 +3355,12 @@ elf_add (struct backtrace_state *state, const char 
*filename, int descriptor,
     backtrace_release_view (state, &buildid_view, error_callback, data);
   if (debug_view_valid)
     backtrace_release_view (state, &debug_view, error_callback, data);
+  for (i = 0; i < (int) DEBUG_MAX; ++i)
+    {
+      if (split_debug_view_valid[i])
+       backtrace_release_view (state, &split_debug_view[i],
+                               error_callback, data);
+    }
   if (opd)
     backtrace_release_view (state, &opd->view, error_callback, data);
   if (descriptor != -1)

Reply via email to