]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libbacktrace: sometimes read debug sections individually
authorIan Lance Taylor <iant@golang.org>
Sun, 16 Feb 2020 01:56:35 +0000 (17:56 -0800)
committerIan Lance Taylor <iant@golang.org>
Sat, 9 May 2020 23:00:54 +0000 (16:00 -0700)
libbacktrace/
* elf.c (elf_add): If debug sections are very large or far apart,
read them individually rather than as a single view.

libbacktrace/ChangeLog
libbacktrace/elf.c

index 1739be9eedd2b22176de0b6e36c05542bf37ec39..277d7c01ff32367da57a68c1b3bd5ee9f00300e9 100644 (file)
@@ -1,3 +1,8 @@
+2020-05-09  Ian Lance Taylor  <iant@golang.org>
+
+       * elf.c (elf_add): If debug sections are very large or far apart,
+       read them individually rather than as a single view.
+
 2020-05-08  Ian Lance Taylor  <iant@golang.org>
 
        * fileline.c (sysctl_exec_name): New static function.
index 9a866eb5048c17848aaa77dd10e8c34560126835..eb481c588e7e8e35499c141fdbe20c15cdca520b 100644 (file)
@@ -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)