]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdw: Handle DWARF5 line tables in dwarf_getsrclines.
authorMark Wielaard <mark@klomp.org>
Sat, 5 May 2018 22:33:27 +0000 (00:33 +0200)
committerMark Wielaard <mark@klomp.org>
Fri, 11 May 2018 14:42:57 +0000 (16:42 +0200)
In DWARF5 the actual line number table format doesn't change, except for
not allowing DW_LNE_define_file (but we still just accept it). The
changes are the header having new fields for address and segment
selector sizes, and new formats for the directory and file names tables.

The directory and file name tables are much more flexible in DWARF5, but
we only interpret the actual names and file/dir index relationships,
skipping/ignoring any other information. There also is no new interface
yet to get at the new directory and file properties.

There is some small confusion about the file name table indexing. Older
DWARF versions explicitly called the first file name table 1. DWARF5
implies the first index is 0 (but for file attributes, zero means not
associated with a file). We get away with that by having an actual zero
index for older DWARF versions (the null_fill). It looks like gcc gets
around it by explicitly duplicating the first (0) and second (1) file
name entry in the table. This can also be seen in the new testcase.

The patch looks big because of moving a few initializations around
and because the code that is different for older/newer DWARF got moved
under if statements. But the original old DWARF code path didn't really
change.

Signed-off-by: Mark Wielaard <mark@klomp.org>
libdw/ChangeLog
libdw/dwarf.h
libdw/dwarf_getsrclines.c
libdw/libdwP.h
tests/ChangeLog
tests/Makefile.am
tests/run-readelf-line.sh
tests/testfile-dwarf-4.bz2 [new file with mode: 0755]
tests/testfile-dwarf-45.source [new file with mode: 0644]
tests/testfile-dwarf-5.bz2 [new file with mode: 0755]

index 9ec493fb56cdfa94535a6ce523a301c55941f4d6..cc7eae9d46898972770953ffa072dd643209c472 100644 (file)
@@ -1,3 +1,11 @@
+2018-05-05  Mark Wielaard  <mark@klomp.org>
+
+       * dwarf.h: Add DWARF line content descriptions.
+       * libdwP.h (libdw_valid_user_form): New static function.
+       * dwarf_getsrclines.c (read_srclines): Check and parse version 5
+       DWARF header, dir and file tables separately from older versions
+       where different.
+
 2018-04-24  Mark Wielaard  <mark@klomp.org>
 
        * dwarf_begin_elf.c (dwarf_scnnames): Add ".debug_line_str".
index 99cc11282572548f4bfbab4d3a1b56be1e084554..fc9801bd5a6827a939b9dfc5c95807828b86800c 100644 (file)
@@ -783,6 +783,17 @@ enum
     DW_DEFAULTED_out_of_class = 2
   };
 
+/* DWARF line content descriptions.  */
+enum
+  {
+    DW_LNCT_path = 0x1,
+    DW_LNCT_directory_index = 0x2,
+    DW_LNCT_timestamp = 0x3,
+    DW_LNCT_size = 0x4,
+    DW_LNCT_MD5 = 0x5,
+    DW_LNCT_lo_user = 0x2000,
+    DW_LNCT_hi_user = 0x3fff
+  };
 
 /* DWARF standard opcode encodings.  */
 enum
index d02c38db40eb8f01b19acb662f214fa62b057d89..2f966ab7db7afcb3cd94ef3e4108a3a31749c2aa 100644 (file)
@@ -1,7 +1,6 @@
 /* Return line number information of CU.
-   Copyright (C) 2004-2010, 2013, 2014, 2015, 2016 Red Hat, Inc.
+   Copyright (C) 2004-2010, 2013, 2014, 2015, 2016, 2018 Red Hat, Inc.
    This file is part of elfutils.
-   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
 
    This file is free software; you can redistribute it and/or modify
    it under the terms of either
@@ -157,18 +156,6 @@ read_srclines (Dwarf *dbg,
   size_t nfilelist = 0;
   unsigned int ndirlist = 0;
 
-  struct filelist null_file =
-    {
-      .info =
-      {
-       .name = "???",
-       .mtime = 0,
-       .length = 0
-      },
-      .next = NULL
-    };
-  struct filelist *filelist = &null_file;
-
   /* 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.  */
