libdw: dwarf_getsrcfiles should not imply dwarf_getsrclines

Message ID 20240410034539.164402-1-amerey@redhat.com
State Committed
Headers
Series libdw: dwarf_getsrcfiles should not imply dwarf_getsrclines |

Commit Message

Aaron Merey April 10, 2024, 3:45 a.m. UTC
  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>
---

v2 changes:
Restored support for DW_LNE_define_file.

Added DW_LNE_define_file testcase and testfile.

Added new function get_lines_or_files which is based on the old
__libdw_getsrclines.  __libdw_getsrclines and __libdw_getsrcfiles now
call get_lines_or_files.

Mentioned max resident set size improvement in the commit message.  I
did not mention a 5% speed up to rpm indexing that I have previously
talked about since I could not reliably reproduce it with v2 of the patch.
I suspect that speed up may have been due to the smaller max RSS reducing
swapping during that round of testing.

 libdw/dwarf_getsrcfiles.c       |  24 +-
 libdw/dwarf_getsrclines.c       | 661 ++++++++++++++++++++++----------
 libdw/dwarf_macro_getsrcfiles.c |   4 +-
 libdw/libdwP.h                  |  10 +
 tests/.gitignore                |   1 +
 tests/Makefile.am               |   6 +-
 tests/get-files-define-file.c   | 162 ++++++++
 tests/get-files.c               |   8 +
 tests/get-lines.c               |  20 +-
 tests/run-get-files.sh          |  65 +++-
 tests/testfile-define-file.bz2  | Bin 0 -> 24910 bytes
 11 files changed, 734 insertions(+), 227 deletions(-)
 create mode 100644 tests/get-files-define-file.c
 create mode 100644 tests/testfile-define-file.bz2
  

Comments

Mark Wielaard April 10, 2024, 7:47 p.m. UTC | #1
Hi Aaron,

On Tue, 2024-04-09 at 23:45 -0400, Aaron Merey wrote:
> 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>
> ---
> 
> v2 changes:
> Restored support for DW_LNE_define_file.

Great. And sorry I first suggested to just drop it and then said I
would like it back. This was more work than I though.

> Added DW_LNE_define_file testcase and testfile.

Nice. How did you edit this file?

> Added new function get_lines_or_files which is based on the old
> __libdw_getsrclines.  __libdw_getsrclines and __libdw_getsrcfiles now
> call get_lines_or_files.

It is just a simple rename, but so much nicer to my eyes. Thanks.

> Mentioned max resident set size improvement in the commit message.  I
> did not mention a 5% speed up to rpm indexing that I have previously
> talked about since I could not reliably reproduce it with v2 of the patch.
> I suspect that speed up may have been due to the smaller max RSS reducing
> swapping during that round of testing.

Makes sense. And a reduction of 75% of the max resident size it pretty
huge in itself.

