]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdw: Handle .debug_loclists in dwarf_getlocation.
authorMark Wielaard <mark@klomp.org>
Sat, 7 Apr 2018 21:48:27 +0000 (23:48 +0200)
committerMark Wielaard <mark@klomp.org>
Tue, 29 May 2018 22:16:15 +0000 (00:16 +0200)
Handle all new DW_LLE opcodes in .debug_loclists in dwarf_getlocation.
__libdw_read_begin_end_pair_inc now also handles a default location
(which is simply the range [0,-1]). Since expression blocks can now
also come from the .debug_loclists section add a new fake_loclists_cu
necessary for checking bounds while parsing expression blocks.

Adapt varlocs test to handle debug-only files.
Test testfileranges5.debug and testfilesplitranges5.debug with it.

Signed-off-by: Mark Wielaard <mark@klomp.org>
13 files changed:
libdw/ChangeLog
libdw/dwarf_begin_elf.c
libdw/dwarf_end.c
libdw/dwarf_getlocation.c
libdw/dwarf_getlocation_attr.c
libdw/dwarf_ranges.c
libdw/libdwP.h
libdw/libdw_findcu.c
src/ChangeLog
src/readelf.c
tests/ChangeLog
tests/run-varlocs.sh
tests/varlocs.c

index 0db49bf8eee11f29562f489a7d049b467b5e3d5c..22712f18a1f9b05d241148fe7f1ddc498be41d7b 100644 (file)
@@ -1,3 +1,20 @@
+2018-04-07  Mark Wielaard  <mark@klomp.org>
+
+       * libdwP.h (struct Dwarf_CU): Add locs_base.
+       (__libdw_cu_locs_base): New static inline function.
+       * libdw_findcu.c (__libdw_intern_next_unit): Initialize locs_base.
+       * dwarf_begin_elf.c (valid_p): Create fake_loclists_cu if necessary.
+       * dwarf_end.c (dwarf_end): Clean up fake_loclists_cu.
+       * dwarf_getlocation.c (initial_offset): Handle .debug_loclists.
+       (getlocations_addr): Likewise.
+       (dwarf_getlocation_addr): Likewise.
+       * dwarf_getlocation_attr.c (attr_form_cu): Use fake_loclists_cu for
+       DWARF5.
+       (initial_offset): Handle DW_FORM_loclistx.
+       * dwarf_ranges.c (__libdw_read_begin_end_pair_inc): Handle
+       .debug_loclists.
+       * libdwP.h (struct Dwarf): Add fake_loclists_cu.
+
 2018-04-12  Mark Wielaard  <mark@klomp.org>
 
        * dwarf.h: Add DWARF5 location list entry DW_LLE encodings.
index af5096fb39fc73e810694381207e685385450cc0..513af2b1c9e367cf3e8cd5dd9127d64f9cf9b082 100644 (file)
@@ -226,6 +226,9 @@ valid_p (Dwarf *result)
       result = NULL;
     }
 
+  /* For dwarf_location_attr () we need a "fake" CU to indicate
+     where the "fake" attribute data comes from.  This is a block
+     inside the .debug_loc or .debug_loclists section.  */
   if (result != NULL && result->sectiondata[IDX_debug_loc] != NULL)
     {
       result->fake_loc_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
@@ -248,6 +251,29 @@ valid_p (Dwarf *result)
        }
     }
 
