This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] readelf: Add DWARF5 .debug_line support.


This only changes the parsing of the directory and file name tables.
It does this by sharing the printing of (non-CU based) from data from
the .debug_macro code. Adding support for printing strx[1234] form data
by sharing the code that detects the correct str_offsets_base in libdw.

The header format is also cleaned up a bit so that it better lines out.
Testcases adjusted and new ones added.

Signed-off-by: Mark Wielaard <mark@klomp.org>
---
 libdw/ChangeLog             |   7 +
 libdw/dwarf_formstring.c    |  17 --
 libdw/libdwP.h              | 107 ++++++-
 src/ChangeLog               |  11 +
 src/readelf.c               | 711 +++++++++++++++++++++++++++++++------------
 tests/ChangeLog             |   6 +
 tests/run-readelf-line.sh   | 712 +++++++++++++++++++++++++++++++++++++++++---
 tests/run-readelf-zdebug.sh |  20 +-
 8 files changed, 1333 insertions(+), 258 deletions(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 86d2b78..efdd927 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,10 @@
+2018-05-09  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf_formstring.c (__libdw_cu_str_off_base): Moved to...
+	* libdwP.h (__libdw_cu_str_off_base): ...here. Make static inline.
+	(str_offsets_base_off): New internal function that also parses
+	.debug_str_offsets header if necessary.
+
 2018-05-11  Mark Wielaard  <mark@klomp.org>
 
 	* dwarf_siblingof.c (dwarf_siblingof): Don't reference cu till it is
diff --git a/libdw/dwarf_formstring.c b/libdw/dwarf_formstring.c
index c55c7f0..251784d 100644
--- a/libdw/dwarf_formstring.c
+++ b/libdw/dwarf_formstring.c
@@ -177,20 +177,3 @@ dwarf_formstring (Dwarf_Attribute *attrp)
   return (const char *) data->d_buf + off;
 }
 INTDEF(dwarf_formstring)
-
-Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu)
-{
-  if (cu->str_off_base == (Dwarf_Off) -1)
-    {
-      Dwarf_Die cu_die = CUDIE(cu);
-      Dwarf_Attribute attr;
-      if (dwarf_attr (&cu_die, DW_AT_str_offsets_base, &attr) != NULL)
-	{
-	  Dwarf_Word off;
-	  if (dwarf_formudata (&attr, &off) == 0)
-	    cu->str_off_base = off;
-	}
-    }
-
-  return cu->str_off_base;
-}
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 7aa290e..da0383f 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -933,8 +933,113 @@ Dwarf_Addr __libdw_cu_base_address (Dwarf_CU *cu);
 /* Get the address base for the CU, fetches it when not yet set.  */
 Dwarf_Off __libdw_cu_addr_base (Dwarf_CU *cu);
 
+/* Gets the .debug_str_offsets base offset to use.  static inline to
+   be shared between libdw and eu-readelf.  */
+static inline Dwarf_Off
+str_offsets_base_off (Dwarf *dbg, Dwarf_CU *cu)
+{
+  /* If we don't have a CU, then find and use the first one in the
+     debug file (when we support .dwp files, we must actually find the
+     one matching our "caller" - aka macro or line).  If we (now) have
+     a cu and str_offsets_base attribute, just use that.  Otherwise
+     use the first offset.  But we might have to parse the header
+     first, but only if this is version 5.  Assume if all else fails,
+     this is version 4, without header.  */
+
+  if (cu == NULL && dbg != NULL)
+    {
+      Dwarf_CU *first_cu;
+      if (dwarf_get_units (dbg, NULL, &first_cu,
+			   NULL, NULL, NULL, NULL) == 0)
+	cu = first_cu;
+    }
+
+  if (cu != NULL)
+    {
+      if (cu->str_off_base == (Dwarf_Off) -1)
+	{
+	  Dwarf_Die cu_die = CUDIE(cu);
+	  Dwarf_Attribute attr;
+	  if (dwarf_attr (&cu_die, DW_AT_str_offsets_base, &attr) != NULL)
+	    {
+	      Dwarf_Word off;
+	      if (dwarf_formudata (&attr, &off) == 0)
+		{
+		  cu->str_off_base = off;
+		  return cu->str_off_base;
+		}
+	    }
+	  /* For older DWARF simply assume zero (no header).  */
+	  if (cu->version < 5)
+	    {
+	      cu->str_off_base = 0;
+	      return cu->str_off_base;
+	    }
+	}
+      else
+	return cu->str_off_base;
+    }
+
+  /* No str_offsets_base attribute, we have to assume "zero".
+     But there could be a header first.  */
+  Dwarf_Off off = 0;
+  if (dbg == NULL)
+    goto no_header;
+
+  Elf_Data *data =  dbg->sectiondata[IDX_debug_str_offsets];
+  if (data == NULL)
+    goto no_header;
+
+  const unsigned char *start;
+  const unsigned char *readp;
+  const unsigned char *readendp;
+  start = readp = (const unsigned char *) data->d_buf;
+  readendp = (const unsigned char *) data->d_buf + data->d_size;
+
+  uint64_t unit_length;
+  uint16_t version;
+
+  unit_length = read_4ubyte_unaligned_inc (dbg, readp);
+  if (unlikely (unit_length == 0xffffffff))
+    {
+      if (unlikely (readendp - readp < 8))
+	goto no_header;
+      unit_length = read_8ubyte_unaligned_inc (dbg, readp);
+      /* In theory the offset size could be different
+	 between CU and str_offsets unit.  But we just
+	 ignore that here. */
+    }
+
+  /* We need at least 2-bytes (version) + 2-bytes (padding) =
+     4 bytes to complete the header.  And this unit cannot go
+     beyond the section data.  */
+  if (readendp - readp < 4
+      || unit_length < 4
+      || (uint64_t) (readendp - readp) < unit_length)
+    goto no_header;
+
+  version = read_2ubyte_unaligned_inc (dbg, readp);
+  if (version != 5)
+    goto no_header;
+  /* padding */
+  read_2ubyte_unaligned_inc (dbg, readp);
+
+  off = (Dwarf_Off) (readp - start);
+
+ no_header:
+  if (cu != NULL)
+    cu->str_off_base = off;
+
+  return off;
+}
+
+
 /* Get the string offsets base for the CU, fetches it when not yet set.  */
-Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu);
+static inline Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu)
+{
+  return str_offsets_base_off (NULL, cu);
+}
+
 
 /* Given a file descriptor, dir and file returns a full path.  If the
    file is absolute (starts with a /) a copy of file is returned.  If
diff --git a/src/ChangeLog b/src/ChangeLog
index a6ee30b..4208b52 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,14 @@
+2018-05-09  Mark Wielaard  <mark@klomp.org>
+
+	* readelf.c (dwarf_line_content_description_string): New function.
+	(dwarf_line_content_description_name): Likewise.
+	(print_bytes): Likewise.
+	(print_form_data): Likewise. Based on code taken from...
+	(print_debug_macro_section): ...here. Now calls print_form_data
+	and str_offsets_base_off.
+	(print_debug_line_section): Parse DWARF5 header, directory and file
+	name tables.
+
 2018-04-28  Mark Wielaard  <mark@klomp.org>
 
 	* readelf.c (print_debug): If .debug_info is needed implicitly by
diff --git a/src/readelf.c b/src/readelf.c
index e44b2a3..ba4c1d7 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -1,7 +1,6 @@
 /* Print information from ELF file in human-readable form.
-   Copyright (C) 1999-2017 Red Hat, Inc.
+   Copyright (C) 1999-2018 Red Hat, Inc.
    This file is part of elfutils.
-   Written by Ulrich Drepper <drepper@redhat.com>, 1999.
 
    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
@@ -3975,6 +3974,20 @@ dwarf_unit_string (unsigned int type)
 }
 
 
+static const char *
+dwarf_line_content_description_string (unsigned int kind)
+{
+  switch (kind)
+    {
+#define DWARF_ONE_KNOWN_DW_LNCT(NAME, CODE) case CODE: return #NAME;
+      DWARF_ALL_KNOWN_DW_LNCT
+#undef DWARF_ONE_KNOWN_DW_LNCT
+    default:
+      return NULL;
+    }
+}
+
+
 /* Used by all dwarf_foo_name functions.  */
 static const char *
 string_or_unknown (const char *known, unsigned int code,
@@ -4122,6 +4135,15 @@ dwarf_unit_name (unsigned int type)
 }
 
 
+static const char *
+dwarf_line_content_description_name (unsigned int kind)
+{
+  const char *ret = dwarf_line_content_description_string (kind);
+  return string_or_unknown (ret, kind, DW_LNCT_lo_user, DW_LNCT_hi_user,
+			    false);
+}
+
+
 static void
 print_block (size_t n, const void *block)
 {
@@ -4139,6 +4161,17 @@ print_block (size_t n, const void *block)
 }
 
 static void