@@ -177,16 +164,7 @@ read_srclines (Dwarf *dbg,
 #define MAX_STACK_FILES (MAX_STACK_ALLOC / 4)
 #define MAX_STACK_DIRS  (MAX_STACK_ALLOC / 16)
 
-  struct dirlist
-  {
-    const char *dir;
-    size_t len;
-  };
-  struct dirlist dirstack[MAX_STACK_DIRS];
-  struct dirlist *dirarray = dirstack;
-
-  /* We are about to process the statement program.  Initialize the
-     state machine registers (see 6.2.2 in the v2.1 specification).  */
+  /* Initial statement program state (except for stmt_list, see below).  */
   struct line_state state =
     {
       .linelist = NULL,
@@ -222,25 +200,45 @@ read_srclines (Dwarf *dbg,
     }
 
   /* 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);
-  if (unlikely (version < 2) || unlikely (version > 4))
+  if (unlikely (version < 2) || unlikely (version > 5))
     {
       __libdw_seterrno (DWARF_E_VERSION);
       goto out;
     }
 
+  /* DWARF5 explicitly lists address and segment_selector sizes.  */
+  if (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)
+       goto invalid_data;
+    }
+
   /* 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);
+    {
+      if ((size_t) (lineendp - linep) < 8)
+       goto invalid_data;
+      header_length = read_8ubyte_unaligned_inc (dbg, linep);
+    }
   const unsigned char *header_start = linep;
 
   /* Next the minimum instruction length.  */
@@ -250,13 +248,17 @@ read_srclines (Dwarf *dbg,
   uint_fast8_t max_ops_per_instr = 1;
   if (version >= 4)
     {
-      if (unlikely (lineendp - linep < 5))
+      if (unlikely ((size_t) (lineendp - linep) < 1))
        goto invalid_data;
       max_ops_per_instr = *linep++;
       if (unlikely (max_ops_per_instr == 0))
        goto invalid_data;
     }
 
+  /* 4 more bytes, is_stmt, line_base, line_range and opcode_base.  */
+  if ((size_t) (lineendp - linep) < 4)
+    goto invalid_data;
+
   /* Then the flag determining the default value of the is_stmt
      register.  */
   uint_fast8_t default_is_stmt = *linep++;
@@ -277,29 +279,84 @@ read_srclines (Dwarf *dbg,
     goto invalid_data;
   linep += opcode_base - 1;
 
-  /* First comes the list of directories.  Add the compilation
-     directory first since the index zero is used for it.  */
-  struct dirlist comp_dir_elem =
-    {
-      .dir = comp_dir,
-      .len = comp_dir ? strlen (comp_dir) : 0,
-    };
-  ndirlist = 1;
+  /* To read DWARF5 dir and file lists we need to know the forms.  For
+     now we skip everything, except the DW_LNCT_path and
+     DW_LNCT_directory_index.  */
+  uint16_t forms[256];
+  unsigned char nforms = 0;
+  unsigned char form_path = -1; /* Which forms is DW_LNCT_path.  */
+  unsigned char form_idx = -1;  /* And which is DW_LNCT_directory_index.  */
+
+  /* To read/skip form data.  */
+  Dwarf_CU fake_cu = {
+    .dbg = dbg,
+    .sec_idx = IDX_debug_line,
+    .version = 5,
+    .offset_size = length,
+    .address_size = address_size,
+    .startp = (void *) linep,
+    .endp = (void *) lineendp,
+  };
 
   /* First count the entries.  */
-  const unsigned char *dirp = linep;
   unsigned int ndirs = 0;
-  while (*dirp != 0)
+  if (version < 5)
     {
-      uint8_t *endp = memchr (dirp, '\0', lineendp - dirp);
-      if (endp == NULL)
+      const unsigned char *dirp = linep;
+      while (*dirp != 0)
+       {
+         uint8_t *endp = memchr (dirp, '\0', lineendp - dirp);
+         if (endp == NULL)
+           goto invalid_data;
+         ++ndirs;
+         dirp = endp + 1;
+       }
+      ndirs = ndirs + 1; /* There is always the "unknown" dir.  */
+    }
+  else
+    {
+      if ((size_t) (lineendp - linep) < 1)
+       goto invalid_data;
+      nforms = *linep++;
+      for (int i = 0; i < nforms; 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);
+
+         if (! libdw_valid_user_form (form))
+           goto invalid_data;
+
+         forms[i] = form;
+         if (desc == DW_LNCT_path)
+           form_path = i;
+       }
+
+      if (nforms > 0 && form_path == (unsigned char) -1)
+       goto invalid_data;
+
+      if ((size_t) (lineendp - linep) < 1)
+       goto invalid_data;
+      get_uleb128 (ndirs, linep, lineendp);
+
+      if (nforms == 0 && ndirs != 0)
        goto invalid_data;
-      ++ndirs;
-      dirp = endp + 1;
     }
-  ndirlist += ndirs;
+
+  struct dirlist
+  {
+    const char *dir;
+    size_t len;
+  };
+  struct dirlist dirstack[MAX_STACK_DIRS];
+  struct dirlist *dirarray = dirstack;
 
   /* Arrange the list in array form.  */
+  ndirlist = ndirs;
   if (ndirlist >= MAX_STACK_DIRS)
     {
       dirarray = (struct dirlist *) malloc (ndirlist * sizeof (*dirarray));
@@ -310,20 +367,82 @@ read_srclines (Dwarf *dbg,
          goto out;
        }
     }
-  dirarray[0] = comp_dir_elem;
-  for (unsigned int n = 1; n < ndirlist; n++)
+
+  /* Entry zero is implicit for older versions, but explicit for 5+.  */
+  struct dirlist comp_dir_elem;
+  if (version < 5)
     {
-      dirarray[n].dir = (char *) linep;
-      uint8_t *endp = memchr (linep, '\0', lineendp - linep);
-      assert (endp != NULL);
-      dirarray[n].len = endp - linep;
-      linep = endp + 1;
+      /* First comes the list of directories.  Add the compilation
+        directory first since the index zero is used for it.  */
+      comp_dir_elem.dir = comp_dir;
+      comp_dir_elem.len = comp_dir ? strlen (comp_dir) : 0,
+      dirarray[0] = comp_dir_elem;
+      for (unsigned int n = 1; n < ndirlist; n++)
+       {
+         dirarray[n].dir = (char *) linep;
+         uint8_t *endp = memchr (linep, '\0', lineendp - linep);
+         assert (endp != NULL);
+         dirarray[n].len = endp - linep;
+         linep = endp + 1;
+       }
+      /* Skip the final NUL byte.  */
+      ++linep;
     }
-  /* Skip the final NUL byte.  */
-  ++linep;
+  else
+    {
+      Dwarf_Attribute attr;
+      attr.code = DW_AT_name;
+      attr.cu = &fake_cu;
+      for (unsigned int n = 0; n < ndirlist; n++)
+       {
+         const char *dir = NULL;
+         for (unsigned char m = 0; m < nforms; m++)
+           {
+             if (m == form_path)
+               {
+                 attr.form = forms[m];
+                 attr.valp = (void *) linep;
+                 dir = dwarf_formstring (&attr);
+               }
+
+             size_t len = __libdw_form_val_len (&fake_cu, forms[m], linep);
+             if ((size_t) (lineendp - linep) < len)
+               goto invalid_data;
+
+             linep += len;
+           }
+
+         if (dir == NULL)
+           goto invalid_data;
+
+         dirarray[n].dir = dir;
+         dirarray[n].len = strlen (dir);
+       }
+    }
+
+  /* File index zero doesn't exist for DWARF < 5.  Files are indexed
+     starting from 1.  But for DWARF5 they are indexed starting from
+     zero, but the default index is still 1.  In both cases the
+     "first" file is special and refers to the main compile unit file,
+     equal to the DW_AT_name of the DW_TAG_compile_unit.  */
+  struct filelist null_file =
+    {
+      .info =
+      {
+       .name = "???",
+       .mtime = 0,
+       .length = 0
+      },
+      .next = NULL
+    };
+  struct filelist *filelist = &null_file;
+  nfilelist = 1;
 
   /* Allocate memory for a new file.  For the first MAX_STACK_FILES
-     entries just return a slot in the preallocated stack array.  */
+     entries just return a slot in the preallocated stack array.
+     This is slightly complicated because in DWARF < 5 new files could
+     be defined with DW_LNE_define_file after the normal file list was
+     read.  */
   struct filelist flstack[MAX_STACK_FILES];
 #define NEW_FILE() ({                                                  \
   struct filelist *fl = (nfilelist < MAX_STACK_FILES                   \
@@ -337,69 +456,176 @@ read_srclines (Dwarf *dbg,
   fl; })
 
   /* Now read the files.  */
-  nfilelist = 1;
-
-  if (unlikely (linep >= lineendp))
-    goto invalid_data;
-  while (*linep != 0)
+  if (version < 5)
     {
-      struct filelist *new_file = NEW_FILE ();
-
-      /* First comes the file name.  */
-      char *fname = (char *) linep;
-      uint8_t *endp = memchr (fname, '\0', lineendp - linep);
-      if (endp == NULL)
-       goto invalid_data;
-      size_t fnamelen = endp - (uint8_t *) fname;
-      linep = endp + 1;
-
-      /* Then the index.  */
-      Dwarf_Word diridx;
       if (unlikely (linep >= lineendp))
        goto invalid_data;
-      get_uleb128 (diridx, linep, lineendp);
-      if (unlikely (diridx >= ndirlist))
+      while (*linep != 0)
        {
-         __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
-         goto out;
-       }
+         struct filelist *new_file = NEW_FILE ();
 
-      if (*fname == '/')
-       /* It's an absolute path.  */
-       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;
+         /* First comes the file name.  */
+         char *fname = (char *) linep;
+         uint8_t *endp = memchr (fname, '\0', lineendp - linep);
+         if (endp == NULL)
+           goto invalid_data;
+         size_t fnamelen = endp - (uint8_t *) fname;
+         linep = endp + 1;
 
-         if (dirarray[diridx].dir != NULL)
+         /* Then the index.  */
+         Dwarf_Word diridx;
+         if (unlikely (linep >= lineendp))
+           goto invalid_data;
+         get_uleb128 (diridx, linep, lineendp);
+         if (unlikely (diridx >= ndirlist))
            {
-             /* This value could be NULL in case the DW_AT_comp_dir
-                was not present.  We cannot do much in this case.
-                The easiest thing is to convert the path in an
-                absolute path.  */
-             cp = stpcpy (cp, dirarray[diridx].dir);
+             __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
+             goto out;
            }
-         *cp++ = '/';
-         strcpy (cp, fname);
-         assert (strlen (new_file->info.name)
-                 < dirarray[diridx].len + 1 + fnamelen + 1);
+
+         if (*fname == '/')
+           /* It's an absolute path.  */
+           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.
+                    The easiest thing is to convert the path in an
+                    absolute path.  */
+                 cp = stpcpy (cp, dirarray[diridx].dir);
+               }
+             *cp++ = '/';
+             strcpy (cp, fname);
+             assert (strlen (new_file->info.name)
+                     < dirarray[diridx].len + 1 + fnamelen + 1);
+           }
+
+         /* Next comes the modification time.  */
+         if (unlikely (linep >= lineendp))
+           goto invalid_data;
+         get_uleb128 (new_file->info.mtime, linep, lineendp);
+
+         /* Finally the length of the file.  */
+         if (unlikely (linep >= lineendp))
+           goto invalid_data;
+         get_uleb128 (new_file->info.length, linep, lineendp);
+       }
+      /* Skip the final NUL byte.  */
+      ++linep;
+    }
+  else
+    {
+      if ((size_t) (lineendp - linep) < 1)
+       goto invalid_data;
+      nforms = *linep++;
+      form_path = form_idx = -1;
+      for (int i = 0; i < nforms; 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);
+
+         if (! libdw_valid_user_form (form))
+           goto invalid_data;
+
+         forms[i] = form;
+         if (desc == DW_LNCT_path)
+           form_path = i;
+         else if (desc == DW_LNCT_directory_index)
+           form_idx = i;
        }
 