+  if (result != NULL && result->sectiondata[IDX_debug_loclists] != NULL)
+    {
+      result->fake_loclists_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
+      if (unlikely (result->fake_loclists_cu == NULL))
+       {
+         Dwarf_Sig8_Hash_free (&result->sig8_hash);
+         __libdw_seterrno (DWARF_E_NOMEM);
+         free (result->fake_loc_cu);
+         free (result);
+         result = NULL;
+       }
+      else
+       {
+         result->fake_loclists_cu->sec_idx = IDX_debug_loclists;
+         result->fake_loclists_cu->dbg = result;
+         result->fake_loclists_cu->startp
+           = result->sectiondata[IDX_debug_loclists]->d_buf;
+         result->fake_loclists_cu->endp
+           = (result->sectiondata[IDX_debug_loclists]->d_buf
+              + result->sectiondata[IDX_debug_loclists]->d_size);
+       }
+    }
+
   /* For DW_OP_constx/GNU_const_index and DW_OP_addrx/GNU_addr_index
      the dwarf_location_attr () will need a "fake" address CU to
      indicate where the attribute data comes from.  This is a just
@@ -260,6 +286,7 @@ valid_p (Dwarf *result)
          Dwarf_Sig8_Hash_free (&result->sig8_hash);
          __libdw_seterrno (DWARF_E_NOMEM);
          free (result->fake_loc_cu);
+         free (result->fake_loclists_cu);
          free (result);
          result = NULL;
        }
index 19546741e7ea3f4f9ead0d8a632b280ad76fc846..23a50a0b216903be2baf1cff2953d6db066c47f4 100644 (file)
@@ -113,6 +113,11 @@ dwarf_end (Dwarf *dwarf)
          cu_free (dwarf->fake_loc_cu);
          free (dwarf->fake_loc_cu);
        }
+      if (dwarf->fake_loclists_cu != NULL)
+       {
+         cu_free (dwarf->fake_loclists_cu);
+         free (dwarf->fake_loclists_cu);
+       }
       if (dwarf->fake_addr_cu != NULL)
        {
          cu_free (dwarf->fake_addr_cu);
index d4b8effea08036ce8a8ac9761f6b62a456529a87..d293e75d60238cc4dfbe53abd03e7c7cadd6585a 100644 (file)
@@ -696,13 +696,77 @@ __libdw_cu_base_address (Dwarf_CU *cu)
 static int
 initial_offset (Dwarf_Attribute *attr, ptrdiff_t *offset)
 {
-  size_t secidx = IDX_debug_loc;
+  size_t secidx = (attr->cu->version < 5
+                  ? IDX_debug_loc : IDX_debug_loclists);
 
   Dwarf_Word start_offset;
-  if (__libdw_formptr (attr, secidx,
-                      DWARF_E_NO_DEBUG_LOC,
-                      NULL, &start_offset) == NULL)
-    return -1;
+  if (attr->form == DW_FORM_loclistx)
+    {
+      Dwarf_Word idx;
+      Dwarf_CU *cu = attr->cu;
+      const unsigned char *datap = attr->valp;
+      const unsigned char *endp = cu->endp;
+      if (datap >= endp)
+       {
+         __libdw_seterrno (DWARF_E_INVALID_DWARF);
+         return -1;
+       }
+      get_uleb128 (idx, datap, endp);
+
+      Elf_Data *data = cu->dbg->sectiondata[secidx];
+      if (data == NULL && cu->unit_type == DW_UT_split_compile)
+       {
+         cu = __libdw_find_split_unit (cu);
+         if (cu != NULL)
+           data = cu->dbg->sectiondata[secidx];
+       }
+
+      if (data == NULL)
+       {
+         __libdw_seterrno (secidx == IDX_debug_loc
+                            ? DWARF_E_NO_DEBUG_LOC
+                            : DWARF_E_NO_DEBUG_LOCLISTS);
+         return -1;
+       }
+
+      Dwarf_Off loc_base_off = __libdw_cu_locs_base (cu);
+
+      /* The section should at least contain room for one offset.  */
+      size_t sec_size = cu->dbg->sectiondata[secidx]->d_size;
+      size_t offset_size = cu->offset_size;
+      if (offset_size > sec_size)
+       {
+       invalid_offset:
+         __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+         return -1;
+       }
+
+      /* And the base offset should be at least inside the section.  */
+      if (loc_base_off > (sec_size - offset_size))
+       goto invalid_offset;
+
+      size_t max_idx = (sec_size - offset_size - loc_base_off) / offset_size;
+      if (idx > max_idx)
+       goto invalid_offset;
+
+      datap = (cu->dbg->sectiondata[secidx]->d_buf
+              + loc_base_off + (idx * offset_size));
+      if (offset_size == 4)
+       start_offset = read_4ubyte_unaligned (cu->dbg, datap);
+      else
+       start_offset = read_8ubyte_unaligned (cu->dbg, datap);
+
+      start_offset += loc_base_off;
+    }
+  else
+    {
+      if (__libdw_formptr (attr, secidx,
+                          (secidx == IDX_debug_loc
+                           ? DWARF_E_NO_DEBUG_LOC
+                           : DWARF_E_NO_DEBUG_LOCLISTS),
+                           NULL, &start_offset) == NULL)
+       return -1;
+    }
 
   *offset = start_offset;
   return 0;