+print_bytes (size_t n, const unsigned char *bytes)
+{
+  while (n-- > 0)
+    {
+      printf ("%02x", *bytes++);
+      if (n > 0)
+	printf (" ");
+    }
+}
+
+static void
 print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
 	   unsigned int vers, unsigned int addrsize, unsigned int offset_size,
 	   struct Dwarf_CU *cu, Dwarf_Word len, const unsigned char *data)
@@ -6747,6 +6780,230 @@ print_decoded_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
 }
 
 
+/* Print the value of a form.
+   Returns new value of readp, or readendp on failure.  */
+static const unsigned char *
+print_form_data (Dwarf *dbg, int form, const unsigned char *readp,
+		 const unsigned char *readendp, unsigned int offset_len,
+		 Dwarf_Off str_offsets_base)
+{
+  Dwarf_Word val;
+  unsigned char *endp;
+  Elf_Data *data;
+  char *str;
+  switch (form)
+    {
+    case DW_FORM_data1:
+      if (readendp - readp < 1)
+	{
+	invalid_data:
+	  error (0, 0, "invalid data");
+	  return readendp;
+	}
+      val = *readp++;
+      printf (" %" PRIx8, (unsigned int) val);
+      break;
+
+    case DW_FORM_data2:
+      if (readendp - readp < 2)
+	goto invalid_data;
+      val = read_2ubyte_unaligned_inc (dbg, readp);
+      printf(" %" PRIx16, (unsigned int) val);
+      break;
+
+    case DW_FORM_data4:
+      if (readendp - readp < 4)
+	goto invalid_data;
+      val = read_4ubyte_unaligned_inc (dbg, readp);
+      printf (" %" PRIx32, (unsigned int) val);
+      break;
+
+    case DW_FORM_data8:
+      if (readendp - readp < 8)
+	goto invalid_data;
+      val = read_8ubyte_unaligned_inc (dbg, readp);
+      printf (" %" PRIx64, val);
+      break;
+
+    case DW_FORM_sdata:
+      if (readendp - readp < 1)
+	goto invalid_data;
+      get_sleb128 (val, readp, readendp);
+      printf (" %" PRIx64, val);
+      break;
+
+    case DW_FORM_udata:
+      if (readendp - readp < 1)
+	goto invalid_data;
+      get_uleb128 (val, readp, readendp);
+      printf (" %" PRIx64, val);
+      break;
+
+    case DW_FORM_block:
+      if (readendp - readp < 1)
+	goto invalid_data;
+      get_uleb128 (val, readp, readendp);
+      if (readendp - readp < (ptrdiff_t) val)
+	goto invalid_data;
+      print_bytes (val, readp);
+      readp += val;
+      break;
+
+    case DW_FORM_block1:
+      if (readendp - readp < 1)
+	goto invalid_data;
+      val = *readp++;
+      if (readendp - readp < (ptrdiff_t) val)
+	goto invalid_data;
+      print_bytes (val, readp);
+      readp += val;
+      break;
+
+    case DW_FORM_block2:
+      if (readendp - readp < 2)
+	goto invalid_data;
+      val = read_2ubyte_unaligned_inc (dbg, readp);
+      if (readendp - readp < (ptrdiff_t) val)
+	goto invalid_data;
+      print_bytes (val, readp);
+      readp += val;
+      break;
+
+    case DW_FORM_block4:
+      if (readendp - readp < 2)
+	goto invalid_data;
+      val = read_4ubyte_unaligned_inc (dbg, readp);
+      if (readendp - readp < (ptrdiff_t) val)
+	goto invalid_data;
+      print_bytes (val, readp);
+      readp += val;
+      break;
+
+    case DW_FORM_data16:
+      if (readendp - readp < 16)
+	goto invalid_data;
+      print_bytes (16, readp);
+      readp += 16;
+      break;
+
+    case DW_FORM_flag:
+      if (readendp - readp < 1)
+	goto invalid_data;
+      val = *readp++;
+      printf ("%s", val != 0 ? gettext ("yes") : gettext ("no"));
+      break;
+
+    case DW_FORM_string:
+      endp = memchr (readp, '\0', readendp - readp);
+      if (endp == NULL)
+	goto invalid_data;
+      printf ("%s", readp);
+      readp = endp + 1;
+      break;
+
+    case DW_FORM_strp:
+    case DW_FORM_line_strp:
+    case DW_FORM_strp_sup:
+      if (readendp - readp < offset_len)
+	goto invalid_data;
+      if (offset_len == 8)
+	val = read_8ubyte_unaligned_inc (dbg, readp);
+      else
+	val = read_4ubyte_unaligned_inc (dbg, readp);
+      if (form == DW_FORM_strp)
+	data = dbg->sectiondata[IDX_debug_str];
+      else if (form == DW_FORM_line_strp)
+	data = dbg->sectiondata[IDX_debug_line_str];
+      else /* form == DW_FORM_strp_sup */
+	{
+	  Dwarf *alt = dwarf_getalt (dbg);
+	  data = alt != NULL ? alt->sectiondata[IDX_debug_str] : NULL;
+	}
+      if (data == NULL || val >= data->d_size
+	  || memchr (data->d_buf + val, '\0', data->d_size - val) == NULL)
+	str = "???";
+      else
+	str = (char *) data->d_buf + val;
+      printf ("%s (%" PRIu64 ")", str, val);
+      break;
+
+    case DW_FORM_sec_offset:
+      if (readendp - readp < offset_len)
+	goto invalid_data;
+      if (offset_len == 8)
+	val = read_8ubyte_unaligned_inc (dbg, readp);
+      else
+	val = read_4ubyte_unaligned_inc (dbg, readp);
+      printf ("[%" PRIx64 "]", val);
+      break;
+
+    case DW_FORM_strx:
+      if (readendp - readp < 1)
+	goto invalid_data;
+      get_uleb128 (val, readp, readendp);
+    strx_val:
+      data = dbg->sectiondata[IDX_debug_str_offsets];
+      if (data == NULL
+	  || data->d_size - str_offsets_base < val)
+	str = "???";
+      else
+	{
+	  readp = data->d_buf + str_offsets_base + val;
+	  readendp = data->d_buf + data->d_size;
+	  if (readendp - readp < offset_len)
+	    str = "???";
+	  else
+	    {
+	      Dwarf_Off idx;
+	      if (offset_len == 8)
+		idx = read_8ubyte_unaligned_inc (dbg, readp);
+	      else
+		idx = read_4ubyte_unaligned_inc (dbg, readp);
+
+	      data = dbg->sectiondata[IDX_debug_str];
+	      if (data == NULL || idx >= data->d_size
+		  || memchr (data->d_buf + idx, '\0',
+			     data->d_size - idx) == NULL)
+		str = "???";
+	      else
+		str = (char *) data->d_buf + idx;
+	    }
+	}
+      printf ("%s (%" PRIu64 ")", str, val);
+      break;
+
+    case DW_FORM_strx1:
+      if (readendp - readp < 1)
+	goto invalid_data;
+      val = *readp;
+      goto strx_val;
+
+    case DW_FORM_strx2:
+      if (readendp - readp < 2)
+	goto invalid_data;
+      val = read_2ubyte_unaligned (dbg, readp);
+      goto strx_val;
+
+    case DW_FORM_strx3:
+      if (readendp - readp < 3)
+	goto invalid_data;
+      val = read_3ubyte_unaligned (dbg, readp);
+      goto strx_val;
+
+    case DW_FORM_strx4:
+      if (readendp - readp < 4)
+	goto invalid_data;
+      val = read_4ubyte_unaligned (dbg, readp);
+      goto strx_val;
+
+    default:
+      error (0, 0, gettext ("unknown form: %s"), dwarf_form_name (form));
+      return readendp;
+    }
+
+  return readp;
+}
+
 static void
 print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
 			  Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
@@ -6803,35 +7060,67 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
 	}
 
       /* Check whether we have enough room in the section.  */
-      if (unlikely (unit_length > (size_t) (lineendp - linep)
-	  || unit_length < 2 + length + 5 * 1))
+      if (unlikely (unit_length > (size_t) (lineendp - linep)))
 	goto invalid_data;
       lineendp = linep + 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);
 
+      size_t address_size
+	= elf_getident (ebl->elf, NULL)[EI_CLASS] == ELFCLASS32 ? 4 : 8;
+      unsigned char segment_selector_size = 0;
+      if (version > 4)
+	{
+	  if ((size_t) (lineendp - linep) < 2)
+	    goto invalid_data;
+	  address_size = *linep++;
+	  segment_selector_size = *linep++;
+	}
+
       /* Next comes the header length.  */
       Dwarf_Word header_length;
       if (length == 4)
-	header_length = read_4ubyte_unaligned_inc (dbg, linep);
+	{
+	  if ((size_t) (lineendp - linep) < 4)
+	    goto invalid_data;
+	  header_length = read_4ubyte_unaligned_inc (dbg, linep);
+	}
       else
-	header_length = read_8ubyte_unaligned_inc (dbg, linep);
-      //const unsigned char *header_start = linep;
+	{
+	  if ((size_t) (lineendp - linep) < 8)
+	    goto invalid_data;
+	  header_length = read_8ubyte_unaligned_inc (dbg, linep);
+	}
 
       /* Next the minimum instruction length.  */