-      /* Next comes the modification time.  */
-      if (unlikely (linep >= lineendp))
+      if (nforms > 0 && (form_path == (unsigned char) -1
+                        || form_idx == (unsigned char) -1))
        goto invalid_data;
-      get_uleb128 (new_file->info.mtime, linep, lineendp);
 
-      /* Finally the length of the file.  */
-      if (unlikely (linep >= lineendp))
+      size_t nfiles;
+      get_uleb128 (nfiles, linep, lineendp);
+
+      if (nforms == 0 && nfiles != 0)
        goto invalid_data;
-      get_uleb128 (new_file->info.length, linep, lineendp);
+
+      Dwarf_Attribute attr;
+      attr.cu = &fake_cu;
+      for (unsigned int n = 0; n < nfiles; n++)
+       {
+         const char *fname = NULL;
+         Dwarf_Word diridx = -1;
+         for (unsigned char m = 0; m < nforms; m++)
+           {
+             if (m == form_path)
+               {
+                 attr.code = DW_AT_name;
+                 attr.form = forms[m];
+                 attr.valp = (void *) linep;
+                 fname = dwarf_formstring (&attr);
+               }
+             else if (m == form_idx)
+               {
+                 attr.code = DW_AT_decl_file; /* Close enough.  */
+                 attr.form = forms[m];
+                 attr.valp = (void *) linep;
+                 dwarf_formudata (&attr, &diridx);
+               }
+
+             size_t len = __libdw_form_val_len (&fake_cu, forms[m], linep);
+             if ((size_t) (lineendp - linep) < len)
+               goto invalid_data;
+
+             linep += len;
+           }
+
+         if (fname == NULL || diridx == (Dwarf_Word) -1)
+           goto invalid_data;
+
+         size_t fnamelen = strlen (fname);
+
+         if (unlikely (diridx >= ndirlist))
+           {
+             __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
+             goto out;
+           }
+
+         /* Yes, weird.  Looks like an off-by-one in the spec.  */
+         struct filelist *new_file = n == 0 ? &null_file : NEW_FILE ();
+
+         /* We follow the same rules as above for DWARF < 5, even
+            though the standard doesn't explicitly mention absolute
+            paths and ignoring the dir index.  */
+         if (*fname == '/')
+           /* It's an absolute path.  */
+           new_file->info.name = (char *) fname;
+         else
+           {
+             new_file->info.name = libdw_alloc (dbg, char, 1,
+                                                dirarray[diridx].len + 1
+                                                + fnamelen + 1);
+             char *cp = new_file->info.name;
+
+             /* In the DWARF >= 5 case, dir can never be NULL.  */
+             cp = stpcpy (cp, dirarray[diridx].dir);
+             *cp++ = '/';
+             strcpy (cp, fname);
+             assert (strlen (new_file->info.name)
+                     < dirarray[diridx].len + 1 + fnamelen + 1);
+           }
+
+         /* For now we just ignore the modification time and file length.  */
+         new_file->info.mtime = 0;
+         new_file->info.length = 0;
+       }
     }