@@ -716,7 +780,7 @@ getlocations_addr (Dwarf_Attribute *attr, ptrdiff_t offset,
 {
   Dwarf_CU *cu = attr->cu;
   Dwarf *dbg = cu->dbg;
-  size_t secidx = IDX_debug_loc;
+  size_t secidx = cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists;
   const unsigned char *readp = locs->d_buf + offset;
   const unsigned char *readendp = locs->d_buf + locs->d_size;
 
@@ -741,13 +805,22 @@ getlocations_addr (Dwarf_Attribute *attr, ptrdiff_t offset,
 
   /* We have a location expression.  */
   Dwarf_Block block;
-  if (readendp - readp < 2)
+  if (secidx == IDX_debug_loc)
     {
-    invalid:
-      __libdw_seterrno (DWARF_E_INVALID_DWARF);
-      return -1;
+      if (readendp - readp < 2)
+       {
+       invalid:
+         __libdw_seterrno (DWARF_E_INVALID_DWARF);
+         return -1;
+       }
+      block.length = read_2ubyte_unaligned_inc (dbg, readp);
+    }
+  else
+    {
+      if (readendp - readp < 1)
+       goto invalid;
+      get_uleb128 (block.length, readp, readendp);
     }
-  block.length = read_2ubyte_unaligned_inc (dbg, readp);
   block.data = (unsigned char *) readp;
   if (readendp - readp < (ptrdiff_t) block.length)
     goto invalid;
@@ -815,7 +888,7 @@ dwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address,
   if (initial_offset (attr, &off) != 0)
     return -1;
 
-  size_t secidx = IDX_debug_loc;
+  size_t secidx = attr->cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists;
   const Elf_Data *d = attr->cu->dbg->sectiondata[secidx];
 
   while (got < maxlocs
@@ -896,7 +969,7 @@ dwarf_getlocations (Dwarf_Attribute *attr, ptrdiff_t offset, Dwarf_Addr *basep,
        return -1;
     }
 
-  size_t secidx = IDX_debug_loc;
+  size_t secidx = attr->cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists;
   const Elf_Data *d = attr->cu->dbg->sectiondata[secidx];
 
   return getlocations_addr (attr, offset, basep, startp, endp,
index 9d7fd4b58c2c75f1e779e904097ea8b5623b7247..875fc5d7aa902dafe0e051a96a9a67635d28ddef 100644 (file)
@@ -38,7 +38,7 @@ attr_form_cu (Dwarf_Attribute *attr)
 {
   /* If the attribute has block/expr form the data comes from the
      .debug_info from the same cu as the attr.  Otherwise it comes from
-     the .debug_loc data section.  */
+     the .debug_loc or .debug_loclists data section.  */
   switch (attr->form)
     {
     case DW_FORM_block1:
@@ -48,7 +48,9 @@ attr_form_cu (Dwarf_Attribute *attr)
     case DW_FORM_exprloc:
       return attr->cu;
     default:
-      return attr->cu->dbg->fake_loc_cu;
+      return (attr->cu->version < 5
+             ? attr->cu->dbg->fake_loc_cu
+             : attr->cu->dbg->fake_loclists_cu);
     }
 }
 
index fa65e5c6d4ffa652858a43034b42b9eb1732390b..0f3ee6b53eb89c6f7bb019aaba7855a74d3c50ef 100644 (file)
@@ -36,6 +36,7 @@
 
 /* Read up begin/end pair and increment read pointer.
     - If it's normal range record, set up `*beginp' and `*endp' and return 0.
+    - If it's a default location, set `*beginp' (0), `*endp' (-1) and return 0.
     - If it's base address selection record, set up `*basep' and return 1.
     - If it's end of rangelist, don't set anything and return 2
     - If an error occurs, don't set anything and return -1.  */
@@ -193,6 +194,119 @@ __libdw_read_begin_end_pair_inc (Dwarf_CU *cu, int sec_index,
          *addrp = addr;
          return 0;
 
+       default:
+         goto invalid;
+       }
+    }
+  else if (sec_index == IDX_debug_loclists)
+    {
+      const unsigned char *addr = *addrp;
+      if (addrend - addr < 1)
+       goto invalid;
+
+      const char code = *addr++;
+      uint64_t begin = 0, end = 0, base = *basep, addr_idx;
+      switch (code)
+       {
+       case DW_LLE_end_of_list:
+         *addrp = addr;
+         return 2;
+
+       case DW_LLE_base_addressx:
+         if (addrend - addr < 1)
+           goto invalid;
+         get_uleb128 (addr_idx, addr, addrend);
+         if (__libdw_addrx (cu, addr_idx, &base) != 0)
+           return -1;
+
+         *basep = base;
+         *addrp = addr;
+         return 1;
+
+       case DW_LLE_startx_endx:
+         if (addrend - addr < 1)
+           goto invalid;
+         get_uleb128 (addr_idx, addr, addrend);
+         if (__libdw_addrx (cu, addr_idx, &begin) != 0)
+           return -1;
+         if (addrend - addr < 1)
+           goto invalid;
+         get_uleb128 (addr_idx, addr, addrend);
+         if (__libdw_addrx (cu, addr_idx, &end) != 0)
+           return -1;
+
+         *beginp = begin;
+         *endp = end;
+         *addrp = addr;
+         return 0;
+
+       case DW_LLE_startx_length:
+         if (addrend - addr < 1)
+           goto invalid;
+         get_uleb128 (addr_idx, addr, addrend);
+         if (__libdw_addrx (cu, addr_idx, &begin) != 0)
+           return -1;
+         if (addrend - addr < 1)
+           goto invalid;
+         get_uleb128 (end, addr, addrend);
+
+         *beginp = begin;
+         *endp = begin + end;
+         *addrp = addr;
+         return 0;
+
+       case DW_LLE_offset_pair:
+         if (addrend - addr < 1)
+           goto invalid;
+         get_uleb128 (begin, addr, addrend);
+         if (addrend - addr < 1)
+           goto invalid;
+         get_uleb128 (end, addr, addrend);
+
+         *beginp = begin + base;
+         *endp = end + base;
+         *addrp = addr;
+         return 0;
+
+       case DW_LLE_default_location:
+         *beginp = 0;
+         *endp = (Dwarf_Addr) -1;
+         *addrp = addr;
+         return 0;
+
+       case DW_LLE_base_address:
+         if (addrend - addr < width)
+           goto invalid;
+         __libdw_read_address_inc (dbg, sec_index, &addr, width, &base);
+
+         *basep = base;
+         *addrp = addr;
+         return 1;
+
+       case DW_LLE_start_end:
+         if (addrend - addr < 2 * width)
+           goto invalid;
+         __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
+         __libdw_read_address_inc (dbg, sec_index, &addr, width, &end);
+
+         *beginp = begin;
+         *endp = end;
+         *addrp = addr;
+         return 0;
+
+       case DW_LLE_start_length:
+         if (addrend - addr < width)
+           goto invalid;
+         __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
+         if (addrend - addr < 1)
+           goto invalid;
+         get_uleb128 (end, addr, addrend);
+
+         *beginp = begin;
+         *endp = begin + end;
+         *addrp = addr;
+         return 0;
+
        default:
          goto invalid;
        }
index f99ea584f3cbd9984705458f09e1ac806df7bf38..dd47009bb101b04ed549760c07176622d42db24a 100644 (file)
@@ -206,8 +206,11 @@ struct Dwarf
   struct Dwarf_CFI_s *cfi;
 
   /* Fake loc CU.  Used when synthesizing attributes for Dwarf_Ops that
-     came from a location list entry in dwarf_getlocation_attr.  */
+     came from a location list entry in dwarf_getlocation_attr.
+     Depending on version this is the .debug_loc or .debug_loclists
+     section (could be both if mixing CUs with different DWARF versions).  */
   struct Dwarf_CU *fake_loc_cu;
+  struct Dwarf_CU *fake_loclists_cu;
 
   /* Similar for addrx/constx, which will come from .debug_addr section.  */
   struct Dwarf_CU *fake_addr_cu;
@@ -365,6 +368,10 @@ struct Dwarf_CU
      __libdw_cu_ranges_base.  */
   Dwarf_Off ranges_base;
 
+  /* The start of the offset table in .debug_loclists.
+     Don't access directly, call __libdw_cu_locs_base.  */
+  Dwarf_Off locs_base;
+
   /* Memory boundaries of this CU.  */
   void *startp;
   void *endp;
@@ -1177,6 +1184,84 @@ __libdw_cu_ranges_base (Dwarf_CU *cu)
 }
 
 
+/* The start of the offset table in .debug_loclists for DWARF5.  */
+static inline Dwarf_Off
+__libdw_cu_locs_base (Dwarf_CU *cu)
+{
+  if (cu->locs_base == (Dwarf_Off) -1)
+    {
+      Dwarf_Off offset = 0;
+      Dwarf_Die cu_die = CUDIE(cu);
+      Dwarf_Attribute attr;
+      if (dwarf_attr (&cu_die, DW_AT_loclists_base, &attr) != NULL)
+       {
+         Dwarf_Word off;
+         if (dwarf_formudata (&attr, &off) == 0)
+           offset = off;
+       }
+
+      /* There wasn't an loclists_base, if the Dwarf does have a
+        .debug_loclists section, then it might be we need the
+        base after the first header. */
+      Elf_Data *data = cu->dbg->sectiondata[IDX_debug_loclists];
+      if (offset == 0 && data != NULL)
+       {
+         Dwarf *dbg = cu->dbg;
+         const unsigned char *readp = data->d_buf;
+         const unsigned char *const dataend
+           = (unsigned char *) data->d_buf + data->d_size;
+
+         uint64_t unit_length = read_4ubyte_unaligned_inc (dbg, readp);
+         unsigned int offset_size = 4;
+         if (unlikely (unit_length == 0xffffffff))
+           {
+             if (unlikely (readp > dataend - 8))
+               goto no_header;
+
+             unit_length = read_8ubyte_unaligned_inc (dbg, readp);
+             offset_size = 8;
+           }
+
+         if (readp > dataend - 8
+             || unit_length < 8
+             || unit_length > (uint64_t) (dataend - readp))
+           goto no_header;
+
+         uint16_t version = read_2ubyte_unaligned_inc (dbg, readp);
+         if (version != 5)
+           goto no_header;
+
+         uint8_t address_size = *readp++;
+         if (address_size != 4 && address_size != 8)
+           goto no_header;
+
+         uint8_t segment_size = *readp++;
+         if (segment_size != 0)
+           goto no_header;
+
+         uint32_t offset_entry_count;
+         offset_entry_count = read_4ubyte_unaligned_inc (dbg, readp);
+
+         const unsigned char *offset_array_start = readp;
+         if (offset_entry_count <= 0)
+           goto no_header;
+
+         uint64_t needed = offset_entry_count * offset_size;
+         if (unit_length - 8 < needed)
+           goto no_header;
+
+         offset = (Dwarf_Off) (offset_array_start
+                               - (unsigned char *) data->d_buf);
+       }
+
+    no_header:
+      cu->locs_base = offset;
+    }
+
+  return cu->locs_base;
+}
+
+
 /* Link skeleton and split compile units.  */
 static inline void
 __libdw_link_skel_split (Dwarf_CU *skel, Dwarf_CU *split)
index 83c2eb14de2a81d6ecc300703fba0a463ffcca9f..9d23199971375509524727e770e9c568560d7d8d 100644 (file)
@@ -122,6 +122,7 @@ __libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
   newp->addr_base = (Dwarf_Off) -1;
   newp->str_off_base = (Dwarf_Off) -1;
   newp->ranges_base = (Dwarf_Off) -1;
+  newp->locs_base = (Dwarf_Off) -1;
 
   newp->startp = data->d_buf + newp->start;
   newp->endp = data->d_buf + newp->end;
index 8e02d3c5a5a94a8dc4ba69d7a9815940e8e9da5e..b6c27432083fb35d5bcd1b6693aa5c163a8572a6 100644 (file)
@@ -1,3 +1,8 @@
+2018-04-07  Mark Wielaard  <mark@klomp.org>
+
+       * readelf.c (attr_callback): Handle DW_FORM_loclistx and
+       DW_AT_segment.
+
 2018-04-12  Mark Wielaard  <mark@klomp.org>
 
        * readelf.c (dwarf_loc_list_encoding_string): New functions.
index 153fbf5a8ef8251f76f99bce28135ddbb2b14b75..54bf22c584bab576784792e04774a834f5bceec0 100644 (file)
@@ -6779,6 +6779,7 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
 
     case DW_FORM_sec_offset:
     case DW_FORM_rnglistx:
+    case DW_FORM_loclistx:
     case DW_FORM_implicit_const:
     case DW_FORM_udata:
     case DW_FORM_sdata:
@@ -6808,7 +6809,7 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
            }
          FALLTHROUGH;
 
-       /* These cases always take a loclistptr and no constant. */
+       /* These cases always take a loclist[ptr] and no constant. */
        case DW_AT_location:
        case DW_AT_data_location:
        case DW_AT_vtable_elem_location:
@@ -6817,6 +6818,7 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
        case DW_AT_frame_base:
        case DW_AT_return_addr:
        case DW_AT_static_link:
+       case DW_AT_segment:
        case DW_AT_GNU_call_site_value:
        case DW_AT_GNU_call_site_data_value:
        case DW_AT_GNU_call_site_target:
index 6e366eb36511f30236f7dfa3bf7f40fb3f25fdda..3ed88f6dbd8f87f0fe0e48dfc9ee7b8ce1c67040 100644 (file)
@@ -1,3 +1,11 @@
+2018-04-07  Mark Wielaard  <mark@klomp.org>
+
+       * run-varlocs.sh: Run on testfileranges5.debug and
+       testsplitfileranges5.debug.
+       * varlocs.c (is_debug): New bool.
+       (print_expr): Don't fail on missing CFI for is_debug.
+       (main): Parse --debug, set is_debug.
+
 2018-04-12  Mark Wielaard  <mark@klomp.org>
 
        * run-readelf-loc.sh: Add new testcases.
index 2781fef4453c2022aa30a53dc22e0c87b640c221..8426d20db57606a32d6c2ef50aa57a4b96a707f6 100755 (executable)
@@ -124,6 +124,158 @@ module 'testfile_implicit_pointer'
     frame_base: {call_frame_cfa {bregx(7,8)}}
 EOF
 
+# Multi CU DWARF5. See run-dwarf-ranges.sh.
+testfiles testfileranges5.debug
+testrun_compare ${abs_top_builddir}/tests/varlocs --debug -e testfileranges5.debug <<\EOF
+module 'testfileranges5.debug'
+[c] CU 'hello.c'@0
+  [2a] function 'no_say'@401160
+    frame_base: {call_frame_cfa {...}}
+    [4a] parameter 'prefix'
+      [401160,401169) {reg5}
+      [401169,40116a) {entry_value(1) {reg5}, stack_value}
+      [40116a,401175) {reg5}
+      [401175,40117a) {entry_value(1) {reg5}, stack_value}
+    [59] variable 'world'
+      [401160,40117a) {addr(0x402004), stack_value}
+  [bd] function 'main'@401050
+    frame_base: {call_frame_cfa {...}}
+    [dd] parameter 'argc'
+      [401050,401062) {reg5}
+      [401062,401067) {entry_value(1) {reg5}, stack_value}
+    [ec] parameter 'argv'
+      [401050,401066) {reg4}
+      [401066,401067) {entry_value(1) {reg4}, stack_value}
+  [fb] inlined function 'subject'@401053
+    [117] parameter 'count'
+      [401053,40105f) {reg5}
+    [120] parameter 'word'
+      [401053,40105f) {reg0}
+  [168] function 'subject'@401150
+    frame_base: {call_frame_cfa {...}}
+    [183] parameter 'word'
+      [401150,401160) {reg5}
+    [18a] parameter 'count'
+      [401150,401160) {reg4}
+module 'testfileranges5.debug'
+[1ab] CU 'world.c'@401180
+  [1cd] function 'no_main'@4011d0
+    frame_base: {call_frame_cfa {...}}
+    [1ef] parameter 'argc'
+      [4011d0,4011e2) {reg5}
+      [4011e2,4011e7) {entry_value(1) {reg5}, stack_value}
+    [1fe] parameter 'argv'
+      [4011d0,4011e6) {reg4}
+      [4011e6,4011e7) {entry_value(1) {reg4}, stack_value}
+  [20d] inlined function 'no_subject'@4011d3
+    [229] parameter 'count'
+      [4011d3,4011df) {reg5}
+    [232] parameter 'word'
+      [4011d3,4011df) {reg0}
+  [28d] function 'say'@401180
+    frame_base: {call_frame_cfa {...}}
+    [2af] parameter 'prefix'
+      [401180,40118e) {reg5}
+      [40118e,40119c) {reg3}
+      [40119c,4011a7) {entry_value(1) {reg5}, stack_value}
+      [4011a7,4011b5) {reg3}
+      [4011b5,4011c0) {entry_value(1) {reg5}, stack_value}
+    [2be] variable 'world'
+      [401193,40119b) {reg0}
+      [4011a7,4011b4) {reg0}
+  [2ce] inlined function 'happy'@40119b
+    [2e6] parameter 'w'
+      [4011a7,4011b4) {reg0}
+  [2ef] inlined function 'sad'@40119b
+    [303] parameter 'c'
+      [40119b,4011a6) {reg0}
+      [4011a6,4011a7) {entry_value(1) {reg5}}
+      [4011b4,4011bf) {reg0}
+  [36b] function 'no_subject'@4011c0
+    frame_base: {call_frame_cfa {...}}
+    [386] parameter 'word'
+      [4011c0,4011d0) {reg5}
+    [38d] parameter 'count'
+      [4011c0,4011d0) {reg4}
+EOF
+
+# Multi CU Split DWARF5. See run-dwarf-ranges.sh.
+# Note that the DIE numbers change, but the actual location addresses are
+# the same as above, even though the representation is totally different.
+testfiles testfilesplitranges5.debug
+testfiles testfile-ranges-hello5.dwo testfile-ranges-world5.dwo
+testrun_compare ${abs_top_builddir}/tests/varlocs --debug -e testfilesplitranges5.debug <<\EOF
+module 'testfilesplitranges5.debug'
+[14] CU 'hello.c'
+  [1d] function 'no_say'@401160
+    frame_base: {call_frame_cfa {...}}
+    [33] parameter 'prefix'
+      [401160,401169) {reg5}
+      [401169,40116a) {entry_value(1) {reg5}, stack_value}
+      [40116a,401175) {reg5}
+      [401175,40117a) {entry_value(1) {reg5}, stack_value}
+    [3c] variable 'world'
+      [401160,40117a) {addr: 0x402004, stack_value}
+  [7e] function 'main'@401050
+    frame_base: {call_frame_cfa {...}}
+    [94] parameter 'argc'
+      [401050,401062) {reg5}
+      [401062,401067) {entry_value(1) {reg5}, stack_value}
+    [9d] parameter 'argv'
+      [401050,401066) {reg4}
+      [401066,401067) {entry_value(1) {reg4}, stack_value}
+  [a6] inlined function 'subject'@401053
+    [bb] parameter 'count'
+      [401053,40105f) {reg5}
+    [c1] parameter 'word'
+      [401053,40105f) {reg0}
+  [f6] function 'subject'@401150
+    frame_base: {call_frame_cfa {...}}
+    [10a] parameter 'word'
+      [401150,401160) {reg5}
+    [111] parameter 'count'
+      [401150,401160) {reg4}
+module 'testfilesplitranges5.debug'
+[14] CU 'world.c'
+  [1d] function 'no_main'@4011d0
+    frame_base: {call_frame_cfa {...}}
+    [35] parameter 'argc'
+      [4011d0,4011e2) {reg5}
+      [4011e2,4011e7) {entry_value(1) {reg5}, stack_value}
+    [3e] parameter 'argv'
+      [4011d0,4011e6) {reg4}
+      [4011e6,4011e7) {entry_value(1) {reg4}, stack_value}
+  [47] inlined function 'no_subject'@4011d3
+    [5c] parameter 'count'
+      [4011d3,4011df) {reg5}
+    [62] parameter 'word'
+      [4011d3,4011df) {reg0}
+  [a7] function 'say'@401180
+    frame_base: {call_frame_cfa {...}}
+    [c2] parameter 'prefix'
+      [401180,40118e) {reg5}
+      [40118e,40119c) {reg3}
+      [40119c,4011a7) {entry_value(1) {reg5}, stack_value}
+      [4011a7,4011b5) {reg3}
+      [4011b5,4011c0) {entry_value(1) {reg5}, stack_value}
+    [cb] variable 'world'
+      [401193,40119b) {reg0}
+      [4011a7,4011b4) {reg0}
+  [d5] inlined function 'happy'@40119b
+    [e3] parameter 'w'
+      [4011a7,4011b4) {reg0}
+  [e9] inlined function 'sad'@40119b
+    [f3] parameter 'c'
+      [40119b,4011a6) {reg0}
+      [4011a6,4011a7) {entry_value(1) {reg5}}
+      [4011b4,4011bf) {reg0}
+  [147] function 'no_subject'@4011c0
+    frame_base: {call_frame_cfa {...}}
+    [15b] parameter 'word'
+      [4011c0,4011d0) {reg5}
+    [162] parameter 'count'
+      [4011c0,4011d0) {reg4}
+EOF
 
 # DW_OP_addrx and DW_OP_constx testcases.
 #
index 859068d62891cc2df421165ec42e2ec83ad61708..31a1069a95ea43d1aa53c0c6d7a42a53e42e503f 100644 (file)
@@ -1,5 +1,5 @@
 /* Test program for dwarf location functions.
-   Copyright (C) 2013, 2015, 2017 Red Hat, Inc.
+   Copyright (C) 2013, 2015, 2017, 2018 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -44,6 +44,7 @@ Dwarf_CFI *cfi_eh;
 Dwarf_Addr cfi_eh_bias;
 
 bool is_ET_REL;
+bool is_debug;
 
 // Whether the current function has a DW_AT_frame_base defined.
 // Needed for DW_OP_fbreg.
@@ -257,7 +258,7 @@ print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr)
        error (EXIT_FAILURE, 0, "%s used in CFI", opname);
 
       printf ("%s ", opname);
-      if (cfi_eh == NULL && cfi_debug == NULL)
+      if (cfi_eh == NULL && cfi_debug == NULL && !is_debug)
        error (EXIT_FAILURE, 0, "DW_OP_call_frame_cfa used but no cfi found.");
 
       Dwarf_Frame *frame;
@@ -275,11 +276,11 @@ print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr)
          print_expr_block (NULL, cfa_ops, cfa_nops, 0);
          free (frame);
        }
-      else if (is_ET_REL)
+      else if (is_ET_REL || is_debug)
        {
          /* XXX In ET_REL files there might be an .eh_frame with relocations
             we don't handle (e.g. X86_64_PC32). Maybe we should?  */
-         printf ("{...}\n");
+         printf ("{...}");
        }
       else
        error (EXIT_FAILURE, 0, "dwarf_cfi_addrframe 0x%" PRIx64 ": %s",
@@ -1033,12 +1034,34 @@ main (int argc, char *argv[])
      which contains an DWARF expression (but not location lists) and
      print those.  Otherwise we process all function DIEs and print
      all DWARF expressions and location lists associated with
-     parameters and variables). */
+     parameters and variables). It must be the first argument,
+     or the second, after --debug.  */
   bool exprlocs = false;
-  if (argc > 1 && strcmp ("--exprlocs", argv[1]) == 0)
+
+  /* With --debug we ignore not being able to find .eh_frame.
+     It must come as first argument.  */
+  is_debug = false;
+  if (argc > 1)
+    {
+      if (strcmp ("--exprlocs", argv[1]) == 0)
+       {
+         exprlocs = true;
+         argv[1] = "";
+       }
+      else if (strcmp ("--debug", argv[1]) == 0)
+       {
+         is_debug = true;
+         argv[1] = "";
+       }
+    }
+
+  if (argc > 2)
     {
-      exprlocs = true;
-      argv[1] = "";
+      if (strcmp ("--exprlocs", argv[2]) == 0)
+       {
+         exprlocs = true;
+         argv[2] = "";
+       }
     }
 
   int remaining;