+      if ((size_t) (lineendp - linep) < 1)
+	goto invalid_data;
       uint_fast8_t minimum_instr_len = *linep++;
 
       /* Next the maximum operations per instruction, in version 4 format.  */
-      uint_fast8_t max_ops_per_instr = version < 4 ? 1 : *linep++;
+      uint_fast8_t max_ops_per_instr;
+      if (version < 4)
+	max_ops_per_instr = 1;
+      else
+	{
+	  if ((size_t) (lineendp - linep) < 1)
+	    goto invalid_data;
+	  max_ops_per_instr = *linep++;
+	}
+
+      /* We need at least 4 more bytes.  */
+      if ((size_t) (lineendp - linep) < 4)
+	goto invalid_data;
 
-	/* Then the flag determining the default value of the is_stmt
-	   register.  */
+      /* Then the flag determining the default value of the is_stmt
+	 register.  */
       uint_fast8_t default_is_stmt = *linep++;
 
       /* Now the line base.  */
-      int_fast8_t line_base = *((const int_fast8_t *) linep);
-      ++linep;
+      int_fast8_t line_base = *linep++;
 
       /* And the line range.  */
       uint_fast8_t line_range = *linep++;
@@ -6841,22 +7130,49 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
 
       /* Print what we got so far.  */
       printf (gettext ("\n"
-		       " Length:                     %" PRIu64 "\n"
-		       " DWARF version:              %" PRIuFAST16 "\n"
-		       " Prologue length:            %" PRIu64 "\n"
-		       " Minimum instruction length: %" PRIuFAST8 "\n"
-		       " Maximum operations per instruction: %" PRIuFAST8 "\n"
-		       " Initial value if '%s': %" PRIuFAST8 "\n"
-		       " Line base:                  %" PRIdFAST8 "\n"
-		       " Line range:                 %" PRIuFAST8 "\n"
-		       " Opcode base:                %" PRIuFAST8 "\n"
+		       " Length:                         %" PRIu64 "\n"
+		       " DWARF version:                  %" PRIuFAST16 "\n"
+		       " Prologue length:                %" PRIu64 "\n"
+		       " Address size:                   %zd\n"
+		       " Segment selector size:          %zd\n"
+		       " Min instruction length:         %" PRIuFAST8 "\n"
+		       " Max operations per instruction: %" PRIuFAST8 "\n"
+		       " Initial value if 'is_stmt':     %" PRIuFAST8 "\n"
+		       " Line base:                      %" PRIdFAST8 "\n"
+		       " Line range:                     %" PRIuFAST8 "\n"
+		       " Opcode base:                    %" PRIuFAST8 "\n"
 		       "\n"
 		       "Opcodes:\n"),
 	      (uint64_t) unit_length, version, (uint64_t) header_length,
+	      address_size, (size_t) segment_selector_size,
 	      minimum_instr_len, max_ops_per_instr,
-	      "is_stmt", default_is_stmt, line_base,
+	      default_is_stmt, line_base,
 	      line_range, opcode_base);
 
+      if (version < 2 || version > 5)
+	{
+	  error (0, 0, gettext ("cannot handle .debug_line version: %u\n"),
+		 (unsigned int) version);
+	  linep = lineendp;
+	  continue;
+	}
+
+      if (address_size != 4 && address_size != 8)
+	{
+	  error (0, 0, gettext ("cannot handle address size: %u\n"),
+		 (unsigned int) address_size);
+	  linep = lineendp;
+	  continue;
+	}
+
+      if (segment_selector_size != 0)
+	{
+	  error (0, 0, gettext ("cannot handle segment selector size: %u\n"),
+		 (unsigned int) segment_selector_size);
+	  linep = lineendp;
+	  continue;
+	}
+
       if (unlikely (linep + opcode_base - 1 >= lineendp))
 	{
 	invalid_unit:
@@ -6881,59 +7197,178 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
 			  (int) linep[cnt - 1]),
 		opcode_base_l10, cnt, linep[cnt - 1]);
       linep += opcode_base - 1;
+
       if (unlikely (linep >= lineendp))
 	goto invalid_unit;
 
+      Dwarf_Off str_offsets_base = str_offsets_base_off (dbg, NULL);
+
       puts (gettext ("\nDirectory table:"));
-      while (*linep != 0)
+      if (version > 4)
 	{
-	  unsigned char *endp = memchr (linep, '\0', lineendp - linep);
-	  if (unlikely (endp == NULL))
-	    goto invalid_unit;
+	  struct encpair { uint16_t desc; uint16_t form; };
+	  struct encpair enc[256];
+
+	  printf (gettext ("      ["));
+	  if ((size_t) (lineendp - linep) < 1)
+	    goto invalid_data;
+	  unsigned char directory_entry_format_count = *linep++;
+	  for (int i = 0; i < directory_entry_format_count; i++)
+	    {
+	      uint16_t desc, form;
+	      if ((size_t) (lineendp - linep) < 1)
+		goto invalid_data;
+	      get_uleb128 (desc, linep, lineendp);
+	      if ((size_t) (lineendp - linep) < 1)
+		goto invalid_data;
+	      get_uleb128 (form, linep, lineendp);
+
+	      enc[i].desc = desc;
+	      enc[i].form = form;
+
+	      printf ("%s(%s)",
+		      dwarf_line_content_description_name (desc),
+		      dwarf_form_name (form));
+	      if (i + 1 < directory_entry_format_count)
+		printf (", ");
+	    }
+	  printf ("]\n");
+
+	  uint64_t directories_count;
+	  if ((size_t) (lineendp - linep) < 1)
+            goto invalid_data;
+	  get_uleb128 (directories_count, linep, lineendp);
 
-	  printf (" %s\n", (char *) linep);
+	  if (directory_entry_format_count == 0
+	      && directories_count != 0)
+	    goto invalid_data;
+
+	  for (uint64_t i = 0; i < directories_count; i++)
+	    {
+	      printf (" %-5lu ", i);
+	      for (int j = 0; j < directory_entry_format_count; j++)
+		{
+		  linep = print_form_data (dbg, enc[j].form,
+					   linep, lineendp, length,
+					   str_offsets_base);
+		  if (j + 1 < directory_entry_format_count)
+		    printf (", ");
+		}
+	      printf ("\n");
+	    }
+	}
+      else
+	{
+	  while (*linep != 0)
+	    {
+	      unsigned char *endp = memchr (linep, '\0', lineendp - linep);
+	      if (unlikely (endp == NULL))
+		goto invalid_unit;
 
-	  linep = endp + 1;
+	      printf (" %s\n", (char *) linep);
+
+	      linep = endp + 1;
+	    }
+	  /* Skip the final NUL byte.  */
+	  ++linep;
 	}
-      /* Skip the final NUL byte.  */
-      ++linep;
 
       if (unlikely (linep >= lineendp))
 	goto invalid_unit;
