This libbacktrace patch uses the correct directory and filename index
for DWARF 5.  For DWARF 4 and before, the zero entry for the directory
and filename information stored in the line program came from the
compilation unit.  Because of that, the old code used to handle zero
specially, and otherwise subtract one from the index.  For DWARF 5,
the zero entry is actually present in the tables, so it is no longer
appropriate to subtract one.  To make this work in the simplest
manner, just always store the zero entry in the tables, and stop
treating zero specially, and stop subtracting one.  For DWARF 4 and
before, fetch the zero entry from the compilation unit.  Bootstrapped
on x86_64-pc-linux-gnu.  The libbacktrace tests all pass.  The libgo
test all pass except for the ones that fail due to PR 98708.
Committed to mainline.

Ian

* dwarf.c (read_v2_paths): Allocate zero entry for dirs and
filenames.
(read_line_program): Remove parameter u, change caller.  Don't
subtract one from dirs and filenames index.
(read_function_entry): Don't subtract one from filenames index.
4817984f0f79656698e8b380e524f56a53881f15
diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c
index 3d0cbedf770..9097df6cc76 100644
--- a/libbacktrace/dwarf.c
+++ b/libbacktrace/dwarf.c
@@ -2344,19 +2344,20 @@ read_v2_paths (struct backtrace_state *state, struct 
unit *u,
       ++hdr->dirs_count;
     }
 
-  hdr->dirs = NULL;
-  if (hdr->dirs_count != 0)
-    {
-      hdr->dirs = ((const char **)
-                  backtrace_alloc (state,
-                                   hdr->dirs_count * sizeof (const char *),
-                                   hdr_buf->error_callback,
-                                   hdr_buf->data));
-      if (hdr->dirs == NULL)
-       return 0;
-    }
+  /* The index of the first entry in the list of directories is 1.  Index 0 is
+     used for the current directory of the compilation.  To simplify index
+     handling, we set entry 0 to the compilation unit directory.  */
+  ++hdr->dirs_count;
+  hdr->dirs = ((const char **)
+              backtrace_alloc (state,
+                               hdr->dirs_count * sizeof (const char *),
+                               hdr_buf->error_callback,
+                               hdr_buf->data));
+  if (hdr->dirs == NULL)
+    return 0;
 
-  i = 0;
+  hdr->dirs[0] = u->comp_dir;
+  i = 1;
   while (*hdr_buf->buf != '\0')
     {
       if (hdr_buf->reported_underflow)
@@ -2383,6 +2384,10 @@ read_v2_paths (struct backtrace_state *state, struct 
unit *u,
       ++hdr->filenames_count;
     }
 
+  /* The index of the first entry in the list of file names is 1.  Index 0 is
+     used for the DW_AT_name of the compilation unit.  To simplify index
+     handling, we set entry 0 to the compilation unit file name.  */
+  ++hdr->filenames_count;
   hdr->filenames = ((const char **)
                    backtrace_alloc (state,
                                     hdr->filenames_count * sizeof (char *),
@@ -2390,7 +2395,8 @@ read_v2_paths (struct backtrace_state *state, struct unit 
*u,
                                     hdr_buf->data));
   if (hdr->filenames == NULL)
     return 0;
-  i = 0;
+  hdr->filenames[0] = u->filename;
+  i = 1;
   while (*hdr_buf->buf != '\0')
     {
       const char *filename;
@@ -2404,7 +2410,7 @@ read_v2_paths (struct backtrace_state *state, struct unit 
*u,
        return 0;
       dir_index = read_uleb128 (hdr_buf);
       if (IS_ABSOLUTE_PATH (filename)
-         || (dir_index == 0 && u->comp_dir == NULL))
+         || (dir_index < hdr->dirs_count && hdr->dirs[dir_index] == NULL))
        hdr->filenames[i] = filename;
       else
        {
@@ -2413,10 +2419,8 @@ read_v2_paths (struct backtrace_state *state, struct 
unit *u,
          size_t filename_len;
          char *s;
 
-         if (dir_index == 0)
-           dir = u->comp_dir;
-         else if (dir_index - 1 < hdr->dirs_count)
-           dir = hdr->dirs[dir_index - 1];
+         if (dir_index < hdr->dirs_count)
+           dir = hdr->dirs[dir_index];
          else
            {
              dwarf_buf_error (hdr_buf,
@@ -2704,8 +2708,8 @@ read_line_header (struct backtrace_state *state, struct 
dwarf_data *ddata,
 
 static int
 read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
-                  struct unit *u, const struct line_header *hdr,
-                  struct dwarf_buf *line_buf, struct line_vector *vec)
+                  const struct line_header *hdr, struct dwarf_buf *line_buf,
+                  struct line_vector *vec)
 {
   uint64_t address;
   unsigned int op_index;
@@ -2715,8 +2719,8 @@ read_line_program (struct backtrace_state *state, struct 
dwarf_data *ddata,
 
   address = 0;
   op_index = 0;
-  if (hdr->filenames_count > 0)
-    reset_filename = hdr->filenames[0];
+  if (hdr->filenames_count > 1)
+    reset_filename = hdr->filenames[1];
   else
     reset_filename = "";
   filename = reset_filename;
@@ -2781,10 +2785,8 @@ read_line_program (struct backtrace_state *state, struct 
dwarf_data *ddata,
                    size_t f_len;
                    char *p;
 
-                   if (dir_index == 0 && hdr->version < 5)
-                     dir = u->comp_dir;
-                   else if (dir_index - 1 < hdr->dirs_count)
-                     dir = hdr->dirs[dir_index - 1];
+                   if (dir_index < hdr->dirs_count)
+                     dir = hdr->dirs[dir_index];
                    else
                      {
                        dwarf_buf_error (line_buf,
@@ -2851,14 +2853,14 @@ read_line_program (struct backtrace_state *state, 
struct dwarf_data *ddata,
                  filename = "";
                else
                  {
-                   if (fileno - 1 >= hdr->filenames_count)
+                   if (fileno >= hdr->filenames_count)
                      {
                        dwarf_buf_error (line_buf,
                                         ("invalid file number in "
                                          "line number program"));
                        return 0;
                      }
-                   filename = hdr->filenames[fileno - 1];
+                   filename = hdr->filenames[fileno];
                  }
              }
              break;
@@ -2948,7 +2950,7 @@ read_line_info (struct backtrace_state *state, struct 
dwarf_data *ddata,
   if (!read_line_header (state, ddata, u, is_dwarf64, &line_buf, hdr))
     goto fail;
 
-  if (!read_line_program (state, ddata, u, hdr, &line_buf, &vec))
+  if (!read_line_program (state, ddata, hdr, &line_buf, &vec))
     goto fail;
 
   if (line_buf.reported_underflow)
@@ -3289,7 +3291,7 @@ read_function_entry (struct backtrace_state *state, 
struct dwarf_data *ddata,
                        function->caller_filename = "";
                      else
                        {
-                         if (val.u.uint - 1 >= lhdr->filenames_count)
+                         if (val.u.uint >= lhdr->filenames_count)
                            {
                              dwarf_buf_error (unit_buf,
                                               ("invalid file number in "
@@ -3297,7 +3299,7 @@ read_function_entry (struct backtrace_state *state, 
struct dwarf_data *ddata,
                              return 0;
                            }
                          function->caller_filename =
-                           lhdr->filenames[val.u.uint - 1];
+                           lhdr->filenames[val.u.uint];
                        }
                    }
                  break;

Reply via email to