]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdw: dwarf_getsrcfiles should not imply dwarf_getsrclines
authorAaron Merey <amerey@redhat.com>
Mon, 25 Mar 2024 19:57:25 +0000 (15:57 -0400)
committerAaron Merey <amerey@redhat.com>
Thu, 11 Apr 2024 16:34:43 +0000 (12:34 -0400)
dwarf_getsrcfiles causes line data to be read in addition to file data.
This is wasteful for programs which only need file or directory names.
Debuginfod server is one such example.

Fix this by moving the srcfile reading in read_srclines into a separate
function read_srcfiles.  This change improves debuginfod server's max
resident set size by up to 75% during rpm indexing.

* libdw/dwarf_getsrcfiles.c (dwarf_getsrcfiles): Replace
dwarf_getsrclines and __libdw_getsrclines with
__libdw_getsrcfiles.
* libdw/dwarf_getsrclines.c (read_line_header): New function.
(read_srcfiles): New function.
(read_srclines): Move srcfile reading into read_srcfiles.
Add parameter to use cached srcfiles if available.
Also merge srcfiles with any files from DW_LNE_define_file.
(__libdw_getsrclines): Changed to call get_lines_or_files.
(__libdw_getsrcfiles): New function.  Calls get_lines_or_files.
(get_lines_or_files): New function based on the old
__libdw_getsrclines.  Call read_srcfiles if linesp is NULL,
otherwise call read_srclines.  Pass previously read srcfiles
to read_srclines if available.
* libdw/dwarf_macro_getsrcfiles.c (dwarf_macro_getsrcfiles):
Replace __libdw_getsrclines with __libdw_getsrcfiles.
* libdw/libdwP.h (__libdw_getsrcfiles): New declaration.
* tests/.gitignore: Add new test binary.
* tests/get-files.c: Verify that dwarf_getsrcfiles does
not cause srclines to be read.
* tests/get-lines.c: Verify that srclines can be read
after srcfiles have been read.
* tests/Makefile.am: Add new testfiles.
* tests/get-files-define-file.c: Print file names before
and after reading DW_LNE_define_file.
* tests/run-get-files.sh: Add get-files-define-file test.
* tests/testfile-define-file.bz2: New testfile.  Copy of
testfile36.debug but with a line program consisting of two
DW_LNE_define_file opcodes.

https://sourceware.org/bugzilla/show_bug.cgi?id=27405

Signed-off-by: Aaron Merey <amerey@redhat.com>
libdw/dwarf_getsrcfiles.c
libdw/dwarf_getsrclines.c
libdw/dwarf_macro_getsrcfiles.c
libdw/libdwP.h
tests/.gitignore
tests/Makefile.am
tests/get-files-define-file.c [new file with mode: 0644]
tests/get-files.c
tests/get-lines.c
tests/run-get-files.sh
tests/testfile-define-file.bz2 [new file with mode: 0644]

index cd2e5b5aba5ed7429d20adbc4e33d08c9ad05d1d..24e4b7d287f622d2e0d8716073ffdcc588d6b328 100644 (file)
@@ -70,10 +70,9 @@ dwarf_getsrcfiles (Dwarf_Die *cudie, Dwarf_Files **files, size_t *nfiles)
                {
                  /* We are only interested in the files, the lines will
                     always come from the skeleton.  */
-                 res = __libdw_getsrclines (cu->dbg, dwp_off,
+                 res = __libdw_getsrcfiles (cu->dbg, dwp_off,
                                             __libdw_getcompdir (cudie),
-                                            cu->address_size, NULL,
-                                            &cu->files);
+                                            cu->address_size, &cu->files);
                }
            }
          else
@@ -89,12 +88,19 @@ dwarf_getsrcfiles (Dwarf_Die *cudie, Dwarf_Files **files, size_t *nfiles)
        }
       else
        {
-         Dwarf_Lines *lines;
-         size_t nlines;
-
-         /* Let the more generic function do the work.  It'll create more
-            data but that will be needed in an real program anyway.  */
-         res = INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines);
+         /* The die must have a statement list associated.  */
+         Dwarf_Attribute stmt_list_mem;
+         Dwarf_Attribute *stmt_list = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list,
+                                                          &stmt_list_mem);
+
+         Dwarf_Off debug_line_offset;
+         if (__libdw_formptr (stmt_list, IDX_debug_line, DWARF_E_NO_DEBUG_LINE,
+                              NULL, &debug_line_offset) == NULL)
+           return -1;
+
+         res = __libdw_getsrcfiles (cu->dbg, debug_line_offset,
+                                    __libdw_getcompdir (cudie),
+                                    cu->address_size, &cu->files);
        }
     }
   else if (cu->files != (void *) -1l)
index 69e10c7b13e4a7e9cab09f3a0dd90648dff7e93a..987a86fdd0e12c8a562f9b775665af9f23a137de 100644 (file)
@@ -52,6 +52,11 @@ struct linelist
   size_t sequence;
 };
 
+struct dirlist
+{
+  const char *dir;
+  size_t len;
+};
 
 /* Compare by Dwarf_Line.addr, given pointers into an array of pointers.  */
 static int
@@ -77,6 +82,28 @@ compare_lines (const void *a, const void *b)
     : 0;
 }
 
+/* Decoded .debug_line program header.  */
+struct line_header
+{
+  /* Header entries */
+  Dwarf_Word unit_length;
+  unsigned int length;
+  uint_fast16_t version;
+  size_t line_address_size;
+  size_t segment_selector_size;
+  Dwarf_Word header_length;
+  const unsigned char *header_start;
+  uint_fast8_t minimum_instr_len;
+  uint_fast8_t max_ops_per_instr;
+  uint_fast8_t default_is_stmt;
+  int_fast8_t line_base;
+  uint_fast8_t line_range;
+  uint_fast8_t opcode_base;
+  const uint8_t *standard_opcode_lengths;
+  unsigned int debug_str_offset;  /* CUBIN only */
+  size_t files_start;
+};
+
 struct line_state
 {
   Dwarf_Word addr;
@@ -155,127 +182,81 @@ add_new_line (struct line_state *state, struct linelist *new_line)
   return false;
 }
 
+/* Read the .debug_line program header.  Return 0 if sucessful, otherwise set
+   libdw errno and return -1.  */
+
 static int