-      puts (gettext ("\nFile name table:\n"
-		     " Entry Dir   Time      Size      Name"));
-      for (unsigned int cnt = 1; *linep != 0; ++cnt)
+
+      puts (gettext ("\nFile name table:"));
+      if (version > 4)
 	{
-	  /* First comes the file name.  */
-	  char *fname = (char *) linep;
-	  unsigned char *endp = memchr (fname, '\0', lineendp - linep);
-	  if (unlikely (endp == NULL))
-	    goto invalid_unit;
-	  linep = endp + 1;
+	  struct encpair { uint16_t desc; uint16_t form; };
+	  struct encpair enc[256];
 
-	  /* Then the index.  */
-	  unsigned int diridx;
-	  if (lineendp - linep < 1)
-	    goto invalid_unit;
-	  get_uleb128 (diridx, linep, lineendp);
+	  printf (gettext ("      ["));
+	  if ((size_t) (lineendp - linep) < 1)
+	    goto invalid_data;
+	  unsigned char file_name_format_count = *linep++;
+	  for (int i = 0; i < file_name_format_count; i++)
+	    {
+	      uint64_t desc, form;
+	      if ((size_t) (lineendp - linep) < 1)
+		goto invalid_data;
+	      get_uleb128 (desc, linep, lineendp);
+	      if ((size_t) (lineendp - linep) < 1)
+		goto invalid_data;
+	      get_uleb128 (form, linep, lineendp);
 
-	  /* Next comes the modification time.  */
-	  unsigned int mtime;
-	  if (lineendp - linep < 1)
-	    goto invalid_unit;
-	  get_uleb128 (mtime, linep, lineendp);
+	      if (! libdw_valid_user_form (form))
+		goto invalid_data;
 
-	  /* Finally the length of the file.  */
-	  unsigned int fsize;
-	  if (lineendp - linep < 1)
-	    goto invalid_unit;
-	  get_uleb128 (fsize, linep, lineendp);
+	      enc[i].desc = desc;
+	      enc[i].form = form;
 
-	  printf (" %-5u %-5u %-9u %-9u %s\n",
-		  cnt, diridx, mtime, fsize, fname);
+	      printf ("%s(%s)",
+		      dwarf_line_content_description_name (desc),
+		      dwarf_form_name (form));
+	      if (i + 1 < file_name_format_count)
+		printf (", ");
+	    }
+	  printf ("]\n");
+
+	  uint64_t file_name_count;
+	  if ((size_t) (lineendp - linep) < 1)
+            goto invalid_data;
+	  get_uleb128 (file_name_count, linep, lineendp);
+
+	  if (file_name_format_count == 0
+	      && file_name_count != 0)
+	    goto invalid_data;
+
+	  for (uint64_t i = 0; i < file_name_count; i++)
+	    {
+	      printf (" %-5lu ", i);
+	      for (int j = 0; j < file_name_format_count; j++)
+		{
+		  linep = print_form_data (dbg, enc[j].form,
+					   linep, lineendp, length,
+					   str_offsets_base);
+		  if (j + 1 < file_name_format_count)
+		    printf (", ");
+		}
+	      printf ("\n");
+	    }
+	}
+      else
+	{
+	  puts (gettext (" Entry Dir   Time      Size      Name"));
+	  for (unsigned int cnt = 1; *linep != 0; ++cnt)
+	    {
+	      /* First comes the file name.  */
+	      char *fname = (char *) linep;
+	      unsigned char *endp = memchr (fname, '\0', lineendp - linep);
+	      if (unlikely (endp == NULL))
+		goto invalid_unit;
+	      linep = endp + 1;
+
+	      /* Then the index.  */
+	      unsigned int diridx;
+	      if (lineendp - linep < 1)
+		goto invalid_unit;
+	      get_uleb128 (diridx, linep, lineendp);
+
+	      /* Next comes the modification time.  */
+	      unsigned int mtime;
+	      if (lineendp - linep < 1)
+		goto invalid_unit;
+	      get_uleb128 (mtime, linep, lineendp);
+
+	      /* Finally the length of the file.  */
+	      unsigned int fsize;
+	      if (lineendp - linep < 1)
+		goto invalid_unit;
+	      get_uleb128 (fsize, linep, lineendp);
+
+	      printf (" %-5u %-5u %-9u %-9u %s\n",
+		      cnt, diridx, mtime, fsize, fname);
+	    }
+	  /* Skip the final NUL byte.  */
+	  ++linep;
 	}
-      /* Skip the final NUL byte.  */
-      ++linep;
 
       puts (gettext ("\nLine number statements:"));
       Dwarf_Word address = 0;
@@ -6941,10 +7376,6 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
       size_t line = 1;
       uint_fast8_t is_stmt = default_is_stmt;
 
-      /* Default address value, in case we do not find the CU.  */
-      size_t address_size
-	= elf_getident (ebl->elf, NULL)[EI_CLASS] == ELFCLASS32 ? 4 : 8;
-
       /* Determine the CU this block is for.  */
       Dwarf_Off cuoffset;
       Dwarf_Off ncuoffset = 0;
@@ -7721,6 +8152,18 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
 		  line_offset);
 	}
 
+      struct mac_culist *cu = NULL;
+      if (line_offset != (Dwarf_Off) -1)
+	{
+	  cu = culist;
+	  while (cu != NULL && line_offset != cu->offset)
+	    cu = cu->next;
+	}
+
+      Dwarf_Off str_offsets_base = str_offsets_base_off (dbg, (cu != NULL
+							       ? cu->die.cu
+							       : NULL));
+
       const unsigned char *vendor[DW_MACRO_hi_user - DW_MACRO_lo_user];
       memset (vendor, 0, sizeof vendor);
       if (flag & 0x04)
@@ -7804,22 +8247,16 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
 
 	      /* Find the CU DIE that matches this line offset.  */
 	      const char *fname = "???";
-	      if (line_offset != (Dwarf_Off) -1)
+	      if (cu != NULL)
 		{
-		  struct mac_culist *cu = culist;
-		  while (cu != NULL && line_offset != cu->offset)
-		    cu = cu->next;
-		  if (cu != NULL)
-		    {
-		      if (cu->files == NULL
-			  && dwarf_getsrcfiles (&cu->die, &cu->files,
-						NULL) != 0)
-			cu->files = (Dwarf_Files *) -1l;
-
-		      if (cu->files != (Dwarf_Files *) -1l)
-			fname = (dwarf_filesrc (cu->files, u128_2,
-						NULL, NULL) ?: "???");
-		    }
+		  if (cu->files == NULL
+		      && dwarf_getsrcfiles (&cu->die, &cu->files,
+					    NULL) != 0)
+		    cu->files = (Dwarf_Files *) -1l;
+
+		  if (cu->files != (Dwarf_Files *) -1l)
+		    fname = (dwarf_filesrc (cu->files, u128_2,
+					    NULL, NULL) ?: "???");
 		}
 	      printf ("%*sstart_file %u, [%u] %s\n",
 		      level, "", u128, u128_2, fname);
@@ -7965,125 +8402,11 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
 	      while (args > 0)
 		{
 		  unsigned int form = *op_desc++;
-		  Dwarf_Word val;
-		  switch (form)
-		    {
-		    case DW_FORM_data1:
-		      if (readp + 1 > readendp)
-			goto invalid_data;
-		      val = *readp++;
-		      printf (" %" PRIx8, (unsigned int) val);
-		      break;
-
-		    case DW_FORM_data2:
-		      if (readp + 2 > readendp)
-			goto invalid_data;
-		      val = read_2ubyte_unaligned_inc (dbg, readp);
-		      printf(" %" PRIx16, (unsigned int) val);
-		      break;
-
-		    case DW_FORM_data4:
-		      if (readp + 4 > readendp)
-			goto invalid_data;
-		      val = read_4ubyte_unaligned_inc (dbg, readp);
-		      printf (" %" PRIx32, (unsigned int) val);
-		      break;
-
-		    case DW_FORM_data8:
-		      if (readp + 8 > readendp)
-			goto invalid_data;
-		      val = read_8ubyte_unaligned_inc (dbg, readp);
-		      printf (" %" PRIx64, val);
-		      break;
-
-		    case DW_FORM_sdata:
-		      get_sleb128 (val, readp, readendp);
-		      printf (" %" PRIx64, val);
-		      break;
-
-		    case DW_FORM_udata:
-		      get_uleb128 (val, readp, readendp);
-		      printf (" %" PRIx64, val);
-		      break;
-
-		    case DW_FORM_block:
-		      get_uleb128 (val, readp, readendp);
-		      printf (" block[%" PRIu64 "]", val);
-		      if (readp + val > readendp)
-			goto invalid_data;
-		      readp += val;
-		      break;
-
-		    case DW_FORM_block1:
-		      if (readp + 1 > readendp)
-			goto invalid_data;
-		      val = *readp++;
-		      printf (" block[%" PRIu64 "]", val);
-		      if (readp + val > readendp)
-			goto invalid_data;
-		      break;
-
-		    case DW_FORM_block2:
-		      if (readp + 2 > readendp)
-			goto invalid_data;
-		      val = read_2ubyte_unaligned_inc (dbg, readp);
-		      printf (" block[%" PRIu64 "]", val);
-		      if (readp + val > readendp)
-			goto invalid_data;
-		      break;
-
-		    case DW_FORM_block4:
-		      if (readp + 2 > readendp)
-			goto invalid_data;
-		      val =read_4ubyte_unaligned_inc (dbg, readp);
-		      printf (" block[%" PRIu64 "]", val);
-		      if (readp + val > readendp)
-			goto invalid_data;
-		      break;
-
-		    case DW_FORM_flag:
-		      if (readp + 1 > readendp)
-			goto invalid_data;
-		      val = *readp++;
-		      printf (" %s", val != 0 ? gettext ("yes") : gettext ("no"));
-		      break;
-
-		    case DW_FORM_string:
-		      endp = memchr (readp, '\0', readendp - readp);
-		      if (endp == NULL)
-			goto invalid_data;
-		      printf (" %s", readp);
-		      readp = endp + 1;
-		      break;
-
-		    case DW_FORM_strp:
-		      if (readp + offset_len > readendp)
-			goto invalid_data;
-		      if (offset_len == 8)
-			val = read_8ubyte_unaligned_inc (dbg, readp);
-		      else
-			val = read_4ubyte_unaligned_inc (dbg, readp);
-		      printf (" %s", dwarf_getstring (dbg, val, NULL));
-		      break;
-
-		    case DW_FORM_sec_offset:
-		      if (readp + offset_len > readendp)
-			goto invalid_data;
-		      if (offset_len == 8)
-			val = read_8ubyte_unaligned_inc (dbg, readp);
-		      else
-			val = read_4ubyte_unaligned_inc (dbg, readp);
-		      printf (" %" PRIx64, val);
-		      break;
-
-		      default:
-			error (0, 0, gettext ("vendor opcode not verified?"));
-			return;
-		    }
-
+		  print_form_data (dbg, form, readp, readendp, offset_len,
+				   str_offsets_base);
 		  args--;
 		  if (args > 0)
-		    putchar_unlocked (',');
+		    printf (", ");
 		}
 	      putchar_unlocked ('\n');
 	    }
