[v3,1/4] libdw: Handle split DWARF in dwarf_decl_file

Message ID f6421f642373c704eb442da534f276a02e66a806.1708974560.git.osandov@fb.com
State Committed
Headers
Series elfutils: DWARF package (.dwp) file support |

Commit Message

Omar Sandoval Feb. 26, 2024, 7:32 p.m. UTC
  From: Omar Sandoval <osandov@fb.com>

Calling dwarf_decl_file on a split DWARF DIE fails this assertion:

  dwarf_decl_file.c:72: dwarf_decl_file: Assertion `cu->files != NULL && cu->files != (void *) -1l' failed.

This is because dwarf_decl_file calls dwarf_getsrclines to populate
cu->files.  For normal units, cu->files is cached by dwarf_getsrclines
when it parses the line number information.  However, for split units,
the line number information is parsed for the skeleton unit, then copied
to the split unit's cu->lines.  Split units have their own file name
table, so cu->files is not copied.

The obvious solution is to use dwarf_getsrcfiles instead of relying on
implicit caching.

Also add a test case for dwarf_decl_file.

	* libdw/dwarf_decl_file.c (dwarf_decl_file): Use
	dwarf_getsrcfiles instead of dwarf_getsrclines.
	* tests/Makefile.am (check_PROGRAMS): Add declfiles.
	(TESTS): Add run-declfiles.sh.
	(EXTRA_DIST): Add run-declfiles.sh.
	(declfiles_LDADD): New variable.
	* tests/declfiles.c: New test.
	* tests/run-declfiles.sh: New test.

Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 libdw/dwarf_decl_file.c |  30 ++----
 tests/.gitignore        |   1 +
 tests/Makefile.am       |   8 +-
 tests/declfiles.c       |  90 ++++++++++++++++
 tests/run-declfiles.sh  | 233 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 335 insertions(+), 27 deletions(-)
 create mode 100644 tests/declfiles.c
 create mode 100755 tests/run-declfiles.sh
  

Comments

Mark Wielaard Feb. 29, 2024, 10:08 p.m. UTC | #1
Hi Omar,

On Mon, Feb 26, 2024 at 11:32:48AM -0800, Omar Sandoval wrote:
> Calling dwarf_decl_file on a split DWARF DIE fails this assertion:
> 
>   dwarf_decl_file.c:72: dwarf_decl_file: Assertion `cu->files != NULL && cu->files != (void *) -1l' failed.
> 
> This is because dwarf_decl_file calls dwarf_getsrclines to populate
> cu->files.  For normal units, cu->files is cached by dwarf_getsrclines
> when it parses the line number information.  However, for split units,
> the line number information is parsed for the skeleton unit, then copied
> to the split unit's cu->lines.  Split units have their own file name
> table, so cu->files is not copied.
> 
> The obvious solution is to use dwarf_getsrcfiles instead of relying on
> implicit caching.

And it cleans up the code nicely.

> Also add a test case for dwarf_decl_file.

Thanks.

> 
> 	* libdw/dwarf_decl_file.c (dwarf_decl_file): Use
> 	dwarf_getsrcfiles instead of dwarf_getsrclines.
> 	* tests/Makefile.am (check_PROGRAMS): Add declfiles.
> 	(TESTS): Add run-declfiles.sh.
> 	(EXTRA_DIST): Add run-declfiles.sh.
> 	(declfiles_LDADD): New variable.
> 	* tests/declfiles.c: New test.
> 	* tests/run-declfiles.sh: New test.

All looks good. Pushed.

Cheers,

Mark
  

Patch

diff --git a/libdw/dwarf_decl_file.c b/libdw/dwarf_decl_file.c
index 7dde4af0..1b91a4e9 100644
--- a/libdw/dwarf_decl_file.c
+++ b/libdw/dwarf_decl_file.c
@@ -48,35 +48,17 @@  dwarf_decl_file (Dwarf_Die *die)
 			       &idx) != 0)
     return NULL;
 