-read_srclines (Dwarf *dbg,
-              const unsigned char *linep, const unsigned char *lineendp,
-              const char *comp_dir, unsigned address_size,
-              Dwarf_Lines **linesp, Dwarf_Files **filesp)
+read_line_header (Dwarf *dbg, unsigned address_size,
+                 const unsigned char *linep, const unsigned char *lineendp,
+                 struct line_header *lh)
 {
-  int res = -1;
-
-  struct filelist *filelist = NULL;
-  size_t nfilelist = 0;
-  size_t ndirlist = 0;
-
-  /* If there are a large number of lines, files or dirs don't blow up
-     the stack.  Stack allocate some entries, only dynamically malloc
-     when more than MAX.  */
-#define MAX_STACK_ALLOC 4096
-#define MAX_STACK_LINES (MAX_STACK_ALLOC / 2)
-#define MAX_STACK_FILES (MAX_STACK_ALLOC / 4)
-#define MAX_STACK_DIRS  (MAX_STACK_ALLOC / 16)
-
-  /* Initial statement program state (except for stmt_list, see below).  */
-  struct line_state state =
-    {
-      .linelist = NULL,
-      .nlinelist = 0,
-      .addr = 0,
-      .op_index = 0,
-      .file = 1,
-      /* We only store int but want to check for overflow (see SET above).  */
-      .line = 1,
-      .column = 0,
-      .basic_block = false,
-      .prologue_end = false,
-      .epilogue_begin = false,
-      .isa = 0,
-      .discriminator = 0,
-      .context = 0,
-      .function_name = 0
-    };
-
-  /* The dirs normally go on the stack, but if there are too many
-     we alloc them all.  Set up stack storage early, so we can check on
-     error if we need to free them or not.  */
-  struct dirlist
-  {
-    const char *dir;
-    size_t len;
-  };
-  struct dirlist dirstack[MAX_STACK_DIRS];
-  struct dirlist *dirarray = dirstack;
+  const unsigned char *line_start = linep;
 
   if (unlikely (linep + 4 > lineendp))
-    {
-    invalid_data:
-      __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
-      goto out;
-    }
+    goto invalid_data;
 
-  Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
-  unsigned int length = 4;
-  if (unlikely (unit_length == DWARF3_LENGTH_64_BIT))
+  lh->unit_length = read_4ubyte_unaligned_inc (dbg, linep);
+  lh->length = 4;
+  if (unlikely (lh->unit_length == DWARF3_LENGTH_64_BIT))
     {
       if (unlikely (linep + 8 > lineendp))
        goto invalid_data;
-      unit_length = read_8ubyte_unaligned_inc (dbg, linep);
-      length = 8;
+      lh->unit_length = read_8ubyte_unaligned_inc (dbg, linep);
+      lh->length = 8;
     }
 
   /* Check whether we have enough room in the section.  */
-  if (unlikely (unit_length > (size_t) (lineendp - linep)))
+  if (unlikely (lh->unit_length > (size_t) (lineendp - linep)))
     goto invalid_data;
-  lineendp = linep + unit_length;
+  lineendp = linep + lh->unit_length;
 
   /* The next element of the header is the version identifier.  */
   if ((size_t) (lineendp - linep) < 2)
     goto invalid_data;
-  uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
-  if (unlikely (version < 2) || unlikely (version > 5))
+  lh->version = read_2ubyte_unaligned_inc (dbg, linep);
+  if (unlikely (lh->version < 2) || unlikely (lh->version > 5))
     {
       __libdw_seterrno (DWARF_E_VERSION);
-      goto out;
+      return -1;
     }
 
   /* DWARF5 explicitly lists address and segment_selector sizes.  */
-  if (version >= 5)
+  if (lh->version >= 5)
     {
       if ((size_t) (lineendp - linep) < 2)
        goto invalid_data;
-      size_t line_address_size = *linep++;
-      size_t segment_selector_size = *linep++;
-      if (line_address_size != address_size || segment_selector_size != 0)
+      lh->line_address_size = *linep++;
+      lh->segment_selector_size = *linep++;
+      if (lh->line_address_size != address_size || lh->segment_selector_size != 0)
        goto invalid_data;
     }
 
   /* Next comes the header length.  */
-  Dwarf_Word header_length;
-  if (length == 4)
+  if (lh->length == 4)
     {
       if ((size_t) (lineendp - linep) < 4)
        goto invalid_data;
-      header_length = read_4ubyte_unaligned_inc (dbg, linep);
+      lh->header_length = read_4ubyte_unaligned_inc (dbg, linep);
     }
   else
     {
       if ((size_t) (lineendp - linep) < 8)
        goto invalid_data;
-      header_length = read_8ubyte_unaligned_inc (dbg, linep);
+      lh->header_length = read_8ubyte_unaligned_inc (dbg, linep);
     }
-  const unsigned char *header_start = linep;
+  lh->header_start = linep;
 
   /* Next the minimum instruction length.  */
-  uint_fast8_t minimum_instr_len = *linep++;
+  lh->minimum_instr_len = *linep++;
 
   /* Next the maximum operations per instruction, in version 4 format.  */
-  uint_fast8_t max_ops_per_instr = 1;
-  if (version >= 4)
+  lh->max_ops_per_instr = 1;
+  if (lh->version >= 4)
     {
       if (unlikely ((size_t) (lineendp - linep) < 1))
        goto invalid_data;
-      max_ops_per_instr = *linep++;
-      if (unlikely (max_ops_per_instr == 0))
+      lh->max_ops_per_instr = *linep++;
+      if (unlikely (lh->max_ops_per_instr == 0))
        goto invalid_data;
     }
 
@@ -285,23 +266,71 @@ read_srclines (Dwarf *dbg,
 
   /* Then the flag determining the default value of the is_stmt
      register.  */
-  uint_fast8_t default_is_stmt = *linep++;
+  lh->default_is_stmt = *linep++;
 
   /* Now the line base.  */
-  int_fast8_t line_base = (int8_t) *linep++;
+  lh->line_base = (int8_t) *linep++;
 
   /* And the line range.  */
-  uint_fast8_t line_range = *linep++;
+  lh->line_range = *linep++;
 
   /* The opcode base.  */
-  uint_fast8_t opcode_base = *linep++;
+  lh->opcode_base = *linep++;
 
   /* Remember array with the standard opcode length (-1 to account for
      the opcode with value zero not being mentioned).  */
-  const uint8_t *standard_opcode_lengths = linep - 1;
-  if (unlikely (lineendp - linep < opcode_base - 1))
+  lh->standard_opcode_lengths = linep - 1;
+  if (unlikely (lineendp - linep < lh->opcode_base - 1))
     goto invalid_data;
-  linep += opcode_base - 1;
+  linep += lh->opcode_base - 1;
+
+  /* Record beginning of the file information.  */
+  lh->files_start = (size_t) (linep - line_start);
+
+  return 0;
+
+invalid_data:
+  __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
+  return -1;
+}
+
+/* If there are a large number of lines, files or dirs don't blow up
+   the stack.  Stack allocate some entries, only dynamically malloc
+   when more than MAX.  */
+#define MAX_STACK_ALLOC 4096
+#define MAX_STACK_LINES (MAX_STACK_ALLOC / 2)
+#define MAX_STACK_FILES (MAX_STACK_ALLOC / 4)
+#define MAX_STACK_DIRS  (MAX_STACK_ALLOC / 16)
+
+static int
+read_srcfiles (Dwarf *dbg,
+              const unsigned char *linep, const unsigned char *lineendp,
+              const char *comp_dir, unsigned address_size,
+              struct line_header *lh, Dwarf_Files **filesp)
+{
+  if (filesp == NULL)
+    return -1;
+
+  struct line_header lh_local;
+
+  if (lh == NULL)
+    {
+      if (read_line_header (dbg, address_size, linep, lineendp, &lh_local) != 0)
+       return -1;
+      lh = &lh_local;
+    }
+
+  int res = -1;
+
+  struct filelist *filelist = NULL;
+  size_t nfilelist = 0;
+  size_t ndirlist = 0;
+
+  /* The dirs normally go on the stack, but if there are too many
+     we alloc them all.  Set up stack storage early, so we can check on
+     error if we need to free them or not.  */
+  struct dirlist dirstack[MAX_STACK_DIRS];
+  struct dirlist *dirarray = dirstack;
 
   /* To read DWARF5 dir and file lists we need to know the forms.  For
      now we skip everything, except the DW_LNCT_path and
@@ -311,12 +340,18 @@ read_srclines (Dwarf *dbg,
   unsigned char form_path = -1; /* Which forms is DW_LNCT_path.  */
   unsigned char form_idx = -1;  /* And which is DW_LNCT_directory_index.  */
 
+  /* Set lineendp to the end of the file information.  */
+  lineendp = lh->header_start + lh->header_length;
+
+  /* Advance linep to the beginning of the header's srcfile information.  */
+  linep += lh->files_start;
+
   /* To read/skip form data.  */
   Dwarf_CU fake_cu = {
     .dbg = dbg,
     .sec_idx = IDX_debug_line,
     .version = 5,
-    .offset_size = length,
+    .offset_size = lh->length,
     .address_size = address_size,
     .startp = (void *) linep,
     .endp = (void *) lineendp,
@@ -324,7 +359,7 @@ read_srclines (Dwarf *dbg,
 
   /* First count the entries.  */
   size_t ndirs = 0;
-  if (version < 5)
+  if (lh->version < 5)
     {
       const unsigned char *dirp = linep;
       while (dirp < lineendp && *dirp != 0)
@@ -395,7 +430,7 @@ read_srclines (Dwarf *dbg,
 
   /* Entry zero is implicit for older versions, but explicit for 5+.  */
   struct dirlist comp_dir_elem;
-  if (version < 5)
+  if (lh->version < 5)
     {
       /* First comes the list of directories.  Add the compilation
         directory first since the index zero is used for it.  */
@@ -482,7 +517,7 @@ read_srclines (Dwarf *dbg,
   fl; })
 
   /* Now read the files.  */
-  if (version < 5)
+  if (lh->version < 5)
     {
       if (unlikely (linep >= lineendp))
        goto invalid_data;
@@ -662,29 +697,114 @@ read_srclines (Dwarf *dbg,
        }
     }
 
-  unsigned int debug_str_offset = 0;
-  if (unlikely (linep == header_start + header_length - 4))
+  if (unlikely (linep == lh->header_start + lh->header_length - 4))
     {
       /* CUBINs contain an unsigned 4-byte offset */
-      debug_str_offset = read_4ubyte_unaligned_inc (dbg, linep);
+      lh->debug_str_offset = read_4ubyte_unaligned_inc (dbg, linep);
     }
 
   /* Consistency check.  */
-  if (unlikely (linep != header_start + header_length))
+  if (unlikely (linep != lh->header_start + lh->header_length))
+    goto invalid_data;
+
+  /* Put all the files in an array.  */
+  Dwarf_Files *files = libdw_alloc (dbg, Dwarf_Files,
+                                   sizeof (Dwarf_Files)
+                                   + nfilelist * sizeof (Dwarf_Fileinfo)
+                                   + (ndirlist + 1) * sizeof (char *),
+                                   1);
+
+  if (unlikely (files == NULL))
+    goto no_mem;
+
+  const char **dirs = (void *) &files->info[nfilelist];
+
+  struct filelist *fileslist = filelist;
+  files->nfiles = nfilelist;
+  for (size_t n = nfilelist; n > 0; n--)
     {
-      __libdw_seterrno (DWARF_E_INVALID_DWARF);
-      goto out;
+      files->info[n - 1] = fileslist->info;
+      fileslist = fileslist->next;
+    }
+  assert (fileslist == NULL);
+
+  /* Put all the directory strings in an array.  */
+  files->ndirs = ndirlist;
+  for (unsigned int i = 0; i < ndirlist; ++i)
+    dirs[i] = dirarray[i].dir;
+  dirs[ndirlist] = NULL;
+
+  /* Pass the file data structure to the caller.  */
+  *filesp = files;
+
+  res = 0;
+  goto out;
+
+invalid_data:
+  __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
+
+out:
+  if (dirarray != dirstack)
+    free (dirarray);
+  for (size_t i = MAX_STACK_FILES; i < nfilelist; i++)
+    {
+      struct filelist *fl = filelist->next;
+      free (filelist);
+      filelist = fl;
     }
 
+  return res;
+}
+
+static int
+read_srclines (Dwarf *dbg,
+              const unsigned char *linep, const unsigned char *lineendp,
+              const char *comp_dir, unsigned address_size,
+              Dwarf_Lines **linesp, Dwarf_Files **filesp,
+              bool use_cached_files)
+{
+  int res = -1;
+  struct line_header lh;
+
+  if (read_line_header (dbg, address_size, linep, lineendp, &lh) != 0)
+    return res;
+
+  /* Use the filesp srcfiles if they've already been read.  */
+  if (!use_cached_files
+      && read_srcfiles (dbg, linep, lineendp, comp_dir,
+                       address_size, &lh, filesp) != 0)
+    return res;
+
+  /* Initial statement program state (except for stmt_list, see below).  */
+  struct line_state state =
+    {
+      .linelist = NULL,
+      .nlinelist = 0,
+      .addr = 0,
+      .op_index = 0,
+      .file = 1,
+      /* We only store int but want to check for overflow (see SET above).  */
+      .line = 1,
+      .column = 0,
+      .basic_block = false,
+      .prologue_end = false,
+      .epilogue_begin = false,
+      .isa = 0,
+      .discriminator = 0,
+      .context = 0,
+      .function_name = 0
+    };
+
   /* We are about to process the statement program.  Most state machine
      registers have already been initialize above.  Just add the is_stmt
      default. See 6.2.2 in the v2.1 specification.  */
-  state.is_stmt = default_is_stmt;
+  state.is_stmt = lh.default_is_stmt;
 
   /* Apply the "operation advance" from a special opcode or
      DW_LNS_advance_pc (as per DWARF4 6.2.5.1).  */
 #define advance_pc(op_advance) \
-  run_advance_pc (&state, op_advance, minimum_instr_len, max_ops_per_instr)
+  run_advance_pc (&state, op_advance, lh.minimum_instr_len, \
+                 lh.max_ops_per_instr)
 
   /* Process the instructions.  */
 
@@ -697,12 +817,26 @@ read_srclines (Dwarf *dbg,
                           ? &llstack[state.nlinelist]          \
                           : malloc (sizeof (struct linelist)));        \
     if (unlikely (ll == NULL))                                 \
-      goto no_mem;                                             \
+    {                                                                  \
+       __libdw_seterrno (DWARF_E_NOMEM);                               \
+       goto out;                                                       \
+    }                                                                  \
     state.end_sequence = end_seq;                              \
     if (unlikely (add_new_line (&state, ll)))                  \
       goto invalid_data;                                               \
   } while (0)
 
+  /* If DW_LNE_define_file is present, then additional files will be
+     added to filesp.  */
+  size_t nfilelist = 0;
+  struct filelist *filelist = NULL;
+
+  /* Set lineendp to the end of the line program.  */
+  lineendp = linep + lh.length + lh.unit_length;
+
+  /* Set linep to the beginning of the line program.  */
+  linep = lh.header_start + lh.header_length;
+
   while (linep < lineendp)
     {
       unsigned int opcode;
@@ -713,9 +847,9 @@ read_srclines (Dwarf *dbg,
       opcode = *linep++;
 
       /* Is this a special opcode?  */
-      if (likely (opcode >= opcode_base))
+      if (likely (opcode >= lh.opcode_base))
        {
-         if (unlikely (line_range == 0))
+         if (unlikely (lh.line_range == 0))
            goto invalid_data;
 
          /* Yes.  Handling this is quite easy since the opcode value
@@ -724,12 +858,12 @@ read_srclines (Dwarf *dbg,
             opcode = (desired line increment - line_base)
                       + (line_range * address advance) + opcode_base
          */
-         int line_increment = (line_base
-                               + (opcode - opcode_base) % line_range);
+         int line_increment = (lh.line_base
+                               + (opcode - lh.opcode_base) % lh.line_range);
 
          /* Perform the increments.  */
          state.line += line_increment;
-         advance_pc ((opcode - opcode_base) / line_range);
+         advance_pc ((opcode - lh.opcode_base) / lh.line_range);
 
          /* Add a new line with the current state machine values.  */
          NEW_LINE (0);
@@ -768,7 +902,7 @@ read_srclines (Dwarf *dbg,
              state.file = 1;
              state.line = 1;
              state.column = 0;
-             state.is_stmt = default_is_stmt;
+             state.is_stmt = lh.default_is_stmt;
              state.basic_block = false;
              state.prologue_end = false;
              state.epilogue_begin = false;
@@ -803,7 +937,9 @@ read_srclines (Dwarf *dbg,
                if (unlikely (linep >= lineendp))
                  goto invalid_data;
                get_uleb128 (diridx, linep, lineendp);
-               if (unlikely (diridx >= ndirlist))
+
+               size_t ndirs = (*filesp)->ndirs;
+               if (unlikely (diridx >= ndirs))
                  {
                    __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
                    goto invalid_data;
@@ -817,23 +953,43 @@ read_srclines (Dwarf *dbg,
                  goto invalid_data;
                get_uleb128 (filelength, linep, lineendp);
 
-               struct filelist *new_file = NEW_FILE ();
+               /* Add new_file to filelist that will be merged with filesp.  */
+               struct filelist *new_file = malloc (sizeof (struct filelist));
+               if (unlikely (new_file == NULL))
+                 {
+                   __libdw_seterrno (DWARF_E_NOMEM);
+                   goto out;
+                 }
+               nfilelist++;
+               new_file->next = filelist;
+               filelist = new_file;
+
                if (fname[0] == '/')
                  new_file->info.name = fname;
                else
                  {
+                   /* Directory names are stored in a char *[ndirs] located
+                      after the last Dwarf_Fileinfo_s.  */
+                   size_t nfiles = (*filesp)->nfiles;
+                   const char **dirarray
+                     = (const char **) &((*filesp)->info[nfiles]);
+
+                   const char *dname = dirarray[diridx];
+                   size_t dnamelen = strlen (dname);
+
                    new_file->info.name =
-                     libdw_alloc (dbg, char, 1, (dirarray[diridx].len + 1
-                                                 + fnamelen + 1));
+                     libdw_alloc (dbg, char, 1, (dnamelen + fnamelen + 2));
                    char *cp = new_file->info.name;
 
-                   if (dirarray[diridx].dir != NULL)
+                   if (dname != NULL)
+
                      /* This value could be NULL in case the
                         DW_AT_comp_dir was not present.  We
                         cannot do much in this case.  Just
                         keep the file relative.  */
+
                      {
-                       cp = stpcpy (cp, dirarray[diridx].dir);
+                       cp = stpcpy (cp, dname);
                        *cp++ = '/';
                      }
                    strcpy (cp, fname);
@@ -846,7 +1002,7 @@ read_srclines (Dwarf *dbg,
 
            case DW_LNE_set_discriminator:
              /* Takes one ULEB128 parameter, the discriminator.  */
-             if (unlikely (standard_opcode_lengths[opcode] != 1))
+             if (unlikely (lh.standard_opcode_lengths[opcode] != 1))
                goto invalid_data;
 
              if (unlikely (linep >= lineendp))
@@ -861,14 +1017,14 @@ read_srclines (Dwarf *dbg,
              if (unlikely (linep >= lineendp))
                goto invalid_data;
              get_uleb128 (state.function_name, linep, lineendp);
-             state.function_name += debug_str_offset;
+             state.function_name += lh.debug_str_offset;
              break;
 
            case DW_LNE_NVIDIA_set_function_name:
              if (unlikely (linep >= lineendp))
                goto invalid_data;
              get_uleb128 (state.function_name, linep, lineendp);
-             state.function_name += debug_str_offset;
+             state.function_name += lh.debug_str_offset;
              break;
 
            default:
@@ -886,7 +1042,7 @@ read_srclines (Dwarf *dbg,
            {
            case DW_LNS_copy:
              /* Takes no argument.  */
-             if (unlikely (standard_opcode_lengths[opcode] != 0))
+             if (unlikely (lh.standard_opcode_lengths[opcode] != 0))
                goto invalid_data;
 
              /* Add a new line with the current state machine values.  */
@@ -902,7 +1058,7 @@ read_srclines (Dwarf *dbg,
            case DW_LNS_advance_pc:
              /* Takes one uleb128 parameter which is added to the
                 address.  */
-             if (unlikely (standard_opcode_lengths[opcode] != 1))
+             if (unlikely (lh.standard_opcode_lengths[opcode] != 1))
                goto invalid_data;
 
              if (unlikely (linep >= lineendp))
@@ -914,7 +1070,7 @@ read_srclines (Dwarf *dbg,
            case DW_LNS_advance_line:
              /* Takes one sleb128 parameter which is added to the
                 line.  */
-             if (unlikely (standard_opcode_lengths[opcode] != 1))
+             if (unlikely (lh.standard_opcode_lengths[opcode] != 1))
                goto invalid_data;
 
              if (unlikely (linep >= lineendp))
@@ -925,7 +1081,7 @@ read_srclines (Dwarf *dbg,
 
            case DW_LNS_set_file:
              /* Takes one uleb128 parameter which is stored in file.  */
-             if (unlikely (standard_opcode_lengths[opcode] != 1))
+             if (unlikely (lh.standard_opcode_lengths[opcode] != 1))
                goto invalid_data;
 
              if (unlikely (linep >= lineendp))
@@ -936,7 +1092,7 @@ read_srclines (Dwarf *dbg,
 
            case DW_LNS_set_column:
              /* Takes one uleb128 parameter which is stored in column.  */
-             if (unlikely (standard_opcode_lengths[opcode] != 1))
+             if (unlikely (lh.standard_opcode_lengths[opcode] != 1))
                goto invalid_data;
 
              if (unlikely (linep >= lineendp))
@@ -947,7 +1103,7 @@ read_srclines (Dwarf *dbg,
 
            case DW_LNS_negate_stmt:
              /* Takes no argument.  */
-             if (unlikely (standard_opcode_lengths[opcode] != 0))
+             if (unlikely (lh.standard_opcode_lengths[opcode] != 0))
                goto invalid_data;
 
              state.is_stmt = 1 - state.is_stmt;
@@ -955,7 +1111,7 @@ read_srclines (Dwarf *dbg,
 
            case DW_LNS_set_basic_block:
              /* Takes no argument.  */
-             if (unlikely (standard_opcode_lengths[opcode] != 0))
+             if (unlikely (lh.standard_opcode_lengths[opcode] != 0))
                goto invalid_data;
 
              state.basic_block = true;
@@ -963,19 +1119,19 @@ read_srclines (Dwarf *dbg,
 
            case DW_LNS_const_add_pc:
              /* Takes no argument.  */
-             if (unlikely (standard_opcode_lengths[opcode] != 0))
+             if (unlikely (lh.standard_opcode_lengths[opcode] != 0))
                goto invalid_data;
 
-             if (unlikely (line_range == 0))
+             if (unlikely (lh.line_range == 0))
                goto invalid_data;
 
-             advance_pc ((255 - opcode_base) / line_range);
+             advance_pc ((255 - lh.opcode_base) / lh.line_range);
              break;
 
            case DW_LNS_fixed_advance_pc:
              /* Takes one 16 bit parameter which is added to the
                 address.  */
-             if (unlikely (standard_opcode_lengths[opcode] != 1)
+             if (unlikely (lh.standard_opcode_lengths[opcode] != 1)
                  || unlikely (lineendp - linep < 2))
                goto invalid_data;
 
@@ -985,7 +1141,7 @@ read_srclines (Dwarf *dbg,
 
            case DW_LNS_set_prologue_end:
              /* Takes no argument.  */
-             if (unlikely (standard_opcode_lengths[opcode] != 0))
+             if (unlikely (lh.standard_opcode_lengths[opcode] != 0))
                goto invalid_data;
 
              state.prologue_end = true;
@@ -993,7 +1149,7 @@ read_srclines (Dwarf *dbg,
 
            case DW_LNS_set_epilogue_begin:
              /* Takes no argument.  */
-             if (unlikely (standard_opcode_lengths[opcode] != 0))
+             if (unlikely (lh.standard_opcode_lengths[opcode] != 0))
                goto invalid_data;
 
              state.epilogue_begin = true;
@@ -1001,7 +1157,7 @@ read_srclines (Dwarf *dbg,
 
            case DW_LNS_set_isa:
              /* Takes one uleb128 parameter which is stored in isa.  */
-             if (unlikely (standard_opcode_lengths[opcode] != 1))
+             if (unlikely (lh.standard_opcode_lengths[opcode] != 1))
                goto invalid_data;
 
              if (unlikely (linep >= lineendp))
@@ -1015,7 +1171,7 @@ read_srclines (Dwarf *dbg,
          /* This is a new opcode the generator but not we know about.
             Read the parameters associated with it but then discard
             everything.  Read all the parameters for this opcode.  */
-         for (int n = standard_opcode_lengths[opcode]; n > 0; --n)
+         for (int n = lh.standard_opcode_lengths[opcode]; n > 0; --n)
            {
              if (unlikely (linep >= lineendp))
                goto invalid_data;
@@ -1027,32 +1183,49 @@ read_srclines (Dwarf *dbg,
        }
     }
 
-  /* Put all the files in an array.  */
-  Dwarf_Files *files = libdw_alloc (dbg, Dwarf_Files,
-                                   sizeof (Dwarf_Files)
-                                   + nfilelist * sizeof (Dwarf_Fileinfo)
-                                   + (ndirlist + 1) * sizeof (char *),
-                                   1);
-  const char **dirs = (void *) &files->info[nfilelist];
-
-  struct filelist *fileslist = filelist;
-  files->nfiles = nfilelist;
-  for (size_t n = nfilelist; n > 0; n--)
+  /* Merge filesp with the files from DW_LNE_define_file, if any.  */
+  if (unlikely (filelist != NULL))
     {
-      files->info[n - 1] = fileslist->info;
-      fileslist = fileslist->next;
-    }
-  assert (fileslist == NULL);
+      Dwarf_Files *prevfiles = *filesp;
+      size_t ndirs = prevfiles->ndirs;
+      size_t nprevfiles = prevfiles->nfiles;
+      size_t nnewfiles = nprevfiles + nfilelist;
+
+      Dwarf_Files *newfiles
+       = libdw_alloc (dbg, Dwarf_Files,
+                      sizeof (Dwarf_Files)
+                       + nnewfiles * sizeof (Dwarf_Fileinfo)
+                       + (ndirs + 1) * sizeof (char *),
+                       1);
+
+
+      /* Copy prevfiles to newfiles.  */
+      for (size_t n = 0; n < nprevfiles; n++)
+       newfiles->info[n] = prevfiles->info[n];
+
+      /* Add files from DW_LNE_define_file to newfiles.  */
+      struct filelist *fileslist = filelist;
+      for (size_t n = nfilelist; n > 0; n--)
+       {
+         newfiles->info[nprevfiles + n - 1] = fileslist->info;
+         fileslist = fileslist->next;
+       }
 
-  /* Put all the directory strings in an array.  */
-  files->ndirs = ndirlist;
-  for (unsigned int i = 0; i < ndirlist; ++i)
-    dirs[i] = dirarray[i].dir;
-  dirs[ndirlist] = NULL;
+      if (fileslist != NULL)
+       goto invalid_data;
 
-  /* Pass the file data structure to the caller.  */
-  if (filesp != NULL)
-    *filesp = files;
+      const char **newdirs = (void *) &newfiles->info[nnewfiles];
+      const char **prevdirs = (void *) &prevfiles->info[nprevfiles];
+
+      /* Copy prevdirs to newdirs.  */
+      for (size_t n = 0; n < ndirs; n++)
+       newdirs[n] = prevdirs[n];
+
+      /* Update filesp.  */
+      newfiles->nfiles = nnewfiles;
+      newfiles->ndirs = prevfiles->ndirs;
+      *filesp = newfiles;
+    }
 
   size_t buf_size = (sizeof (Dwarf_Lines)
                     + (sizeof (Dwarf_Line) * state.nlinelist));
@@ -1087,7 +1260,7 @@ read_srclines (Dwarf *dbg,
   for (size_t i = 0; i < state.nlinelist; ++i)
     {
       lines->info[i] = sortlines[i]->line;
-      lines->info[i].files = files;
+      lines->info[i].files = *filesp;
     }
 
   /* Make sure the highest address for the CU is marked as end_sequence.
@@ -1102,8 +1275,12 @@ read_srclines (Dwarf *dbg,
 
   /* Success.  */
   res = 0;
+  goto out;
 
- out:
+invalid_data:
+  __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
+
+out:
   /* Free malloced line records, if any.  */
   for (size_t i = MAX_STACK_LINES; i < state.nlinelist; i++)
     {
@@ -1111,14 +1288,14 @@ read_srclines (Dwarf *dbg,
       free (state.linelist);
       state.linelist = ll;
     }
-  if (dirarray != dirstack)
-    free (dirarray);
-  for (size_t i = MAX_STACK_FILES; i < nfilelist; i++)
-    {
-      struct filelist *fl = filelist->next;
-      free (filelist);
-      filelist = fl;
-    }
+
+  /* Free file records from DW_LNE_define_file, if any.  */
+  for (size_t i = 0; i < nfilelist; i++)
+     {
+       struct filelist *fl = filelist->next;
+       free (filelist);
+       filelist = fl;
+     }
 
   return res;
 }
@@ -1137,17 +1314,17 @@ files_lines_compare (const void *p1, const void *p2)
   return 0;
 }
 
-int
-internal_function
-__libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
-                    const char *comp_dir, unsigned address_size,
-                    Dwarf_Lines **linesp, Dwarf_Files **filesp)
+static int
+get_lines_or_files (Dwarf *dbg, Dwarf_Off debug_line_offset,
+                   const char *comp_dir, unsigned address_size,
+                   Dwarf_Lines **linesp, Dwarf_Files **filesp)
 {
   struct files_lines_s fake = { .debug_line_offset = debug_line_offset };
   struct files_lines_s **found = tfind (&fake, &dbg->files_lines,
                                        files_lines_compare);
   if (found == NULL)
     {
+      /* This .debug_line is being read for the first time.  */
       Elf_Data *data = __libdw_checked_get_data (dbg, IDX_debug_line);
       if (data == NULL
          || __libdw_offset_in_section (dbg, IDX_debug_line,
@@ -1160,8 +1337,19 @@ __libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
       struct files_lines_s *node = libdw_alloc (dbg, struct files_lines_s,
                                                sizeof *node, 1);
 
-      if (read_srclines (dbg, linep, lineendp, comp_dir, address_size,
-                        &node->lines, &node->files) != 0)
+      /* Srcfiles will be read but srclines might not.  Set lines here
+        to avoid possible uninitialized value errors.  */
+      node->lines = NULL;
+
+      /* If linesp is NULL then read srcfiles without reading srclines.  */
+      if (linesp == NULL)
+       {
+         if (read_srcfiles (dbg, linep, lineendp, comp_dir, address_size,
+                            NULL, &node->files) != 0)
+           return -1;
+       }
+      else if (read_srclines (dbg, linep, lineendp, comp_dir, address_size,
+                        &node->lines, &node->files, false) != 0)
        return -1;
 
       node->debug_line_offset = debug_line_offset;
@@ -1173,6 +1361,35 @@ __libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
          return -1;
        }
     }
+  else if (*found != NULL
+          && (*found)->files != NULL
+          && (*found)->lines == NULL)
+    {
+      /* Srcfiles were already read from this .debug_line.  Now read
+        srclines.  */
+      Elf_Data *data = __libdw_checked_get_data (dbg, IDX_debug_line);
+      if (data == NULL
+         || __libdw_offset_in_section (dbg, IDX_debug_line,
+                                       debug_line_offset, 1) != 0)
+       return -1;
+
+      const unsigned char *linep = data->d_buf + debug_line_offset;
+      const unsigned char *lineendp = data->d_buf + data->d_size;
+
+      struct files_lines_s *node = *found;
+
+      if (read_srclines (dbg, linep, lineendp, comp_dir, address_size,
+                        &node->lines, &node->files, true) != 0)
+       return -1;
+    }
+  else if (*found != NULL
+          && (*found)->files == NULL
+          && (*found)->lines != NULL)
+    {
+      /* If srclines were read then srcfiles should have also been read.  */
+      __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
+      return -1;
+    }
 
   if (linesp != NULL)
     *linesp = (*found)->lines;
@@ -1183,6 +1400,26 @@ __libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
   return 0;
 }
 
+int
+internal_function
+__libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
+                    const char *comp_dir, unsigned address_size,
+                    Dwarf_Lines **linesp, Dwarf_Files **filesp)
+{
+  return get_lines_or_files (dbg, debug_line_offset, comp_dir,
+                            address_size, linesp, filesp);
+}
+
+int
+internal_function
+__libdw_getsrcfiles (Dwarf *dbg, Dwarf_Off debug_line_offset,
+                    const char *comp_dir, unsigned address_size,
+                    Dwarf_Files **filesp)
+{
+  return get_lines_or_files (dbg, debug_line_offset, comp_dir,
+                            address_size, NULL, filesp);
+}
+
 /* Get the compilation directory, if any is set.  */
 const char *
 __libdw_getcompdir (Dwarf_Die *cudie)
index 11c587af0d2790af2b83d988ef8c5c4613f0715d..5e02935d405e7b92bb7f3136d3d4357d857cda1e 100644 (file)
@@ -74,8 +74,8 @@ dwarf_macro_getsrcfiles (Dwarf *dbg, Dwarf_Macro *macro,
         the same unit through dwarf_getsrcfiles, and the file names
         will be broken.  */
 
-      if (__libdw_getsrclines (table->dbg, line_offset, table->comp_dir,
-                              table->address_size, NULL, &table->files) < 0)
+      if (__libdw_getsrcfiles (table->dbg, line_offset, table->comp_dir,
+                              table->address_size, &table->files) < 0)
        table->files = (void *) -1;
     }
 
index c1c84ed3567df23d7118b1f88f96e0c023a88110..e55ff50ac64a3de444fbb28c4850e78ce9c49265 100644 (file)
@@ -1108,6 +1108,16 @@ int __libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
   internal_function
   __nonnull_attribute__ (1);
 
+/* Load .debug_line unit at DEBUG_LINE_OFFSET.  COMP_DIR is a value of
+   DW_AT_comp_dir or NULL if that attribute is not available.  Caches
+   the loaded unit and set *FILESP with loaded information.  Returns 0
+   for success or a negative value for failure.  */
+int __libdw_getsrcfiles (Dwarf *dbg, Dwarf_Off debug_line_offset,
+                        const char *comp_dir, unsigned address_size,
+                        Dwarf_Files **filesp)
+  internal_function
+  __nonnull_attribute__ (1);
+
 /* Load and return value of DW_AT_comp_dir from CUDIE.  */
 const char *__libdw_getcompdir (Dwarf_Die *cudie);
 
index 772c7881ae3fef71684d2070de66ace098bb2bad..4937f0d1611f5c9729d0d9540e06c126bcb3f9cf 100644 (file)
@@ -75,6 +75,7 @@
 /funcscopes
 /get-aranges
 /get-files
+/get-files-define_file
 /get-lines
 /get-pubnames
 /get-units-invalid
index b7fb72384f3276ac797e87812c05171c944fc8a0..7aae3d8aa0e56f682e22162bf2c2f21b6146c202 100644 (file)
@@ -35,7 +35,7 @@ endif
 check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
                  showptable update1 update2 update3 update4 test-nlist \
                  show-die-info get-files next-files get-lines next-lines \
-                 get-pubnames \
+                 get-pubnames get-files-define-file \
                  get-aranges allfcts line2addr addrscopes funcscopes \
                  show-abbrev hash newscn ecp dwflmodtest \
                  find-prologues funcretval allregs rdwrmmap \
@@ -655,7 +655,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
             testfile-dwp-5-cu-index-overflow.dwp.bz2 \
             testfile-dwp-4-cu-index-overflow.bz2 \
             testfile-dwp-4-cu-index-overflow.dwp.bz2 \
-            testfile-dwp-cu-index-overflow.source
+            testfile-dwp-cu-index-overflow.source \
+            testfile-define-file.bz2
 
 
 if USE_VALGRIND
@@ -734,6 +735,7 @@ show_abbrev_LDADD = $(libdw) $(libelf)
 get_lines_LDADD = $(libdw) $(libelf)
 next_lines_LDADD = $(libdw) $(libelf)
 get_files_LDADD = $(libdw) $(libelf)
+get_files_define_file_LDADD = $(libdw) $(libelf)
 next_files_LDADD = $(libdw) $(libelf)
 get_aranges_LDADD = $(libdw) $(libelf)
 allfcts_LDADD = $(libdw) $(libelf)
diff --git a/tests/get-files-define-file.c b/tests/get-files-define-file.c
new file mode 100644 (file)
index 0000000..583f985
--- /dev/null
@@ -0,0 +1,162 @@
+/* Copyright (C) 2002, 2004, 2005, 2007 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <libelf.h>
+#include ELFUTILS_HEADER(dw)
+#include <stdio.h>
+#include <unistd.h>
+#include "../libdw/libdwP.h"
+
+static void
+print_dirs_and_files (Dwarf_Files *files, const char *const *dirs,
+                     size_t nfiles, size_t ndirs)
+{
+  if (dirs[0] == NULL)
+    puts (" dirs[0] = (null)");
+  else
+    printf (" dirs[0] = \"%s\"\n", dirs[0]);
+  for (size_t i = 1; i < ndirs; ++i)
+    printf (" dirs[%zu] = \"%s\"\n", i, dirs[i]);
+
+  for (size_t i = 0; i < nfiles; ++i)
+    printf (" file[%zu] = \"%s\"\n", i,
+           dwarf_filesrc (files, i, NULL, NULL));
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int result = 0;
+  int cnt = argc - 1;
+
+  int fd = open (argv[cnt], O_RDONLY);
+
+  Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ);
+  if (dbg == NULL)
+    {
+      printf ("%s not usable\n", argv[cnt]);
+      result = 1;
+      if (fd != -1)
+       close (fd);
+      goto out;
+    }
+
+  Dwarf_Off o = 0;
+  Dwarf_Off ncu;
+  size_t cuhl;
+
+  /* Just inspect the first CU.  */
+  if (dwarf_nextcu (dbg, o, &ncu, &cuhl, NULL, NULL, NULL) != 0)
+    {
+      printf ("%s: cannot get CU\n", argv[cnt]);
+      result = 1;
+      goto out;
+    }
+
+  Dwarf_Die die_mem;
+  Dwarf_Die *die = dwarf_offdie (dbg, o + cuhl, &die_mem);
+
+  if (die == NULL)
+    {
+      printf ("%s: cannot get CU die\n", argv[cnt]);
+      result = 1;
+      goto out;
+    }
+
+  Dwarf_Files *files;
+  size_t nfiles;
+
+  /* The files from DW_LNE_define_file should not be included
+     until dwarf_getsrclines is called.  */
+  if (dwarf_getsrcfiles (die, &files, &nfiles) != 0)
+    {
+      printf ("%s: cannot get files\n", argv[cnt]);
+      result = 1;
+      goto out;
+    }
+
+  if (die->cu->lines != NULL)
+    {
+      printf ("%s: dwarf_getsrcfiles should not get lines\n", argv[cnt]);
+      result = 1;
+      goto out;
+    }
+
+  const char *const *dirs;
+  size_t ndirs;
+  if (dwarf_getsrcdirs (files, &dirs, &ndirs) != 0)
+    {
+      printf ("%s: cannot get include directories\n", argv[cnt]);
+      result = 1;
+      goto out;
+    }
+
+  /* Print file info without files from DW_LNE_define_file.  */
+  print_dirs_and_files (files, dirs, nfiles, ndirs);
+
+  Dwarf_Lines *lines;
+  size_t nlines;
+
+  /* Reading the line program should add the new files.  */
+  if (dwarf_getsrclines (die, &lines, &nlines) != 0)
+    {
+      printf ("%s: cannot get lines\n", argv[cnt]);
+      result = 1;
+      goto out;
+    }
+
+  Dwarf_Files *updated_files;
+  size_t num_updated_files;
+
+  /* Get the new files.  */
+  if (dwarf_getsrcfiles (die, &updated_files, &num_updated_files) != 0)
+    {
+      printf ("%s: cannot get files\n", argv[cnt]);
+      result = 1;
+      goto out;
+    }
+
+  const char *const *updated_dirs;
+  size_t num_updated_dirs;
+
+  /* The dirs shouldn't change but verify that getsrcdirs still works.  */
+  if (dwarf_getsrcdirs (updated_files, &updated_dirs, &num_updated_dirs) != 0)
+    {
+      printf ("%s: cannot get include directories\n", argv[cnt]);
+      result = 1;
+      goto out;
+    }
+
+  /* Verify that we didn't invalidate the old file info.  */
+  print_dirs_and_files (files, dirs, nfiles, ndirs);
+
+  /* Print all files including those from DW_LNE_define_file.  */
+  print_dirs_and_files (updated_files, updated_dirs,
+                       num_updated_files, num_updated_dirs);
+
+out:
+  dwarf_end (dbg);
+  close (fd);
+
+  return result;
+}
index 04091733741c045a696acebf1389e71242576ca9..fa65aa9307177df8eecc3b204fda79244976af10 100644 (file)
@@ -24,6 +24,7 @@
 #include ELFUTILS_HEADER(dw)
 #include <stdio.h>
 #include <unistd.h>
+#include "../libdw/libdwP.h"
 
 
 int
@@ -76,6 +77,13 @@ main (int argc, char *argv[])
              break;
            }
 
+         if (die->cu->lines != NULL)
+           {
+             printf ("%s: dwarf_getsrcfiles should not get lines\n", argv[cnt]);
+             result = 1;
+             break;
+           }
+
          const char *const *dirs;
          size_t ndirs;
          if (dwarf_getsrcdirs (files, &dirs, &ndirs) != 0)
index 188d016243d9d4404a1fae3e0a61a0360e9f662c..77fb3c54c9d107bc0ed102ebea9887827376ac35 100644 (file)
@@ -26,6 +26,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include "../libdw/libdwP.h"
 
 
 int
@@ -69,6 +70,24 @@ main (int argc, char *argv[])
            }
          old_cuoff = cuoff;
 
+         Dwarf_Files *files;
+         size_t nfiles;
+
+         /* Get files first to test that lines are read separately.  */
+         if (dwarf_getsrcfiles (&die, &files, &nfiles) != 0)
+           {
+             printf ("%s: cannot get files\n", argv[cnt]);
+             result = 1;
+             break;
+           }
+
+         if (die.cu->lines != NULL)
+           {
+             printf ("%s: dwarf_getsrcfiles should not get lines\n", argv[cnt]);
+             result = 1;
+             break;
+           }
+
          Dwarf_Lines *lb;
          size_t nlb;
          if (dwarf_getsrclines (&die, &lb, &nlb) != 0)
@@ -103,7 +122,6 @@ main (int argc, char *argv[])
 
              /* Getting the file path through the Dwarf_Files should
                 result in the same path.  */
-             Dwarf_Files *files;
              size_t idx;
              if (dwarf_line_file (l, &files, &idx) != 0)
                {
index 1306544d687fd32d83d4354460f8696e25cbe693..baf107d693d43f30b4b8de6403003090c558b32d 100755 (executable)
@@ -18,7 +18,7 @@
 
 . $srcdir/test-subr.sh
 
-testfiles testfile testfile2
+testfiles testfile testfile2 testfile-define-file
 
 testrun_compare ${abs_builddir}/get-files testfile testfile2 <<\EOF
 cuhl = 11, o = 0, asz = 4, osz = 4, ncu = 191
@@ -245,4 +245,75 @@ cuhl = 11, o = 0, asz = 8, osz = 4, ncu = 857
  file[3] = "/usr/include/stdc-predef.h"
 EOF
 
+tempfiles files define-files.out get-files-define-file.out
+
+cat > files <<\EOF
+ dirs[0] = "session"
+ dirs[1] = "/home/wcohen/minimal_mod"
+ dirs[2] = "include/asm"
+ dirs[3] = "include/linux"
+ dirs[4] = "include/asm-generic"
+ file[0] = "???"
+ file[1] = "/home/wcohen/minimal_mod/minimal_mod.c"
+ file[2] = "include/asm/gcc_intrin.h"
+ file[3] = "include/linux/kernel.h"
+ file[4] = "include/asm/processor.h"
+ file[5] = "include/asm/types.h"
+ file[6] = "include/asm/ptrace.h"
+ file[7] = "include/linux/sched.h"
+ file[8] = "include/asm/thread_info.h"
+ file[9] = "include/linux/thread_info.h"
+ file[10] = "include/asm/atomic.h"
+ file[11] = "include/linux/list.h"
+ file[12] = "include/linux/cpumask.h"
+ file[13] = "include/linux/rbtree.h"
+ file[14] = "include/asm/page.h"
+ file[15] = "include/linux/rwsem.h"
+ file[16] = "include/asm/rwsem.h"
+ file[17] = "include/asm/spinlock.h"
+ file[18] = "include/linux/completion.h"
+ file[19] = "include/linux/wait.h"
+ file[20] = "include/linux/aio.h"
+ file[21] = "include/linux/workqueue.h"
+ file[22] = "include/linux/timer.h"
+ file[23] = "include/linux/types.h"
+ file[24] = "include/asm/posix_types.h"
+ file[25] = "include/linux/pid.h"
+ file[26] = "include/linux/time.h"
+ file[27] = "include/linux/capability.h"
+ file[28] = "include/linux/signal.h"
+ file[29] = "include/linux/resource.h"
+ file[30] = "include/linux/sem.h"
+ file[31] = "include/asm/fpu.h"
+ file[32] = "include/linux/fs_struct.h"
+ file[33] = "include/asm/signal.h"
+ file[34] = "include/asm/siginfo.h"
+ file[35] = "include/asm-generic/siginfo.h"
+ file[36] = "include/asm/nodedata.h"
+ file[37] = "include/linux/mmzone.h"
+ file[38] = "include/linux/jiffies.h"
+ file[39] = "include/asm/io.h"
+ file[40] = "include/asm/machvec.h"
+ file[41] = "include/asm/smp.h"
+ file[42] = "include/asm/numa.h"
+ file[43] = "include/linux/slab.h"
+EOF
+
+# Files should be printed 3 times, followed by the two files from
+# DW_LNE_define_file
+cat files > define-files.out
+cat files >> define-files.out
+cat files >> define-files.out
+echo ' file[44] = "include/asm/abc.c"' >> define-files.out
+echo ' file[45] = "include/linux/01.c"' >> define-files.out
+
+# testfile-define-file is a copy of testfile36.debug but with a modified
+# line program.  The line program in testfile-define-file consists of
+# two DW_LNE_define_file opcodes.
+#
+# xxd was used to create a hexdump of testfile36.debug and a text editor
+# was used to modify the line program.  The modified hexdump was converted
+# back to a binary with xxd -r.
+cat define-files.out | testrun_compare ${abs_builddir}/get-files-define-file testfile-define-file
+
 exit 0
diff --git a/tests/testfile-define-file.bz2 b/tests/testfile-define-file.bz2
new file mode 100644 (file)
index 0000000..32ee7b7
Binary files /dev/null and b/tests/testfile-define-file.bz2 differ