diff --git a/tests/ChangeLog b/tests/ChangeLog
index b236ee7..16011c8 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,9 @@
+2018-05-09  Mark Wielaard  <mark@klomp.org>
+
+	* run-readelf-zdebug.sh: Adjust test output for new header layout.
+	* run-readelf-line.sh: Likewise. Add new tests for testfile-dwarf-4
+	and testfile-dwarf-5.
+
 2018-05-11  Mark Wielaard  <mark@klomp.org>
 
 	* Makefile.am (check_PROGRAMS): Add get-units-invalid.
diff --git a/tests/run-readelf-line.sh b/tests/run-readelf-line.sh
index b08752e..a95e6aa 100755
--- a/tests/run-readelf-line.sh
+++ b/tests/run-readelf-line.sh
@@ -1,5 +1,5 @@
 #! /bin/sh
-# Copyright (C) 2013 Red Hat, Inc.
+# Copyright (C) 2013, 2018 Red Hat, Inc.
 # This file is part of elfutils.
 #
 # This file is free software; you can redistribute it and/or modify
@@ -28,15 +28,17 @@ DWARF section [30] '.debug_line' at offset 0x15f6:
 
 Table at offset 0:
 
- Length:                     83
- DWARF version:              2
- Prologue length:            43
- Minimum instruction length: 1
- Maximum operations per instruction: 1
- Initial value if 'is_stmt': 1
- Line base:                  -5
- Line range:                 14
- Opcode base:                13
+ Length:                         83
+ DWARF version:                  2
+ Prologue length:                43
+ Address size:                   4
+ Segment selector size:          0
+ Min instruction length:         1
+ Max operations per instruction: 1
+ Initial value if 'is_stmt':     1
+ Line base:                      -5
+ Line range:                     14
+ Opcode base:                    13
 
 Opcodes:
   [ 1]  0 arguments
@@ -83,15 +85,17 @@ Line number statements:
 
 Table at offset 87:
 
- Length:                     72
- DWARF version:              2
- Prologue length:            28
- Minimum instruction length: 1
- Maximum operations per instruction: 1
- Initial value if 'is_stmt': 1
- Line base:                  -5
- Line range:                 14
- Opcode base:                13
+ Length:                         72
+ DWARF version:                  2
+ Prologue length:                28
+ Address size:                   4
+ Segment selector size:          0
+ Min instruction length:         1
+ Max operations per instruction: 1
+ Initial value if 'is_stmt':     1
+ Line base:                      -5
+ Line range:                     14
+ Opcode base:                    13
 
 Opcodes:
   [ 1]  0 arguments
@@ -133,15 +137,17 @@ Line number statements:
 
 Table at offset 163:
 
- Length:                     106
- DWARF version:              2
- Prologue length:            43
- Minimum instruction length: 1
- Maximum operations per instruction: 1
- Initial value if 'is_stmt': 1
- Line base:                  -5
- Line range:                 14
- Opcode base:                13
+ Length:                         106
+ DWARF version:                  2
+ Prologue length:                43
+ Address size:                   4
+ Segment selector size:          0
+ Min instruction length:         1
+ Max operations per instruction: 1
+ Initial value if 'is_stmt':     1
+ Line base:                      -5
+ Line range:                     14
+ Opcode base:                    13
 
 Opcodes:
   [ 1]  0 arguments
@@ -280,15 +286,17 @@ DWARF section [29] '.debug_line' at offset 0xdf6:
 
 Table at offset 0:
 
- Length:                     69
- DWARF version:              2
- Prologue length:            30
- Minimum instruction length: 4
- Maximum operations per instruction: 1
- Initial value if 'is_stmt': 1
- Line base:                  -5
- Line range:                 14
- Opcode base:                13
+ Length:                         69
+ DWARF version:                  2
+ Prologue length:                30
+ Address size:                   8
+ Segment selector size:          0
+ Min instruction length:         4
+ Max operations per instruction: 1
+ Initial value if 'is_stmt':     1
+ Line base:                      -5
+ Line range:                     14
+ Opcode base:                    13
 
 Opcodes:
   [ 1]  0 arguments
@@ -508,4 +516,634 @@ DWARF section [29] '.debug_line' at offset 0x171f:
 
 EOF
 