-  /* Get the array of source files for the CU.  */
-  struct Dwarf_CU *cu = attr_mem.cu;
-  if (cu->lines == NULL)
-    {
-      Dwarf_Lines *lines;
-      size_t nlines;
+  Dwarf_Files *files;
+  size_t nfiles;
+  if (INTUSE(dwarf_getsrcfiles) (&CUDIE (attr_mem.cu), &files, &nfiles) != 0)
+    return NULL;
 
-      /* Let the more generic function do the work.  It'll create more
-	 data but that will be needed in an real program anyway.  */
-      (void) INTUSE(dwarf_getsrclines) (&CUDIE (cu), &lines, &nlines);
-      assert (cu->lines != NULL);
-    }
-
-  if (cu->lines == (void *) -1l)
-    {
-      /* If DW_AT_decl_file was present, there should be file information
-	available.  */
-      __libdw_seterrno (DWARF_E_INVALID_DWARF);
-      return NULL;
-    }
-
-  assert (cu->files != NULL && cu->files != (void *) -1l);
-
-  if (idx >= cu->files->nfiles)
+  if (idx >= nfiles)
     {
       __libdw_seterrno (DWARF_E_INVALID_DWARF);
       return NULL;
     }
 
-  return cu->files->info[idx].name;
+  return files->info[idx].name;
 }
 OLD_VERSION (dwarf_decl_file, ELFUTILS_0.122)
diff --git a/tests/.gitignore b/tests/.gitignore
index d38f0f9e..0289959d 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -32,6 +32,7 @@ 
 /debugaltlink
 /debuginfod_build_id_find
 /debuglink
+/declfiles
 /deleted
 /dwarf-die-addr-die
 /dwarf-getmacros
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d7c53144..3f80c451 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -63,7 +63,7 @@  check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
 		  getphdrnum leb128 read_unaligned \
 		  msg_tst system-elf-libelf-test system-elf-gelf-test \
 		  nvidia_extended_linemap_libdw elf-print-reloc-syms \
-		  cu-dwp-section-info \
+		  cu-dwp-section-info declfiles \
 		  $(asm_TESTS)
 
 asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
@@ -213,7 +213,8 @@  TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
 	$(asm_TESTS) run-disasm-bpf.sh run-low_high_pc-dw-form-indirect.sh \
 	run-nvidia-extended-linemap-libdw.sh run-nvidia-extended-linemap-readelf.sh \
 	run-readelf-dw-form-indirect.sh run-strip-largealign.sh \
-	run-readelf-Dd.sh run-dwfl-core-noncontig.sh run-cu-dwp-section-info.sh
+	run-readelf-Dd.sh run-dwfl-core-noncontig.sh run-cu-dwp-section-info.sh \
+	run-declfiles.sh
 
 if !BIARCH
 export ELFUTILS_DISABLE_BIARCH = 1
@@ -640,7 +641,7 @@  EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
 	     testfile-dwp-4.bz2 testfile-dwp-4.dwp.bz2 \
 	     testfile-dwp-4-strict.bz2 testfile-dwp-4-strict.dwp.bz2 \
 	     testfile-dwp-5.bz2 testfile-dwp-5.dwp.bz2 testfile-dwp.source \
-	     run-cu-dwp-section-info.sh
+	     run-cu-dwp-section-info.sh run-declfiles.sh
 
 
 if USE_VALGRIND
@@ -818,6 +819,7 @@  read_unaligned_LDADD = $(libelf) $(libdw)
 nvidia_extended_linemap_libdw_LDADD = $(libelf) $(libdw)
 elf_print_reloc_syms_LDADD = $(libelf)
 cu_dwp_section_info_LDADD = $(libdw)
+declfiles_LDADD = $(libdw)
 
 # We want to test the libelf headers against the system elf.h header.
 # Don't include any -I CPPFLAGS. Except when we install our own elf.h.