-  /* Skip the final NUL byte.  */
-  ++linep;
 
   /* Consistency check.  */
   if (unlikely (linep != header_start + header_length))
@@ -408,6 +634,9 @@ read_srclines (Dwarf *dbg,
       goto out;
     }
 
+  /* 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;
 
   /* Apply the "operation advance" from a special opcode or
index 4de0f6c3be669c5674874ebfac97bba9803426fd..751206daa8f986a42aedc047c150926d8e729ce1 100644 (file)
@@ -493,6 +493,44 @@ libdw_macro_nforms (Dwarf_Macro *macro)
   return macro->table->table[macro->table->opcodes[macro->opcode - 1]].nforms;
 }
 
+/* Returns true for any allowed FORM in the opcode_operands_table as
+   mentioned in the DWARF5 spec (6.3.1 Macro Information Header).
+   Or those mentioned in DWARF5 spec (6.2.4.2 Vendor-defined Content
+   Descriptions) for the directory/file table (plus DW_FORM_strp_sup).  */
+static inline bool
+libdw_valid_user_form (int form)
+{
+  switch (form)
+    {
+      case DW_FORM_block:
+      case DW_FORM_block1:
+      case DW_FORM_block2:
+      case DW_FORM_block4:
+      case DW_FORM_data1:
+      case DW_FORM_data2:
+      case DW_FORM_data4:
+      case DW_FORM_data8:
+      case DW_FORM_data16:
+      case DW_FORM_flag:
+      case DW_FORM_line_strp:
+      case DW_FORM_sdata:
+      case DW_FORM_sec_offset:
+      case DW_FORM_string:
+      case DW_FORM_strp:
+      case DW_FORM_strp_sup:
+      case DW_FORM_strx:
+      case DW_FORM_strx1:
+      case DW_FORM_strx2:
+      case DW_FORM_strx3:
+      case DW_FORM_strx4:
+      case DW_FORM_udata:
+       return true;
+      default:
+       return false;
+    }
+}
+
+
 /* We have to include the file at this point because the inline
    functions access internals of the Dwarf structure.  */
 #include "memory-access.h"