+# After discarding the different offsets in the line number statements,
+# the remaining difference between 4 and 5 is (besides the header/length)
+# Just the representation of the directory and line tables:
+
+#  Directory table:
+# - /opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include
+# +      [path(line_strp)]
+# + 0     /var/tmp/hello (90)
+# + 1     /opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include (17)
+#
+#  File name table:
+# - Entry Dir   Time      Size      Name
+# - 1     0     0         0         hello.c
+# - 2     0     0         0         hello.h
+# - 3     1     0         0         stddef.h
+# +      [path(line_strp), directory_index(data1)]
+# + 0     hello.c (9),  0
+# + 1     hello.c (9),  0
+# + 2     hello.h (82),  0
+# + 3     stddef.h (0),  1
+#
+#  Directory table:
+# - /usr/include
+# +      [path(line_strp)]
+# + 0     /var/tmp/hello (90)
+# + 1     /usr/include (122)
+#
+#  File name table:
+# - Entry Dir   Time      Size      Name
+# - 1     0     0         0         world.c
+# - 2     0     0         0         hello.h
+# - 3     1     0         0         stdlib.h
+# +      [path(line_strp), directory_index(data1)]
+# + 0     world.c (114),  0
+# + 1     world.c (114),  0
+# + 2     hello.h (82),  0
+# + 3     stdlib.h (105),  1
+
+testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=line testfile-dwarf-4 << \EOF
+
+DWARF section [29] '.debug_line' at offset 0x1734:
+
+Table at offset 0:
+
+ Length:                         608
+ DWARF version:                  4
+ Prologue length:                119
+ Address size:                   8
+ Segment selector size:          0
+ Min instruction length:         1
+ Max operations per instruction: 1
+ Initial value if 'is_stmt':     1
+ Line base:                      -10
+ Line range:                     242
+ Opcode base:                    13
+
+Opcodes:
+  [ 1]  0 arguments
+  [ 2]  1 argument
+  [ 3]  1 argument
+  [ 4]  1 argument
+  [ 5]  1 argument
+  [ 6]  0 arguments
+  [ 7]  0 arguments
+  [ 8]  0 arguments
+  [ 9]  1 argument
+  [10]  0 arguments
+  [11]  0 arguments
+  [12]  1 argument
+
+Directory table:
+ /opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include
+
+File name table:
+ Entry Dir   Time      Size      Name
+ 1     0     0         0         hello.c
+ 2     0     0         0         hello.h
+ 3     1     0         0         stddef.h
+
+Line number statements:
+ [    81] extended opcode 2:  set address to 0x400510 <foo>
+ [    8c] special opcode 43: address+0 = 0x400510 <foo>, line+20 = 21
+ [    8d] set column to 1
+ [    8f] extended opcode 2:  set address to 0x400510 <foo>
+ [    9a] special opcode 24: address+0 = 0x400510 <foo>, line+1 = 22
+ [    9b] set column to 3
+ [    9d] extended opcode 2:  set address to 0x400510 <foo>
+ [    a8] set 'is_stmt' to 0
+ [    a9] copy
+ [    aa] set column to 6
+ [    ac] extended opcode 2:  set address to 0x400514 <foo+0x4>
+ [    b7] special opcode 26: address+0 = 0x400514 <foo+0x4>, line+3 = 25
+ [    b8] set column to 34
+ [    ba] extended opcode 2:  set address to 0x40051a <foo+0xa>
+ [    c5] set 'is_stmt' to 1
+ [    c6] copy
+ [    c7] set column to 3
+ [    c9] extended opcode 2:  set address to 0x40051a <foo+0xa>
+ [    d4] set 'is_stmt' to 0
+ [    d5] copy
+ [    d6] set column to 34
+ [    d8] extended opcode 2:  set address to 0x40051e <foo+0xe>
+ [    e3] special opcode 24: address+0 = 0x40051e <foo+0xe>, line+1 = 26
+ [    e4] set column to 1
+ [    e6] extended opcode 2:  set address to 0x400528 <foo+0x18>
+ [    f1] extended opcode 4:  set discriminator to 1
+ [    f5] special opcode 22: address+0 = 0x400528 <foo+0x18>, line-1 = 25
+ [    f6] set column to 18
+ [    f8] extended opcode 2:  set address to 0x40052b <foo+0x1b>
+ [   103] set file to 2
+ [   105] set 'is_stmt' to 1
+ [   106] advance line by constant -18 to 7
+ [   108] copy
+ [   109] set column to 3
+ [   10b] extended opcode 2:  set address to 0x40052b <foo+0x1b>
+ [   116] special opcode 25: address+0 = 0x40052b <foo+0x1b>, line+2 = 9
+ [   117] set column to 3
+ [   119] extended opcode 2:  set address to 0x40052b <foo+0x1b>
+ [   124] set 'is_stmt' to 0
+ [   125] copy
+ [   126] set column to 6
+ [   128] extended opcode 2:  set address to 0x40052f <foo+0x1f>
+ [   133] extended opcode 4:  set discriminator to 0
+ [   137] set 'is_stmt' to 1
+ [   138] special opcode 24: address+0 = 0x40052f <foo+0x1f>, line+1 = 10
+ [   139] set column to 5
+ [   13b] extended opcode 2:  set address to 0x40052f <foo+0x1f>
+ [   146] set 'is_stmt' to 0
+ [   147] copy
+ [   148] set column to 7
+ [   14a] extended opcode 2:  set address to 0x400531 <foo+0x21>
+ [   155] set 'is_stmt' to 1
+ [   156] special opcode 25: address+0 = 0x400531 <foo+0x21>, line+2 = 12
+ [   157] set column to 3
+ [   159] extended opcode 2:  set address to 0x400531 <foo+0x21>
+ [   164] set file to 1
+ [   166] special opcode 21: address+0 = 0x400531 <foo+0x21>, line-2 = 10
+ [   167] set column to 3
+ [   169] extended opcode 2:  set address to 0x400531 <foo+0x21>
+ [   174] special opcode 25: address+0 = 0x400531 <foo+0x21>, line+2 = 12
+ [   175] set column to 3
+ [   177] extended opcode 2:  set address to 0x400531 <foo+0x21>
+ [   182] set 'is_stmt' to 0
+ [   183] copy
+ [   184] set column to 6
+ [   186] extended opcode 2:  set address to 0x400535 <foo+0x25>
+ [   191] set 'is_stmt' to 1
+ [   192] special opcode 24: address+0 = 0x400535 <foo+0x25>, line+1 = 13
+ [   193] set column to 5
+ [   195] extended opcode 2:  set address to 0x400535 <foo+0x25>
+ [   1a0] set 'is_stmt' to 0
+ [   1a1] copy
+ [   1a2] set column to 7
+ [   1a4] extended opcode 2:  set address to 0x400539 <foo+0x29>
+ [   1af] set 'is_stmt' to 1
+ [   1b0] special opcode 25: address+0 = 0x400539 <foo+0x29>, line+2 = 15
+ [   1b1] set column to 3
+ [   1b3] extended opcode 2:  set address to 0x400539 <foo+0x29>
+ [   1be] special opcode 30: address+0 = 0x400539 <foo+0x29>, line+7 = 22
+ [   1bf] set column to 3
+ [   1c1] extended opcode 2:  set address to 0x400539 <foo+0x29>
+ [   1cc] set 'is_stmt' to 0
+ [   1cd] copy
+ [   1ce] set column to 6
+ [   1d0] extended opcode 2:  set address to 0x40053d <foo+0x2d>
+ [   1db] set 'is_stmt' to 1
+ [   1dc] special opcode 24: address+0 = 0x40053d <foo+0x2d>, line+1 = 23
+ [   1dd] set column to 5
+ [   1df] extended opcode 2:  set address to 0x40053d <foo+0x2d>
+ [   1ea] set 'is_stmt' to 0
+ [   1eb] copy
+ [   1ec] set column to 12
+ [   1ee] extended opcode 2:  set address to 0x400550 <baz>
+ [   1f9] set 'is_stmt' to 1
+ [   1fa] advance line by constant -14 to 9
+ [   1fc] copy
+ [   1fd] set column to 1
+ [   1ff] extended opcode 2:  set address to 0x400550 <baz>
+ [   20a] special opcode 24: address+0 = 0x400550 <baz>, line+1 = 10
+ [   20b] set column to 3
+ [   20d] extended opcode 2:  set address to 0x400550 <baz>
+ [   218] special opcode 25: address+0 = 0x400550 <baz>, line+2 = 12
+ [   219] set column to 3
+ [   21b] extended opcode 2:  set address to 0x400550 <baz>
+ [   226] set 'is_stmt' to 0
+ [   227] copy
+ [   228] set column to 9
+ [   22a] extended opcode 2:  set address to 0x400556 <baz+0x6>
+ [   235] special opcode 24: address+0 = 0x400556 <baz+0x6>, line+1 = 13
+ [   236] set column to 7
+ [   238] extended opcode 2:  set address to 0x40055f <baz+0xf>
+ [   243] set 'is_stmt' to 1
+ [   244] special opcode 25: address+0 = 0x40055f <baz+0xf>, line+2 = 15
+ [   245] set column to 3
+ [   247] extended opcode 2:  set address to 0x40055f <baz+0xf>
+ [   252] set 'is_stmt' to 0
+ [   253] copy
+ [   254] set column to 7
+ [   256] extended opcode 2:  set address to 0x400561
+ [   261] extended opcode 1:  end of sequence
+
+Table at offset 612:
+
+ Length:                         450
+ DWARF version:                  4
+ Prologue length:                67
+ Address size:                   8
+ Segment selector size:          0
+ Min instruction length:         1
+ Max operations per instruction: 1
+ Initial value if 'is_stmt':     1
+ Line base:                      -10
+ Line range:                     242
+ Opcode base:                    13
+
+Opcodes:
+  [ 1]  0 arguments
+  [ 2]  1 argument
+  [ 3]  1 argument
+  [ 4]  1 argument
+  [ 5]  1 argument
+  [ 6]  0 arguments
+  [ 7]  0 arguments
+  [ 8]  0 arguments
+  [ 9]  1 argument
+  [10]  0 arguments
+  [11]  0 arguments
+  [12]  1 argument
+
+Directory table:
+ /usr/include
+
+File name table:
+ Entry Dir   Time      Size      Name
+ 1     0     0         0         world.c
+ 2     0     0         0         hello.h
+ 3     1     0         0         stdlib.h
+
+Line number statements:
+ [   2b1] extended opcode 2:  set address to 0x400410 <main>
+ [   2bc] special opcode 37: address+0 = 0x400410 <main>, line+14 = 15
+ [   2bd] set column to 1
+ [   2bf] extended opcode 2:  set address to 0x400410 <main>
+ [   2ca] special opcode 24: address+0 = 0x400410 <main>, line+1 = 16
+ [   2cb] set column to 3
+ [   2cd] extended opcode 2:  set address to 0x400410 <main>
+ [   2d8] special opcode 24: address+0 = 0x400410 <main>, line+1 = 17
+ [   2d9] set column to 3
+ [   2db] extended opcode 2:  set address to 0x400410 <main>
+ [   2e6] set 'is_stmt' to 0
+ [   2e7] special opcode 21: address+0 = 0x400410 <main>, line-2 = 15
+ [   2e8] set column to 1
+ [   2ea] extended opcode 2:  set address to 0x400419 <main+0x9>
+ [   2f5] special opcode 25: address+0 = 0x400419 <main+0x9>, line+2 = 17
+ [   2f6] set column to 6
+ [   2f8] extended opcode 2:  set address to 0x40041e <main+0xe>
+ [   303] set 'is_stmt' to 1
+ [   304] special opcode 24: address+0 = 0x40041e <main+0xe>, line+1 = 18
+ [   305] set column to 5
+ [   307] extended opcode 2:  set address to 0x40041e <main+0xe>
+ [   312] set 'is_stmt' to 0
+ [   313] copy
+ [   314] set column to 7
+ [   316] extended opcode 2:  set address to 0x400421 <main+0x11>
+ [   321] set 'is_stmt' to 1
+ [   322] special opcode 27: address+0 = 0x400421 <main+0x11>, line+4 = 22
+ [   323] set column to 3
+ [   325] extended opcode 2:  set address to 0x400430 <_start>
+ [   330] extended opcode 1:  end of sequence
+ [   333] extended opcode 2:  set address to 0x400570 <calc>
+ [   33e] special opcode 28: address+0 = 0x400570 <calc>, line+5 = 6
+ [   33f] set column to 1
+ [   341] extended opcode 2:  set address to 0x400570 <calc>
+ [   34c] special opcode 24: address+0 = 0x400570 <calc>, line+1 = 7
+ [   34d] set column to 3
+ [   34f] extended opcode 2:  set address to 0x400570 <calc>
+ [   35a] set 'is_stmt' to 0
+ [   35b] copy
+ [   35c] set column to 6
+ [   35e] extended opcode 2:  set address to 0x400575 <calc+0x5>
+ [   369] extended opcode 4:  set discriminator to 1
+ [   36d] copy
+ [   36e] set column to 24
+ [   370] extended opcode 2:  set address to 0x400578 <calc+0x8>
+ [   37b] copy
+ [   37c] set column to 17
+ [   37e] extended opcode 2:  set address to 0x40057d <calc+0xd>
+ [   389] extended opcode 4:  set discriminator to 0
+ [   38d] set 'is_stmt' to 1
+ [   38e] special opcode 26: address+0 = 0x40057d <calc+0xd>, line+3 = 10
+ [   38f] set column to 3
+ [   391] extended opcode 2:  set address to 0x40057d <calc+0xd>
+ [   39c] set 'is_stmt' to 0
+ [   39d] copy
+ [   39e] set column to 10
+ [   3a0] extended opcode 2:  set address to 0x400583 <calc+0x13>
+ [   3ab] set file to 2
+ [   3ad] copy
+ [   3ae] set column to 7
+ [   3b0] extended opcode 2:  set address to 0x400585 <calc+0x15>
+ [   3bb] set file to 1
+ [   3bd] copy
+ [   3be] set column to 10
+ [   3c0] extended opcode 2:  set address to 0x400588 <calc+0x18>
+ [   3cb] set file to 2
+ [   3cd] set 'is_stmt' to 1
+ [   3ce] special opcode 20: address+0 = 0x400588 <calc+0x18>, line-3 = 7
+ [   3cf] set column to 3
+ [   3d1] extended opcode 2:  set address to 0x400588 <calc+0x18>
+ [   3dc] special opcode 25: address+0 = 0x400588 <calc+0x18>, line+2 = 9
+ [   3dd] set column to 3
+ [   3df] extended opcode 2:  set address to 0x400588 <calc+0x18>
+ [   3ea] set 'is_stmt' to 0
+ [   3eb] special opcode 24: address+0 = 0x400588 <calc+0x18>, line+1 = 10
+ [   3ec] set column to 7
+ [   3ee] extended opcode 2:  set address to 0x40058f <calc+0x1f>
+ [   3f9] set 'is_stmt' to 1
+ [   3fa] special opcode 25: address+0 = 0x40058f <calc+0x1f>, line+2 = 12
+ [   3fb] set column to 3
+ [   3fd] extended opcode 2:  set address to 0x40058f <calc+0x1f>
+ [   408] set 'is_stmt' to 0
+ [   409] copy
+ [   40a] set column to 10
+ [   40c] extended opcode 2:  set address to 0x400598 <calc+0x28>
+ [   417] set file to 1
+ [   419] special opcode 22: address+0 = 0x400598 <calc+0x28>, line-1 = 11
+ [   41a] set column to 1
+ [   41c] extended opcode 2:  set address to 0x40059b
+ [   427] extended opcode 1:  end of sequence
+EOF
+
+testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=line testfile-dwarf-5 << \EOF
+
+DWARF section [29] '.debug_line' at offset 0x171f:
+
+Table at offset 0:
+
+ Length:                         547
+ DWARF version:                  5
+ Prologue length:                56
+ Address size:                   8
+ Segment selector size:          0
+ Min instruction length:         1
+ Max operations per instruction: 1
+ Initial value if 'is_stmt':     1
+ Line base:                      -10
+ Line range:                     242
+ Opcode base:                    13
+
+Opcodes:
+  [ 1]  0 arguments
+  [ 2]  1 argument
+  [ 3]  1 argument
+  [ 4]  1 argument
+  [ 5]  1 argument
+  [ 6]  0 arguments
+  [ 7]  0 arguments
+  [ 8]  0 arguments
+  [ 9]  1 argument
+  [10]  0 arguments
+  [11]  0 arguments
+  [12]  1 argument
+
+Directory table:
+      [path(line_strp)]
+ 0     /var/tmp/hello (90)
+ 1     /opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include (17)
+
+File name table:
+      [path(line_strp), directory_index(data1)]
+ 0     hello.c (9),  0
+ 1     hello.c (9),  0
+ 2     hello.h (82),  0
+ 3     stddef.h (0),  1
+
+Line number statements:
+ [    44] extended opcode 2:  set address to 0x400510 <foo>
+ [    4f] special opcode 43: address+0 = 0x400510 <foo>, line+20 = 21
+ [    50] set column to 1
+ [    52] extended opcode 2:  set address to 0x400510 <foo>
+ [    5d] special opcode 24: address+0 = 0x400510 <foo>, line+1 = 22
+ [    5e] set column to 3
+ [    60] extended opcode 2:  set address to 0x400510 <foo>
+ [    6b] set 'is_stmt' to 0
+ [    6c] copy
+ [    6d] set column to 6
+ [    6f] extended opcode 2:  set address to 0x400514 <foo+0x4>
+ [    7a] special opcode 26: address+0 = 0x400514 <foo+0x4>, line+3 = 25
+ [    7b] set column to 34
+ [    7d] extended opcode 2:  set address to 0x40051a <foo+0xa>
+ [    88] set 'is_stmt' to 1
+ [    89] copy
+ [    8a] set column to 3
+ [    8c] extended opcode 2:  set address to 0x40051a <foo+0xa>
+ [    97] set 'is_stmt' to 0
+ [    98] copy
+ [    99] set column to 34
+ [    9b] extended opcode 2:  set address to 0x40051e <foo+0xe>
+ [    a6] special opcode 24: address+0 = 0x40051e <foo+0xe>, line+1 = 26
+ [    a7] set column to 1
+ [    a9] extended opcode 2:  set address to 0x400528 <foo+0x18>
+ [    b4] extended opcode 4:  set discriminator to 1
+ [    b8] special opcode 22: address+0 = 0x400528 <foo+0x18>, line-1 = 25
+ [    b9] set column to 18
+ [    bb] extended opcode 2:  set address to 0x40052b <foo+0x1b>
+ [    c6] set file to 2
+ [    c8] set 'is_stmt' to 1
+ [    c9] advance line by constant -18 to 7
+ [    cb] copy
+ [    cc] set column to 3
+ [    ce] extended opcode 2:  set address to 0x40052b <foo+0x1b>
+ [    d9] special opcode 25: address+0 = 0x40052b <foo+0x1b>, line+2 = 9
+ [    da] set column to 3
+ [    dc] extended opcode 2:  set address to 0x40052b <foo+0x1b>
+ [    e7] set 'is_stmt' to 0
+ [    e8] copy
+ [    e9] set column to 6
+ [    eb] extended opcode 2:  set address to 0x40052f <foo+0x1f>
+ [    f6] extended opcode 4:  set discriminator to 0
+ [    fa] set 'is_stmt' to 1
+ [    fb] special opcode 24: address+0 = 0x40052f <foo+0x1f>, line+1 = 10
+ [    fc] set column to 5
+ [    fe] extended opcode 2:  set address to 0x40052f <foo+0x1f>
+ [   109] set 'is_stmt' to 0
+ [   10a] copy
+ [   10b] set column to 7
+ [   10d] extended opcode 2:  set address to 0x400531 <foo+0x21>
+ [   118] set 'is_stmt' to 1
+ [   119] special opcode 25: address+0 = 0x400531 <foo+0x21>, line+2 = 12
+ [   11a] set column to 3
+ [   11c] extended opcode 2:  set address to 0x400531 <foo+0x21>
+ [   127] set file to 1
+ [   129] special opcode 21: address+0 = 0x400531 <foo+0x21>, line-2 = 10
+ [   12a] set column to 3
+ [   12c] extended opcode 2:  set address to 0x400531 <foo+0x21>
+ [   137] special opcode 25: address+0 = 0x400531 <foo+0x21>, line+2 = 12
+ [   138] set column to 3
+ [   13a] extended opcode 2:  set address to 0x400531 <foo+0x21>
+ [   145] set 'is_stmt' to 0
+ [   146] copy
+ [   147] set column to 6
+ [   149] extended opcode 2:  set address to 0x400535 <foo+0x25>
+ [   154] set 'is_stmt' to 1
+ [   155] special opcode 24: address+0 = 0x400535 <foo+0x25>, line+1 = 13
+ [   156] set column to 5
+ [   158] extended opcode 2:  set address to 0x400535 <foo+0x25>
+ [   163] set 'is_stmt' to 0
+ [   164] copy
+ [   165] set column to 7
+ [   167] extended opcode 2:  set address to 0x400539 <foo+0x29>
+ [   172] set 'is_stmt' to 1
+ [   173] special opcode 25: address+0 = 0x400539 <foo+0x29>, line+2 = 15
+ [   174] set column to 3
+ [   176] extended opcode 2:  set address to 0x400539 <foo+0x29>
+ [   181] special opcode 30: address+0 = 0x400539 <foo+0x29>, line+7 = 22
+ [   182] set column to 3
+ [   184] extended opcode 2:  set address to 0x400539 <foo+0x29>
+ [   18f] set 'is_stmt' to 0
+ [   190] copy
+ [   191] set column to 6
+ [   193] extended opcode 2:  set address to 0x40053d <foo+0x2d>
+ [   19e] set 'is_stmt' to 1
+ [   19f] special opcode 24: address+0 = 0x40053d <foo+0x2d>, line+1 = 23
+ [   1a0] set column to 5
+ [   1a2] extended opcode 2:  set address to 0x40053d <foo+0x2d>
+ [   1ad] set 'is_stmt' to 0
+ [   1ae] copy
+ [   1af] set column to 12
+ [   1b1] extended opcode 2:  set address to 0x400550 <baz>
+ [   1bc] set 'is_stmt' to 1
+ [   1bd] advance line by constant -14 to 9
+ [   1bf] copy
+ [   1c0] set column to 1
+ [   1c2] extended opcode 2:  set address to 0x400550 <baz>
+ [   1cd] special opcode 24: address+0 = 0x400550 <baz>, line+1 = 10
+ [   1ce] set column to 3
+ [   1d0] extended opcode 2:  set address to 0x400550 <baz>
+ [   1db] special opcode 25: address+0 = 0x400550 <baz>, line+2 = 12
+ [   1dc] set column to 3
+ [   1de] extended opcode 2:  set address to 0x400550 <baz>
+ [   1e9] set 'is_stmt' to 0
+ [   1ea] copy
+ [   1eb] set column to 9
+ [   1ed] extended opcode 2:  set address to 0x400556 <baz+0x6>
+ [   1f8] special opcode 24: address+0 = 0x400556 <baz+0x6>, line+1 = 13
+ [   1f9] set column to 7
+ [   1fb] extended opcode 2:  set address to 0x40055f <baz+0xf>
+ [   206] set 'is_stmt' to 1
+ [   207] special opcode 25: address+0 = 0x40055f <baz+0xf>, line+2 = 15
+ [   208] set column to 3
+ [   20a] extended opcode 2:  set address to 0x40055f <baz+0xf>
+ [   215] set 'is_stmt' to 0
+ [   216] copy
+ [   217] set column to 7
+ [   219] extended opcode 2:  set address to 0x400561
+ [   224] extended opcode 1:  end of sequence
+
+Table at offset 551:
+
+ Length:                         441
+ DWARF version:                  5
+ Prologue length:                56
+ Address size:                   8
+ Segment selector size:          0
+ Min instruction length:         1
+ Max operations per instruction: 1
+ Initial value if 'is_stmt':     1
+ Line base:                      -10
+ Line range:                     242
+ Opcode base:                    13
+
+Opcodes:
+  [ 1]  0 arguments
+  [ 2]  1 argument
+  [ 3]  1 argument
+  [ 4]  1 argument
+  [ 5]  1 argument
+  [ 6]  0 arguments
+  [ 7]  0 arguments
+  [ 8]  0 arguments
+  [ 9]  1 argument
+  [10]  0 arguments
+  [11]  0 arguments
+  [12]  1 argument
+
+Directory table:
+      [path(line_strp)]
+ 0     /var/tmp/hello (90)
+ 1     /usr/include (122)
+
+File name table:
+      [path(line_strp), directory_index(data1)]
+ 0     world.c (114),  0
+ 1     world.c (114),  0
+ 2     hello.h (82),  0
+ 3     stdlib.h (105),  1
+
+Line number statements:
+ [   26b] extended opcode 2:  set address to 0x400410 <main>
+ [   276] special opcode 37: address+0 = 0x400410 <main>, line+14 = 15
+ [   277] set column to 1
+ [   279] extended opcode 2:  set address to 0x400410 <main>
+ [   284] special opcode 24: address+0 = 0x400410 <main>, line+1 = 16
+ [   285] set column to 3
+ [   287] extended opcode 2:  set address to 0x400410 <main>
+ [   292] special opcode 24: address+0 = 0x400410 <main>, line+1 = 17
+ [   293] set column to 3
+ [   295] extended opcode 2:  set address to 0x400410 <main>
+ [   2a0] set 'is_stmt' to 0
+ [   2a1] special opcode 21: address+0 = 0x400410 <main>, line-2 = 15
+ [   2a2] set column to 1
+ [   2a4] extended opcode 2:  set address to 0x400419 <main+0x9>
+ [   2af] special opcode 25: address+0 = 0x400419 <main+0x9>, line+2 = 17
+ [   2b0] set column to 6
+ [   2b2] extended opcode 2:  set address to 0x40041e <main+0xe>
+ [   2bd] set 'is_stmt' to 1
+ [   2be] special opcode 24: address+0 = 0x40041e <main+0xe>, line+1 = 18
+ [   2bf] set column to 5
+ [   2c1] extended opcode 2:  set address to 0x40041e <main+0xe>
+ [   2cc] set 'is_stmt' to 0
+ [   2cd] copy
+ [   2ce] set column to 7
+ [   2d0] extended opcode 2:  set address to 0x400421 <main+0x11>
+ [   2db] set 'is_stmt' to 1
+ [   2dc] special opcode 27: address+0 = 0x400421 <main+0x11>, line+4 = 22
+ [   2dd] set column to 3
+ [   2df] extended opcode 2:  set address to 0x400430 <_start>
+ [   2ea] extended opcode 1:  end of sequence
+ [   2ed] extended opcode 2:  set address to 0x400570 <calc>
+ [   2f8] special opcode 28: address+0 = 0x400570 <calc>, line+5 = 6
+ [   2f9] set column to 1
+ [   2fb] extended opcode 2:  set address to 0x400570 <calc>
+ [   306] special opcode 24: address+0 = 0x400570 <calc>, line+1 = 7
+ [   307] set column to 3
+ [   309] extended opcode 2:  set address to 0x400570 <calc>
+ [   314] set 'is_stmt' to 0
+ [   315] copy
+ [   316] set column to 6
+ [   318] extended opcode 2:  set address to 0x400575 <calc+0x5>
+ [   323] extended opcode 4:  set discriminator to 1
+ [   327] copy
+ [   328] set column to 24
+ [   32a] extended opcode 2:  set address to 0x400578 <calc+0x8>
+ [   335] copy
+ [   336] set column to 17
+ [   338] extended opcode 2:  set address to 0x40057d <calc+0xd>
+ [   343] extended opcode 4:  set discriminator to 0
+ [   347] set 'is_stmt' to 1
+ [   348] special opcode 26: address+0 = 0x40057d <calc+0xd>, line+3 = 10
+ [   349] set column to 3
+ [   34b] extended opcode 2:  set address to 0x40057d <calc+0xd>
+ [   356] set 'is_stmt' to 0
+ [   357] copy
+ [   358] set column to 10
+ [   35a] extended opcode 2:  set address to 0x400583 <calc+0x13>
+ [   365] set file to 2
+ [   367] copy
+ [   368] set column to 7
+ [   36a] extended opcode 2:  set address to 0x400585 <calc+0x15>
+ [   375] set file to 1
+ [   377] copy
+ [   378] set column to 10
+ [   37a] extended opcode 2:  set address to 0x400588 <calc+0x18>
+ [   385] set file to 2
+ [   387] set 'is_stmt' to 1
+ [   388] special opcode 20: address+0 = 0x400588 <calc+0x18>, line-3 = 7
+ [   389] set column to 3
+ [   38b] extended opcode 2:  set address to 0x400588 <calc+0x18>
+ [   396] special opcode 25: address+0 = 0x400588 <calc+0x18>, line+2 = 9
+ [   397] set column to 3
+ [   399] extended opcode 2:  set address to 0x400588 <calc+0x18>
+ [   3a4] set 'is_stmt' to 0
+ [   3a5] special opcode 24: address+0 = 0x400588 <calc+0x18>, line+1 = 10
+ [   3a6] set column to 7
+ [   3a8] extended opcode 2:  set address to 0x40058f <calc+0x1f>
+ [   3b3] set 'is_stmt' to 1
+ [   3b4] special opcode 25: address+0 = 0x40058f <calc+0x1f>, line+2 = 12
+ [   3b5] set column to 3
+ [   3b7] extended opcode 2:  set address to 0x40058f <calc+0x1f>
+ [   3c2] set 'is_stmt' to 0
+ [   3c3] copy
+ [   3c4] set column to 10
+ [   3c6] extended opcode 2:  set address to 0x400598 <calc+0x28>
+ [   3d1] set file to 1
+ [   3d3] special opcode 22: address+0 = 0x400598 <calc+0x28>, line-1 = 11
+ [   3d4] set column to 1
+ [   3d6] extended opcode 2:  set address to 0x40059b
+ [   3e1] extended opcode 1:  end of sequence
+EOF
+
 exit 0
diff --git a/tests/run-readelf-zdebug.sh b/tests/run-readelf-zdebug.sh
index 28128ad..878e0ba 100755
--- a/tests/run-readelf-zdebug.sh
+++ b/tests/run-readelf-zdebug.sh
@@ -361,15 +361,17 @@ DWARF section [34] '.debug_line' at offset 0x104c:
 
 Table at offset 0:
 
- Length:                     70
- DWARF version:              2
- Prologue length:            40
- Minimum instruction length: 1
- Maximum operations per instruction: 1
- Initial value if 'is_stmt': 1
- Line base:                  -5
- Line range:                 14
- Opcode base:                13
+ Length:                         70
+ DWARF version:                  2
+ Prologue length:                40
+ Address size:                   8
+ Segment selector size:          0
+ Min instruction length:         1
+ Max operations per instruction: 1
+ Initial value if 'is_stmt':     1
+ Line base:                      -5
+ Line range:                     14
+ Opcode base:                    13
 
 Opcodes:
   [ 1]  0 arguments
-- 
1.8.3.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]