diff --git a/tests/declfiles.c b/tests/declfiles.c
new file mode 100644
index 00000000..0842d637
--- /dev/null
+++ b/tests/declfiles.c
@@ -0,0 +1,90 @@ 
+/* Test program for dwarf_decl_file
+   Copyright (c) 2024 Meta Platforms, Inc. and affiliates.
+   This file is part of elfutils.
+
+   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 <stdio.h>
+#include <unistd.h>
+
+#include <dwarf.h>
+#include ELFUTILS_HEADER(dw)
+
+static void
+walk_tree (Dwarf_Die *dwarf_die, int indent)
+{
+  Dwarf_Die die = *dwarf_die;
+  do
+    {
+      int child_indent = indent;
+      const char *file = dwarf_decl_file (&die);
+      if (file != NULL)
+	{
+	  printf("%*s", indent, "");
+	  const char *name = dwarf_diename (&die) ?: "???";
+	  int line, column;
+	  if (dwarf_decl_line (&die, &line) == 0)
+	    {
+	      if (dwarf_decl_column (&die, &column) == 0)
+		printf ("%s@%s:%d:%d\n", name, file, line, column);
+	      else
+		printf ("%s@%s:%d\n", name, file, line);
+	    }
+	  else
+	    printf ("%s@%s\n", name, file);
+	  child_indent++;
+	}
+
+      Dwarf_Die child;
+      if (dwarf_child (&die, &child) == 0)
+	walk_tree (&child, child_indent);
+    }
+  while (dwarf_siblingof (&die, &die) == 0);
+}
+
+int
+main (int argc, char *argv[])
+{
+  for (int i = 1; i < argc; i++)
+    {
+      printf ("file: %s\n", argv[i]);
+      int fd = open (argv[i], O_RDONLY);
+      Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ);
+      if (dbg == NULL)
+	{
+	  printf ("%s not usable: %s\n", argv[i], dwarf_errmsg (-1));
+	  return -1;
+	}
+
+      Dwarf_CU *cu = NULL;
+      Dwarf_Die cudie, subdie;
+      uint8_t unit_type;
+      while (dwarf_get_units (dbg, cu, &cu, NULL, &unit_type, &cudie, &subdie)
+	     == 0)
+	{
+	  Dwarf_Die *die = unit_type == DW_UT_skeleton ? &subdie : &cudie;
+	  printf (" cu: %s\n", dwarf_diename (die) ?: "???");
+	  walk_tree (die, 2);
+	}
+
+      dwarf_end (dbg);
+      close (fd);
+    }
+
+  return 0;
+}
diff --git a/tests/run-declfiles.sh b/tests/run-declfiles.sh
new file mode 100755
index 00000000..faba7078
--- /dev/null
+++ b/tests/run-declfiles.sh
@@ -0,0 +1,233 @@ 
+#! /bin/sh
+# Copyright (c) 2024 Meta Platforms, Inc. and affiliates.
+# This file is part of elfutils.
+#
+# 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/>.
+
+. $srcdir/test-subr.sh
+
+# see tests/testfile-dwarf-45.source
+testfiles testfile-dwarf-4 testfile-dwarf-5
+testfiles testfile-splitdwarf-4 testfile-hello4.dwo testfile-world4.dwo
+testfiles testfile-splitdwarf-5 testfile-hello5.dwo testfile-world5.dwo
+
+testrun_compare ${abs_builddir}/declfiles testfile-dwarf-4 << EOF
+file: testfile-dwarf-4
+ cu: hello.c
+  wchar_t@/opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include/stddef.h:328:24
+  m@/var/tmp/hello/hello.h:1:12
+  m@/var/tmp/hello/hello.c:5:5
+  foo@/var/tmp/hello/hello.c:20:1
+   f@/var/tmp/hello/hello.c:20:14
+  baz@/var/tmp/hello/hello.c:8:5
+   x@/var/tmp/hello/hello.c:8:14
+   r@/var/tmp/hello/hello.c:10:7
+  frob@/var/tmp/hello/hello.h:5:1
+   a@/var/tmp/hello/hello.h:5:11
+   b@/var/tmp/hello/hello.h:5:18
+   c@/var/tmp/hello/hello.h:7:7
+  foo@/var/tmp/hello/hello.c:20:1
+   f@/var/tmp/hello/hello.c:20:14
+   frob@/var/tmp/hello/hello.h:5:1
+    b@/var/tmp/hello/hello.h:5:18
+    a@/var/tmp/hello/hello.h:5:11
+    c@/var/tmp/hello/hello.h:7:7
+    baz@/var/tmp/hello/hello.c:8:5
+     x@/var/tmp/hello/hello.c:8:14
+     r@/var/tmp/hello/hello.c:10:7
+   foo@/var/tmp/hello/hello.c:20:1
+    f@/var/tmp/hello/hello.c:20:14
+    main@/var/tmp/hello/hello.c:4:12
+  baz@/var/tmp/hello/hello.c:8:5
+   x@/var/tmp/hello/hello.c:8:14
+   r@/var/tmp/hello/hello.c:10:7
+   foo@/var/tmp/hello/hello.c:20:1
+  main@/var/tmp/hello/hello.c:4:12
+ cu: world.c
+  m@/var/tmp/hello/hello.h:1:12
+  main@/var/tmp/hello/world.c:14:1
+   argc@/var/tmp/hello/world.c:14:11
+   argv@/var/tmp/hello/world.c:14:30
+   n@/var/tmp/hello/world.c:16:15
+   calc@/var/tmp/hello/world.c:5:1
+   exit@/usr/include/stdlib.h:542:13
+  calc@/var/tmp/hello/world.c:5:1
+   word@/var/tmp/hello/world.c:5:19
+   frob@/var/tmp/hello/hello.h:5:1
+    b@/var/tmp/hello/hello.h:5:18
+    a@/var/tmp/hello/hello.h:5:11
+    c@/var/tmp/hello/hello.h:7:7
+    baz@/var/tmp/hello/hello.h:2:12
+  frob@/var/tmp/hello/hello.h:5:1
+   a@/var/tmp/hello/hello.h:5:11
+   b@/var/tmp/hello/hello.h:5:18
+   c@/var/tmp/hello/hello.h:7:7
+  exit@/usr/include/stdlib.h:542:13
+  baz@/var/tmp/hello/hello.h:2:12
+EOF
+
+testrun_compare ${abs_builddir}/declfiles testfile-dwarf-5 << EOF
+file: testfile-dwarf-5
+ cu: hello.c
+  wchar_t@/opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include/stddef.h:328:24
+  m@/var/tmp/hello/hello.h:1:12
+  m@/var/tmp/hello/hello.c:5:5
+  foo@/var/tmp/hello/hello.c:20:1
+   f@/var/tmp/hello/hello.c:20:14
+  baz@/var/tmp/hello/hello.c:8:5
+   x@/var/tmp/hello/hello.c:8:14
+   r@/var/tmp/hello/hello.c:10:7
+  frob@/var/tmp/hello/hello.h:5:1
+   a@/var/tmp/hello/hello.h:5:11
+   b@/var/tmp/hello/hello.h:5:18
+   c@/var/tmp/hello/hello.h:7:7
+  foo@/var/tmp/hello/hello.c:20:1
+   f@/var/tmp/hello/hello.c:20:14
+   frob@/var/tmp/hello/hello.h:5:1
+    b@/var/tmp/hello/hello.h:5:18
+    a@/var/tmp/hello/hello.h:5:11
+    c@/var/tmp/hello/hello.h:7:7
+    baz@/var/tmp/hello/hello.c:8:5
+     x@/var/tmp/hello/hello.c:8:14
+     r@/var/tmp/hello/hello.c:10:7
+   foo@/var/tmp/hello/hello.c:20:1
+    f@/var/tmp/hello/hello.c:20:14
+  baz@/var/tmp/hello/hello.c:8:5
+   x@/var/tmp/hello/hello.c:8:14
+   r@/var/tmp/hello/hello.c:10:7
+  main@/var/tmp/hello/hello.c:4:12
+ cu: world.c
+  m@/var/tmp/hello/hello.h:1:12
+  main@/var/tmp/hello/world.c:14:1
+   argc@/var/tmp/hello/world.c:14:11
+   argv@/var/tmp/hello/world.c:14:30
+   n@/var/tmp/hello/world.c:16:15
+  calc@/var/tmp/hello/world.c:5:1
+   word@/var/tmp/hello/world.c:5:19
+   frob@/var/tmp/hello/hello.h:5:1
+    b@/var/tmp/hello/hello.h:5:18
+    a@/var/tmp/hello/hello.h:5:11
+    c@/var/tmp/hello/hello.h:7:7
+  frob@/var/tmp/hello/hello.h:5:1
+   a@/var/tmp/hello/hello.h:5:11
+   b@/var/tmp/hello/hello.h:5:18
+   c@/var/tmp/hello/hello.h:7:7
+  exit@/usr/include/stdlib.h:542:13
+  baz@/var/tmp/hello/hello.h:2:12
+EOF
+
+testrun_compare ${abs_builddir}/declfiles testfile-splitdwarf-4 << EOF
+file: testfile-splitdwarf-4
+ cu: hello.c
+  wchar_t@/opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include/stddef.h:328:24
+  m@/home/mark/src/elfutils/tests/hello.h:1:12
+  m@/home/mark/src/elfutils/tests/hello.c:5:5
+  foo@/home/mark/src/elfutils/tests/hello.c:20:1
+   f@/home/mark/src/elfutils/tests/hello.c:20:14
+  baz@/home/mark/src/elfutils/tests/hello.c:8:5
+   x@/home/mark/src/elfutils/tests/hello.c:8:14
+   r@/home/mark/src/elfutils/tests/hello.c:10:7
+  frob@/home/mark/src/elfutils/tests/hello.h:5:1
+   a@/home/mark/src/elfutils/tests/hello.h:5:11
+   b@/home/mark/src/elfutils/tests/hello.h:5:18
+   c@/home/mark/src/elfutils/tests/hello.h:7:7
+  foo@/home/mark/src/elfutils/tests/hello.c:20:1
+   f@/home/mark/src/elfutils/tests/hello.c:20:14
+   frob@/home/mark/src/elfutils/tests/hello.h:5:1
+    b@/home/mark/src/elfutils/tests/hello.h:5:18
+    a@/home/mark/src/elfutils/tests/hello.h:5:11
+    c@/home/mark/src/elfutils/tests/hello.h:7:7
+    baz@/home/mark/src/elfutils/tests/hello.c:8:5
+     x@/home/mark/src/elfutils/tests/hello.c:8:14
+     r@/home/mark/src/elfutils/tests/hello.c:10:7
+   foo@/home/mark/src/elfutils/tests/hello.c:20:1
+    f@/home/mark/src/elfutils/tests/hello.c:20:14
+    main@/home/mark/src/elfutils/tests/hello.c:4:12
+  baz@/home/mark/src/elfutils/tests/hello.c:8:5
+   x@/home/mark/src/elfutils/tests/hello.c:8:14
+   r@/home/mark/src/elfutils/tests/hello.c:10:7
+   foo@/home/mark/src/elfutils/tests/hello.c:20:1
+  main@/home/mark/src/elfutils/tests/hello.c:4:12
+ cu: world.c
+  m@/home/mark/src/elfutils/tests/hello.h:1:12
+  main@/home/mark/src/elfutils/tests/world.c:14:1
+   argc@/home/mark/src/elfutils/tests/world.c:14:11
+   argv@/home/mark/src/elfutils/tests/world.c:14:30
+   n@/home/mark/src/elfutils/tests/world.c:16:15
+   calc@/home/mark/src/elfutils/tests/world.c:5:1
+   exit@/usr/include/stdlib.h:542:13
+  calc@/home/mark/src/elfutils/tests/world.c:5:1
+   word@/home/mark/src/elfutils/tests/world.c:5:19
+   frob@/home/mark/src/elfutils/tests/hello.h:5:1
+    b@/home/mark/src/elfutils/tests/hello.h:5:18
+    a@/home/mark/src/elfutils/tests/hello.h:5:11
+    c@/home/mark/src/elfutils/tests/hello.h:7:7
+    baz@/home/mark/src/elfutils/tests/hello.h:2:12
+  frob@/home/mark/src/elfutils/tests/hello.h:5:1
+   a@/home/mark/src/elfutils/tests/hello.h:5:11
+   b@/home/mark/src/elfutils/tests/hello.h:5:18
+   c@/home/mark/src/elfutils/tests/hello.h:7:7
+  exit@/usr/include/stdlib.h:542:13
+  baz@/home/mark/src/elfutils/tests/hello.h:2:12
+EOF
+
+testrun_compare ${abs_builddir}/declfiles testfile-splitdwarf-5 << EOF
+file: testfile-splitdwarf-5
+ cu: hello.c
+  wchar_t@/opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include/stddef.h:328:24
+  m@/home/mark/src/elfutils/tests/hello.h:1:12
+  m@/home/mark/src/elfutils/tests/hello.c:5:5
+  foo@/home/mark/src/elfutils/tests/hello.c:20:1
+   f@/home/mark/src/elfutils/tests/hello.c:20:14
+  baz@/home/mark/src/elfutils/tests/hello.c:8:5
+   x@/home/mark/src/elfutils/tests/hello.c:8:14
+   r@/home/mark/src/elfutils/tests/hello.c:10:7
+  frob@/home/mark/src/elfutils/tests/hello.h:5:1
+   a@/home/mark/src/elfutils/tests/hello.h:5:11
+   b@/home/mark/src/elfutils/tests/hello.h:5:18
+   c@/home/mark/src/elfutils/tests/hello.h:7:7
+  foo@/home/mark/src/elfutils/tests/hello.c:20:1
+   f@/home/mark/src/elfutils/tests/hello.c:20:14
+   frob@/home/mark/src/elfutils/tests/hello.h:5:1
+    b@/home/mark/src/elfutils/tests/hello.h:5:18
+    a@/home/mark/src/elfutils/tests/hello.h:5:11
+    c@/home/mark/src/elfutils/tests/hello.h:7:7
+    baz@/home/mark/src/elfutils/tests/hello.c:8:5
+     x@/home/mark/src/elfutils/tests/hello.c:8:14
+     r@/home/mark/src/elfutils/tests/hello.c:10:7
+   foo@/home/mark/src/elfutils/tests/hello.c:20:1
+    f@/home/mark/src/elfutils/tests/hello.c:20:14
+  baz@/home/mark/src/elfutils/tests/hello.c:8:5
+   x@/home/mark/src/elfutils/tests/hello.c:8:14
+   r@/home/mark/src/elfutils/tests/hello.c:10:7
+  main@/home/mark/src/elfutils/tests/hello.c:4:12
+ cu: world.c
+  m@/home/mark/src/elfutils/tests/hello.h:1:12
+  main@/home/mark/src/elfutils/tests/world.c:14:1
+   argc@/home/mark/src/elfutils/tests/world.c:14:11
+   argv@/home/mark/src/elfutils/tests/world.c:14:30
+   n@/home/mark/src/elfutils/tests/world.c:16:15
+  calc@/home/mark/src/elfutils/tests/world.c:5:1
+   word@/home/mark/src/elfutils/tests/world.c:5:19
+   frob@/home/mark/src/elfutils/tests/hello.h:5:1
+    b@/home/mark/src/elfutils/tests/hello.h:5:18
+    a@/home/mark/src/elfutils/tests/hello.h:5:11
+    c@/home/mark/src/elfutils/tests/hello.h:7:7
+  frob@/home/mark/src/elfutils/tests/hello.h:5:1
+   a@/home/mark/src/elfutils/tests/hello.h:5:11
+   b@/home/mark/src/elfutils/tests/hello.h:5:18
+   c@/home/mark/src/elfutils/tests/hello.h:7:7
+  exit@/usr/include/stdlib.h:542:13
+  baz@/home/mark/src/elfutils/tests/hello.h:2:12
+EOF