index 14159d80c66e23a80c9fbd73f082f64df5c6c2f5..8a098b4cf195f4ec2508db7984217301e5f14786 100644 (file)
@@ -1,3 +1,13 @@
+2018-05-05  Mark Wielaard  <mark@klomp.org>
+
+       * testfile-dwarf-45.source: New file.
+       * testfile-dwarf-4.bz2: New test file.
+       * testfile-dwarf-5.bz2: Likewise.
+       * run-readelf-line.sh: Add testcases for testfile-dwarf-4 and
+       testfile-dwarf-5.
+       * Makefile (EXTRA_DIST): Add testfile-dwarf-45.source,
+       testfile-dwarf-4.bz2 and testfile-dwarf-5.bz2.
+
 2018-04-19  Andreas Schwab  <schwab@suse.de>
 
        * hello_riscv64.ko.bz2: New file.
index 6b1356e9d4bca2e97c2891a43415d3859d9d08fb..2f9ae2377c638b98924ebe006e9ba54bc735aa9e 100644 (file)
@@ -231,6 +231,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
             run-readelf-loc.sh testfileloc.bz2 \
             run-readelf-aranges.sh run-readelf-line.sh testfilefoobarbaz.bz2 \
             testfile-ppc64-min-instr.bz2 \
+            testfile-dwarf-45.source \
+            testfile-dwarf-4.bz2 testfile-dwarf-5.bz2 \
             run-readelf-z.sh \
             run-readelf-dwz-multi.sh libtestfile_multi_shared.so.bz2 \
             testfile_multi.dwz.bz2 testfile_multi_main.bz2 \