> +            case DW_LNE_define_file:
> +              {
> +                char *fname = (char *) linep;
> +                uint8_t *endp = memchr (linep, '\0', lineendp - linep);
> +                if (endp == NULL)
> +                  goto invalid_data;
> +                size_t fnamelen = endp - linep;
> +                linep = endp + 1;
> +
> +                unsigned int diridx;
> +                if (unlikely (linep >= lineendp))
> +                  goto invalid_data;
> +                get_uleb128 (diridx, linep, lineendp);
> +
> +		size_t ndirs = (*filesp)->ndirs;

This one line uses tabs for indentation, all others spaces.

> +                if (unlikely (diridx >= ndirs))
> +                  {
> +                    __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
> +                    goto invalid_data;
> +                  }
> +                Dwarf_Word mtime;
> +                if (unlikely (linep >= lineendp))
> +                  goto invalid_data;
> +                get_uleb128 (mtime, linep, lineendp);
> +                Dwarf_Word filelength;
> +                if (unlikely (linep >= lineendp))
> +                  goto invalid_data;
> +                get_uleb128 (filelength, linep, lineendp);
> +
> +		/* 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_INVALID_DIR_IDX);
> -		    goto invalid_data;
> +		    __libdw_seterrno (DWARF_E_NOMEM);
> +		    goto out;
>  		  }

And this last block uses tabs again.

> -		Dwarf_Word mtime;
> -		if (unlikely (linep >= lineendp))
> -		  goto invalid_data;
> -		get_uleb128 (mtime, linep, lineendp);
> -		Dwarf_Word filelength;
> -		if (unlikely (linep >= lineendp))
> -		  goto invalid_data;
> -		get_uleb128 (filelength, linep, lineendp);
> -
> -		struct filelist *new_file = NEW_FILE ();
> -		if (fname[0] == '/')
> -		  new_file->info.name = fname;
> -		else
> -		  {
> -		    new_file->info.name =
> -		      libdw_alloc (dbg, char, 1, (dirarray[diridx].len + 1
> -						  + fnamelen + 1));
> -		    char *cp = new_file->info.name;
> -
> -		    if (dirarray[diridx].dir != 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++ = '/';
> -		      }
> -		    strcpy (cp, fname);
> -		  }
> -
> -		new_file->info.mtime = mtime;
> -		new_file->info.length = filelength;
> -	      }
> -	      break;
> +		nfilelist++;
> +		new_file->next = filelist;
> +		filelist = new_file;

Here tabs again, then the rest spaces.

> +                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, (dnamelen + fnamelen + 2));
> +                    char *cp = new_file->info.name;
> +
> +                    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, dname);
> +                        *cp++ = '/';
> +                      }
> +                    strcpy (cp, fname);
> +                  }
> +
> +                new_file->info.mtime = mtime;
> +                new_file->info.length = filelength;
> +              }
> +              break;
> 

So inconsistent indentation, but the code looks good.

> @@ -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];

Again slightly off indentation.
But I also don't fully follow the prevdirs/newdirs copying.
Why is this? No newdirs are defined here, are there?
Maybe I don't understand the data-structure used here.


> diff --git a/tests/.gitignore b/tests/.gitignore
> index 0289959d..e40ad238 100644
> --- a/tests/.gitignore
> +++ b/tests/.gitignore
> @@ -74,6 +74,7 @@
>  /funcscopes
>  /get-aranges
>  /get-files
> +/get-files-define_file
>  /get-lines
>  /get-pubnames
>  /get-units-invalid
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index 9141074f..7b016dc8 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -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 \
> @@ -646,7 +646,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
> @@ -725,6 +726,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
> index 00000000..583f9852
> --- /dev/null
> +++ b/tests/get-files-define-file.c
> @@ -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;
> +}
> 
> [...]
> diff --git a/tests/run-get-files.sh b/tests/run-get-files.sh
> index 1306544d..c2bc01bf 100755
> --- a/tests/run-get-files.sh
> +++ b/tests/run-get-files.sh
> @@ -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,67 @@ 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 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
> +
> +cat define-files.out | testrun_compare ${abs_builddir}/get-files-define-file testfile-define-file
> +
>  exit 0

Nice.

So testfile-define-file is actually testfile36.debug but with a new
line program? How did you edit/insert that one?

Cheers,

Mark
  
Aaron Merey April 10, 2024, 8:43 p.m. UTC | #2
Hi Mark,

On Wed, Apr 10, 2024 at 3:48 PM Mark Wielaard <mark@klomp.org> wrote:
> > v2 changes:
> > Restored support for DW_LNE_define_file.
>
> Great. And sorry I first suggested to just drop it and then said I
> would like it back. This was more work than I though.

No problem, better if we support this just in case.

> This one line uses tabs for indentation, all others spaces.
> [...]
> And this last block uses tabs again.
> [...]
> Here tabs again, then the rest spaces.
> [...]
> So inconsistent indentation, but the code looks good.

Fixed the indentation.

> > -  /* 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];
>
> Again slightly off indentation.
> But I also don't fully follow the prevdirs/newdirs copying.
> Why is this? No newdirs are defined here, are there?
> Maybe I don't understand the data-structure used here.

The directories are the same but we still need to copy them so that
dwarf_getsrcdirs can find newfiles' dir names.

Dwarf_Files is an unusual structure since it doesn't contain a member
specifically for the array of dirnames.  Instead they're stored at
the end of the Dwarf_Fileinfo array member.

> So testfile-define-file is actually testfile36.debug but with a new
> line program? How did you edit/insert that one?

I used xxd to create a hexdump of testfile36.debug and modified the line
program by hand with a text editor.  I converted the modified hexdump
back to a binary with xxd -r.

I chose testfile36.debug because its .debug_line includes multiple
directory and file names.  It also contains a single short line program
that was easy to replace with two DW_LNE_define_file opcodes without
corrupting things.

Aaron
  
Mark Wielaard April 11, 2024, 9:55 a.m. UTC | #3
Hi Aaron,

On Wed, Apr 10, 2024 at 04:43:53PM -0400, Aaron Merey wrote:
> > > -  /* 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];
> >
> > Again slightly off indentation.
> > But I also don't fully follow the prevdirs/newdirs copying.
> > Why is this? No newdirs are defined here, are there?
> > Maybe I don't understand the data-structure used here.
> 
> The directories are the same but we still need to copy them so that
> dwarf_getsrcdirs can find newfiles' dir names.
> 
> Dwarf_Files is an unusual structure since it doesn't contain a member
> specifically for the array of dirnames.  Instead they're stored at
> the end of the Dwarf_Fileinfo array member.

Aha. Thanks for explaining. Clearly I should not try to review code if
I don't understand the underlying data structures.

> > So testfile-define-file is actually testfile36.debug but with a new
> > line program? How did you edit/insert that one?
> 
> I used xxd to create a hexdump of testfile36.debug and modified the line
> program by hand with a text editor.  I converted the modified hexdump
> back to a binary with xxd -r.
> 
> I chose testfile36.debug because its .debug_line includes multiple
> directory and file names.  It also contains a single short line program
> that was easy to replace with two DW_LNE_define_file opcodes without
> corrupting things.

Fun. Could you add a small description to tests/run-get-files.sh where
testfile-define-file is use so future hackers know how the file was
created?

All looks good BTW. Please do push (if possible with the above change).

Thanks,

Mark
  
Aaron Merey April 11, 2024, 4:41 p.m. UTC | #4
On Thu, Apr 11, 2024 at 5:55 AM Mark Wielaard <mark@klomp.org> wrote:
>
> All looks good BTW. Please do push (if possible with the above change).

Thanks Mark, pushed as commit d4b0848be5f575ff9464fee12ce7be416e4fb392

Aaron
  

Patch

diff --git a/libdw/dwarf_getsrcfiles.c b/libdw/dwarf_getsrcfiles.c
index cd2e5b5a..24e4b7d2 100644
--- a/libdw/dwarf_getsrcfiles.c
+++ b/libdw/dwarf_getsrcfiles.c
@@ -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)
diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c
index 69e10c7b..e30695f3 100644
--- a/libdw/dwarf_getsrclines.c
+++ b/libdw/dwarf_getsrclines.c
@@ -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;
@@ -790,63 +924,85 @@  read_srclines (Dwarf *dbg,
 		goto out;
 	      break;
 
-	    case DW_LNE_define_file:
-	      {
-		char *fname = (char *) linep;
-		uint8_t *endp = memchr (linep, '\0', lineendp - linep);
-		if (endp == NULL)
-		  goto invalid_data;
-		size_t fnamelen = endp - linep;
-		linep = endp + 1;
-
-		unsigned int diridx;
-		if (unlikely (linep >= lineendp))
-		  goto invalid_data;
-		get_uleb128 (diridx, linep, lineendp);
-		if (unlikely (diridx >= ndirlist))
+            case DW_LNE_define_file:
+              {
+                char *fname = (char *) linep;
+                uint8_t *endp = memchr (linep, '\0', lineendp - linep);
+                if (endp == NULL)
+                  goto invalid_data;
+                size_t fnamelen = endp - linep;
+                linep = endp + 1;
+
+                unsigned int diridx;
+                if (unlikely (linep >= lineendp))
+                  goto invalid_data;
+                get_uleb128 (diridx, linep, lineendp);
+
+		size_t ndirs = (*filesp)->ndirs;
+                if (unlikely (diridx >= ndirs))
+                  {
+                    __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
+                    goto invalid_data;
+                  }
+                Dwarf_Word mtime;
+                if (unlikely (linep >= lineendp))
+                  goto invalid_data;
+                get_uleb128 (mtime, linep, lineendp);
+                Dwarf_Word filelength;
+                if (unlikely (linep >= lineendp))
+                  goto invalid_data;
+                get_uleb128 (filelength, linep, lineendp);
+
+		/* 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_INVALID_DIR_IDX);
-		    goto invalid_data;
+		    __libdw_seterrno (DWARF_E_NOMEM);
+		    goto out;
 		  }
-		Dwarf_Word mtime;
-		if (unlikely (linep >= lineendp))
-		  goto invalid_data;
-		get_uleb128 (mtime, linep, lineendp);
-		Dwarf_Word filelength;
-		if (unlikely (linep >= lineendp))
-		  goto invalid_data;
-		get_uleb128 (filelength, linep, lineendp);
-
-		struct filelist *new_file = NEW_FILE ();
-		if (fname[0] == '/')
-		  new_file->info.name = fname;
-		else
-		  {
-		    new_file->info.name =
-		      libdw_alloc (dbg, char, 1, (dirarray[diridx].len + 1
-						  + fnamelen + 1));
-		    char *cp = new_file->info.name;
-
-		    if (dirarray[diridx].dir != 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++ = '/';
-		      }
-		    strcpy (cp, fname);
-		  }
-
-		new_file->info.mtime = mtime;
-		new_file->info.length = filelength;
-	      }
-	      break;
+		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, (dnamelen + fnamelen + 2));
+                    char *cp = new_file->info.name;
+
+                    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, dname);
+                        *cp++ = '/';
+                      }
+                    strcpy (cp, fname);
+                  }
+
+                new_file->info.mtime = mtime;
+                new_file->info.length = filelength;
+              }
+              break;
 
 	    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;
+
+invalid_data:
+  __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
 
- out:
+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)
diff --git a/libdw/dwarf_macro_getsrcfiles.c b/libdw/dwarf_macro_getsrcfiles.c
index 11c587af..5e02935d 100644
--- a/libdw/dwarf_macro_getsrcfiles.c
+++ b/libdw/dwarf_macro_getsrcfiles.c
@@ -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;
     }
 
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index c1c84ed3..e55ff50a 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -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);
 
diff --git a/tests/.gitignore b/tests/.gitignore
index 0289959d..e40ad238 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -74,6 +74,7 @@ 
 /funcscopes
 /get-aranges
 /get-files
+/get-files-define_file
 /get-lines
 /get-pubnames
 /get-units-invalid
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9141074f..7b016dc8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -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 \
@@ -646,7 +646,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
@@ -725,6 +726,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
index 00000000..583f9852
--- /dev/null
+++ b/tests/get-files-define-file.c
@@ -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;
+}
diff --git a/tests/get-files.c b/tests/get-files.c
index 04091733..fa65aa93 100644
--- a/tests/get-files.c
+++ b/tests/get-files.c
@@ -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)
diff --git a/tests/get-lines.c b/tests/get-lines.c
index 188d0162..77fb3c54 100644
--- a/tests/get-lines.c
+++ b/tests/get-lines.c
@@ -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)
 		{
diff --git a/tests/run-get-files.sh b/tests/run-get-files.sh
index 1306544d..c2bc01bf 100755
--- a/tests/run-get-files.sh
+++ b/tests/run-get-files.sh
@@ -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,67 @@  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 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
+
+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
index 0000000000000000000000000000000000000000..32ee7b76545bd6e2afca786e8f0314df2e2d326b
GIT binary patch
literal 24910
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
H+)L6<#`!(z

literal 0
HcmV?d00001

-- 
2.43.0