index f93bf47d147f6afe815e29c890c780f292c05c96..b08752eead4fc0815432f5298167fb11a3ad8c62 100755 (executable)
@@ -345,4 +345,167 @@ DWARF section [29] '.debug_line' at offset 0xdf6:
      8:3   S   *    0   0  0 0x00000000100005f7 <main+0x53>
 
 EOF
+
+# Two tests for the same code but encoded using DWARF4 or DWARF5.
+# Output is identical except for the section offset and CU numbers.
+# See tests/testfile-dwarf-45.source.
+
+testfiles testfile-dwarf-4 testfile-dwarf-5
+
+testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=decodedline testfile-dwarf-4 << \EOF
+
+DWARF section [29] '.debug_line' at offset 0x1734:
+
+ CU [b] hello.c
+  line:col SBPE* disc isa op address (Statement Block Prologue Epilogue *End)
+  /var/tmp/hello/hello.c (mtime: 0, length: 0)
+    21:0   S        0   0  0 0x0000000000400510 <foo>
+    22:1   S        0   0  0 0x0000000000400510 <foo>
+    22:3            0   0  0 0x0000000000400510 <foo>
+    25:6            0   0  0 0x0000000000400514 <foo+0x4>
+    25:34  S        0   0  0 0x000000000040051a <foo+0xa>
+    25:3            0   0  0 0x000000000040051a <foo+0xa>
+    26:34           0   0  0 0x000000000040051e <foo+0xe>
+    25:1            1   0  0 0x0000000000400528 <foo+0x18>
+  /var/tmp/hello/hello.h (mtime: 0, length: 0)
+     7:18  S        0   0  0 0x000000000040052b <foo+0x1b>
+     9:3   S        0   0  0 0x000000000040052b <foo+0x1b>
+     9:3            0   0  0 0x000000000040052b <foo+0x1b>
+    10:6   S        0   0  0 0x000000000040052f <foo+0x1f>
+    10:5            0   0  0 0x000000000040052f <foo+0x1f>
+    12:7   S        0   0  0 0x0000000000400531 <foo+0x21>
+  /var/tmp/hello/hello.c (mtime: 0, length: 0)
+    10:3   S        0   0  0 0x0000000000400531 <foo+0x21>
+    12:3   S        0   0  0 0x0000000000400531 <foo+0x21>
+    12:3            0   0  0 0x0000000000400531 <foo+0x21>
+    13:6   S        0   0  0 0x0000000000400535 <foo+0x25>
+    13:5            0   0  0 0x0000000000400535 <foo+0x25>
+    15:7   S        0   0  0 0x0000000000400539 <foo+0x29>
+    22:3   S        0   0  0 0x0000000000400539 <foo+0x29>
+    22:3            0   0  0 0x0000000000400539 <foo+0x29>
+    23:6   S        0   0  0 0x000000000040053d <foo+0x2d>
+    23:5            0   0  0 0x000000000040053d <foo+0x2d>
+     9:12  S        0   0  0 0x0000000000400550 <baz>
+    10:1   S        0   0  0 0x0000000000400550 <baz>
+    12:3   S        0   0  0 0x0000000000400550 <baz>
+    12:3            0   0  0 0x0000000000400550 <baz>
+    13:9            0   0  0 0x0000000000400556 <baz+0x6>
+    15:7   S        0   0  0 0x000000000040055f <baz+0xf>
+    15:3            0   0  0 0x000000000040055f <baz+0xf>
+    15:7       *    0   0  0 0x0000000000400560 <baz+0x10>
+
+ CU [21c] world.c
+  line:col SBPE* disc isa op address (Statement Block Prologue Epilogue *End)
+  /var/tmp/hello/world.c (mtime: 0, length: 0)
+    15:0   S        0   0  0 0x0000000000400410 <main>
+    16:1   S        0   0  0 0x0000000000400410 <main>
+    17:3   S        0   0  0 0x0000000000400410 <main>
+    15:3            0   0  0 0x0000000000400410 <main>
+    17:1            0   0  0 0x0000000000400419 <main+0x9>
+    18:6   S        0   0  0 0x000000000040041e <main+0xe>
+    18:5            0   0  0 0x000000000040041e <main+0xe>
+    22:7   S        0   0  0 0x0000000000400421 <main+0x11>
+    22:3   S   *    0   0  0 0x000000000040042f <main+0x1f>
+
+     6:0   S        0   0  0 0x0000000000400570 <calc>
+     7:1   S        0   0  0 0x0000000000400570 <calc>
+     7:3            0   0  0 0x0000000000400570 <calc>
+     7:6            1   0  0 0x0000000000400575 <calc+0x5>
+     7:24           0   0  0 0x0000000000400578 <calc+0x8>
+    10:17  S        0   0  0 0x000000000040057d <calc+0xd>
+    10:3            0   0  0 0x000000000040057d <calc+0xd>
+  /var/tmp/hello/hello.h (mtime: 0, length: 0)
+    10:10           0   0  0 0x0000000000400583 <calc+0x13>
+  /var/tmp/hello/world.c (mtime: 0, length: 0)
+    10:7            0   0  0 0x0000000000400585 <calc+0x15>
+  /var/tmp/hello/hello.h (mtime: 0, length: 0)
+     7:10  S        0   0  0 0x0000000000400588 <calc+0x18>
+     9:3   S        0   0  0 0x0000000000400588 <calc+0x18>
+    10:3            0   0  0 0x0000000000400588 <calc+0x18>
+    12:7   S        0   0  0 0x000000000040058f <calc+0x1f>
+    12:3            0   0  0 0x000000000040058f <calc+0x1f>
+  /var/tmp/hello/world.c (mtime: 0, length: 0)
+    11:10           0   0  0 0x0000000000400598 <calc+0x28>
+    11:1       *    0   0  0 0x000000000040059a <calc+0x2a>
+
+EOF
+
+testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=decodedline testfile-dwarf-5 << \EOF
+
+DWARF section [29] '.debug_line' at offset 0x171f:
+
+ CU [c] hello.c
+  line:col SBPE* disc isa op address (Statement Block Prologue Epilogue *End)
+  /var/tmp/hello/hello.c (mtime: 0, length: 0)
+    21:0   S        0   0  0 0x0000000000400510 <foo>
+    22:1   S        0   0  0 0x0000000000400510 <foo>
+    22:3            0   0  0 0x0000000000400510 <foo>
+    25:6            0   0  0 0x0000000000400514 <foo+0x4>
+    25:34  S        0   0  0 0x000000000040051a <foo+0xa>
+    25:3            0   0  0 0x000000000040051a <foo+0xa>
+    26:34           0   0  0 0x000000000040051e <foo+0xe>
+    25:1            1   0  0 0x0000000000400528 <foo+0x18>
+  /var/tmp/hello/hello.h (mtime: 0, length: 0)
+     7:18  S        0   0  0 0x000000000040052b <foo+0x1b>
+     9:3   S        0   0  0 0x000000000040052b <foo+0x1b>
+     9:3            0   0  0 0x000000000040052b <foo+0x1b>
+    10:6   S        0   0  0 0x000000000040052f <foo+0x1f>
+    10:5            0   0  0 0x000000000040052f <foo+0x1f>
+    12:7   S        0   0  0 0x0000000000400531 <foo+0x21>
+  /var/tmp/hello/hello.c (mtime: 0, length: 0)
+    10:3   S        0   0  0 0x0000000000400531 <foo+0x21>
+    12:3   S        0   0  0 0x0000000000400531 <foo+0x21>
+    12:3            0   0  0 0x0000000000400531 <foo+0x21>
+    13:6   S        0   0  0 0x0000000000400535 <foo+0x25>
+    13:5            0   0  0 0x0000000000400535 <foo+0x25>
+    15:7   S        0   0  0 0x0000000000400539 <foo+0x29>
+    22:3   S        0   0  0 0x0000000000400539 <foo+0x29>
+    22:3            0   0  0 0x0000000000400539 <foo+0x29>
+    23:6   S        0   0  0 0x000000000040053d <foo+0x2d>
+    23:5            0   0  0 0x000000000040053d <foo+0x2d>
+     9:12  S        0   0  0 0x0000000000400550 <baz>
+    10:1   S        0   0  0 0x0000000000400550 <baz>
+    12:3   S        0   0  0 0x0000000000400550 <baz>
+    12:3            0   0  0 0x0000000000400550 <baz>
+    13:9            0   0  0 0x0000000000400556 <baz+0x6>
+    15:7   S        0   0  0 0x000000000040055f <baz+0xf>
+    15:3            0   0  0 0x000000000040055f <baz+0xf>
+    15:7       *    0   0  0 0x0000000000400560 <baz+0x10>
+
+ CU [218] world.c
+  line:col SBPE* disc isa op address (Statement Block Prologue Epilogue *End)
+  /var/tmp/hello/world.c (mtime: 0, length: 0)
+    15:0   S        0   0  0 0x0000000000400410 <main>
+    16:1   S        0   0  0 0x0000000000400410 <main>
+    17:3   S        0   0  0 0x0000000000400410 <main>
+    15:3            0   0  0 0x0000000000400410 <main>
+    17:1            0   0  0 0x0000000000400419 <main+0x9>
+    18:6   S        0   0  0 0x000000000040041e <main+0xe>
+    18:5            0   0  0 0x000000000040041e <main+0xe>
+    22:7   S        0   0  0 0x0000000000400421 <main+0x11>
+    22:3   S   *    0   0  0 0x000000000040042f <main+0x1f>
+
+     6:0   S        0   0  0 0x0000000000400570 <calc>
+     7:1   S        0   0  0 0x0000000000400570 <calc>
+     7:3            0   0  0 0x0000000000400570 <calc>
+     7:6            1   0  0 0x0000000000400575 <calc+0x5>
+     7:24           0   0  0 0x0000000000400578 <calc+0x8>
+    10:17  S        0   0  0 0x000000000040057d <calc+0xd>
+    10:3            0   0  0 0x000000000040057d <calc+0xd>
+  /var/tmp/hello/hello.h (mtime: 0, length: 0)
+    10:10           0   0  0 0x0000000000400583 <calc+0x13>
+  /var/tmp/hello/world.c (mtime: 0, length: 0)
+    10:7            0   0  0 0x0000000000400585 <calc+0x15>
+  /var/tmp/hello/hello.h (mtime: 0, length: 0)
+     7:10  S        0   0  0 0x0000000000400588 <calc+0x18>
+     9:3   S        0   0  0 0x0000000000400588 <calc+0x18>
+    10:3            0   0  0 0x0000000000400588 <calc+0x18>
+    12:7   S        0   0  0 0x000000000040058f <calc+0x1f>
+    12:3            0   0  0 0x000000000040058f <calc+0x1f>
+  /var/tmp/hello/world.c (mtime: 0, length: 0)
+    11:10           0   0  0 0x0000000000400598 <calc+0x28>
+    11:1       *    0   0  0 0x000000000040059a <calc+0x2a>
+
+EOF
+
 exit 0
diff --git a/tests/testfile-dwarf-4.bz2 b/tests/testfile-dwarf-4.bz2
new file mode 100755 (executable)
index 0000000..fd3aaea
Binary files /dev/null and b/tests/testfile-dwarf-4.bz2 differ
diff --git a/tests/testfile-dwarf-45.source b/tests/testfile-dwarf-45.source
new file mode 100644 (file)
index 0000000..c9c4446
--- /dev/null
@@ -0,0 +1,81 @@
+# Nonsensical program used to generate an example DWARF4 and DWARF5 file.
+# The generated code is the same, but the DWARF representation is different.
+
+# = hello.h =
+
+extern int m;
+extern int baz (int x);
+
+static inline int
+frob (int a, int b)
+{
+  int c = a;
+
+  if (a > b)
+    c -= b;
+
+  return baz (c);
+}
+
+# = hello.c =
+
+#include <stddef.h>
+#include "hello.h"
+
+extern int main (int, char **);
+int m = 2;
+
+wchar_t foo (wchar_t);
+int baz (int x)
+{
+  int r = x;
+
+  if (x > m)
+    r -= m;
+
+  r = foo (r);
+  return r;
+}
+
+wchar_t
+foo (wchar_t f)
+{
+  if (f < 0)
+    return main (f, NULL);
+
+  return f > 0 ? frob (f - 1, m) : 0;
+}
+
+# = world.c =
+
+#include "hello.h"
+#include <stdlib.h>
+
+int
+calc (const char *word)
+{
+  if (word == 0 || word[0] == '\0')
+    return 0;
+
+  return frob (word[0], m + 42);
+}
+
+int
+main (int argc, const char **argv)
+{
+  const char *n;
+  if (argc > 1)
+    n = argv[0];
+  else
+    n = "world";
+
+  exit (calc (n));
+}
+
+$ gcc -gdwarf-4 -gno-as-loc-support -gno-variable-location-views -O2 -c world.c
+$ gcc -gdwarf-4 -gno-as-loc-support -gno-variable-location-views -O2 -c hello.c
+$ gcc -o testfile-dwarf-4 hello.o world.o
+
+$ gcc -gdwarf-5 -gno-as-loc-support -gno-variable-location-views -O2 -c world.c
+$ gcc -gdwarf-5 -gno-as-loc-support -gno-variable-location-views -O2 -c hello.c
+$ gcc -o testfile-dwarf-5 hello.o world.o
diff --git a/tests/testfile-dwarf-5.bz2 b/tests/testfile-dwarf-5.bz2
new file mode 100755 (executable)
index 0000000..689fa4f
Binary files /dev/null and b/tests/testfile-dwarf-5.bz2 differ