]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdw: Restructure address range reading for .debug_loc and .debug_ranges.
authorMark Wielaard <mark@klomp.org>
Mon, 2 Apr 2018 21:08:40 +0000 (23:08 +0200)
committerMark Wielaard <mark@klomp.org>
Fri, 13 Apr 2018 11:37:16 +0000 (13:37 +0200)
This caches the CU base address, makes error checking slight more relaxed
and restructures the code so it will be easier to add different forms
of ranges. Adds a new test for the new CU base address code.

Signed-off-by: Mark Wielaard <mark@klomp.org>
libdw/ChangeLog
libdw/dwarf_formudata.c
libdw/dwarf_getlocation.c
libdw/dwarf_ranges.c
libdw/libdwP.h
libdw/libdw_findcu.c
tests/ChangeLog
tests/Makefile.am
tests/run-dwarf-ranges.sh
tests/testfileranges4.debug.bz2 [new file with mode: 0755]

index ad62771212c517cde8405766f829dea265f20339..276f3a4e9095040f81c35d480dae225b9b100400 100644 (file)
@@ -1,3 +1,33 @@
+2018-04-03  Mark Wielaard  <mark@klomp.org>
+
+       * dwarf_formudata.c (__libdw_formptr): Take and return const
+       unsigned char pointers.
+       * dwarf_getlocation.c (attr_base_address): Rename to...
+       (__libdw_cu_base_address): this. Take Dwarf_CU, check and set
+       base_address.
+       (initial_offset_base): Renamed to...
+       (initial_offset): this. Only provide offset.
+       (getlocations_addr): Move data size check and
+       address base addition into __libdw_read_begin_end_pair_inc. Use
+       __libdw_cu_base_address and initial_offset. Drop Elf_Data NULL
+       check (already done by initial_offset, through __libdw_formptr).
+       (dwarf_getlocations): Use __libdw_cu_base_address and initial_offset.
+       Drop Elf_Data NULL check.
+       * dwarf_ranges.c (__libdw_read_begin_end_pair_inc): Change argument
+       type of readp to Add readend argument. Check data size. Include base
+       in begin and end result.
+       (initial_offset): New static function.
+       (dwarf_ranges): Don't check Elf_Data being NULL (already done by
+       initial_offset, through __libdw_formptr). Use __libdw_cu_base_address
+       and initial_offset. Remove base check and addition (already done by
+       __libdw_read_begin_end_pair_inc.
+       * libdwP.h (Dwarf_CU): Add base_address field.
+       (__libdw_read_begin_end_pair_inc): Change argument type of readp to
+       const. Add readend argument.
+       (__libdw_formptr): Take and return const unsigned char pointers.
+       * libdw_findcu.c (__libdw_intern_next_unit): Initialize Dwarf_CU
+       base_address.
+
 2018-04-04  Mark Wielaard  <mark@klomp.org>
 
        * libdw_findcu.c (__libdw_intern_next_unit): Initialize Dwarf_CU
index 0aaea245edd45be321304624f770bb269fb0510a..02c169452e775592864e0b36f66cfa59ba69a5bd 100644 (file)
@@ -34,9 +34,9 @@
 #include <dwarf.h>
 #include "libdwP.h"
 
-internal_function unsigned char *
+internal_function const unsigned char *
 __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
-                int err_nodata, unsigned char **endpp,
+                int err_nodata, const unsigned char **endpp,
                 Dwarf_Off *offsetp)
 {
   if (attr == NULL)
index 0fcf950247f25d71e0bcfef43c11da6967ec32df..f5776753c5fe176e8dc71c5d3da6968d2ccbe3c2 100644 (file)
@@ -1,7 +1,6 @@
 /* Return location expression list.
-   Copyright (C) 2000-2010, 2013-2015, 2017 Red Hat, Inc.
+   Copyright (C) 2000-2010, 2013-2015, 2017, 2018 Red Hat, Inc.
    This file is part of elfutils.
-   Written by Ulrich Drepper <drepper@redhat.com>, 2000.
 
    This file is free software; you can redistribute it and/or modify
    it under the terms of either
@@ -659,44 +658,55 @@ dwarf_getlocation (Dwarf_Attribute *attr, Dwarf_Op **llbuf, size_t *listlen)
   return getlocation (attr->cu, &block, llbuf, listlen, cu_sec_idx (attr->cu));
 }
 
-static int
-attr_base_address (Dwarf_Attribute *attr, Dwarf_Addr *basep)
+Dwarf_Addr
+__libdw_cu_base_address (Dwarf_CU *cu)
 {
-  /* Fetch the CU's base address.  */
-  Dwarf_Die cudie = CUDIE (attr->cu);
-
-  /* Find the base address of the compilation unit.  It will
-     normally be specified by DW_AT_low_pc.  In DWARF-3 draft 4,
-     the base address could be overridden by DW_AT_entry_pc.  It's
-     been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
-     for compilation units with discontinuous ranges.  */
-  Dwarf_Attribute attr_mem;
-  if (unlikely (INTUSE(dwarf_lowpc) (&cudie, basep) != 0)
-      && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
-                                                    DW_AT_entry_pc,
-                                                    &attr_mem),
-                                basep) != 0)
+  if (cu->base_address == (Dwarf_Addr) -1)
     {
-      if (INTUSE(dwarf_errno) () != 0)
-       return -1;
-
-      /* The compiler provided no base address when it should
-        have.  Buggy GCC does this when it used absolute
-        addresses in the location list and no DW_AT_ranges.  */
-      *basep = 0;
+      Dwarf_Addr base;
+
+      /* Fetch the CU's base address.  */
+      Dwarf_Die cudie = CUDIE (cu);
+
+      /* Find the base address of the compilation unit.  It will
+        normally be specified by DW_AT_low_pc.  In DWARF-3 draft 4,
+        the base address could be overridden by DW_AT_entry_pc.  It's
+        been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
+        for compilation units with discontinuous ranges.  */
+      Dwarf_Attribute attr_mem;
+      if (INTUSE(dwarf_lowpc) (&cudie, &base) != 0
+         && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
+                                                        DW_AT_entry_pc,
+                                                        &attr_mem),
+                                    &base) != 0)
+       {
+         int err = INTUSE(dwarf_errno) ();
+         if (err != 0)
+           {
+             __libdw_seterrno (err);
+             base = (Dwarf_Addr) -1;
+           }
+         else
+           {
+             /* The compiler provided no base address when it should
+                have.  Buggy GCC does this when it used absolute
+                addresses in the location list and no DW_AT_ranges.  */
+             base = 0;
+           }
+       }
+      cu->base_address = base;
     }
-  return 0;
+
+  return cu->base_address;
 }
 
 static int
-initial_offset_base (Dwarf_Attribute *attr, ptrdiff_t *offset,
-                    Dwarf_Addr *basep)
+initial_offset (Dwarf_Attribute *attr, ptrdiff_t *offset)
 {
-  if (attr_base_address (attr, basep) != 0)
-    return -1;
+  size_t secidx = IDX_debug_loc;
 
   Dwarf_Word start_offset;
-  if (__libdw_formptr (attr, IDX_debug_loc,
+  if (__libdw_formptr (attr, secidx,
                       DWARF_E_NO_LOCLIST,
                       NULL, &start_offset) == NULL)
     return -1;
@@ -711,22 +721,19 @@ getlocations_addr (Dwarf_Attribute *attr, ptrdiff_t offset,
                   Dwarf_Addr address, const Elf_Data *locs, Dwarf_Op **expr,
                   size_t *exprlen)
 {
-  unsigned char *readp = locs->d_buf + offset;
-  unsigned char *readendp = locs->d_buf + locs->d_size;
-
- next:
-  if (readendp - readp < attr->cu->address_size * 2)
-    {
-    invalid:
-      __libdw_seterrno (DWARF_E_INVALID_DWARF);
-      return -1;
-    }
+  Dwarf_CU *cu = attr->cu;
+  Dwarf *dbg = cu->dbg;
+  size_t secidx = IDX_debug_loc;
+  const unsigned char *readp = locs->d_buf + offset;
+  const unsigned char *readendp = locs->d_buf + locs->d_size;
 
   Dwarf_Addr begin;
   Dwarf_Addr end;
 
-  switch (__libdw_read_begin_end_pair_inc (attr->cu->dbg, IDX_debug_loc,
-                                          &readp, attr->cu->address_size,
+ next:
+  switch (__libdw_read_begin_end_pair_inc (dbg, secidx,
+                                          &readp, readendp,
+                                          cu->address_size,
                                           &begin, &end, basep))
     {
     case 0: /* got location range. */
@@ -739,25 +746,29 @@ getlocations_addr (Dwarf_Attribute *attr, ptrdiff_t offset,
       return -1;
     }
 
-  if (readendp - readp < 2)
-    goto invalid;
-
   /* We have a location expression.  */
   Dwarf_Block block;
-  block.length = read_2ubyte_unaligned_inc (attr->cu->dbg, readp);
-  block.data = readp;
+  if (readendp - readp < 2)
+    {
+    invalid:
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return -1;
+    }
+  block.length = read_2ubyte_unaligned_inc (dbg, readp);
+  block.data = (unsigned char *) readp;
   if (readendp - readp < (ptrdiff_t) block.length)
     goto invalid;
   readp += block.length;
 
-  *startp = *basep + begin;
-  *endp = *basep + end;
+  /* Note these addresses include any base (if necessary) already.  */
+  *startp = begin;
+  *endp = end;
 
   /* If address is minus one we want them all, otherwise only matching.  */
   if (address != (Dwarf_Word) -1 && (address < *startp || address >= *endp))
     goto next;
 
-  if (getlocation (attr->cu, &block, expr, exprlen, IDX_debug_loc) != 0)
+  if (getlocation (cu, &block, expr, exprlen, secidx) != 0)
     return -1;
 
   return readp - (unsigned char *) locs->d_buf;
@@ -804,19 +815,19 @@ dwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address,
   size_t got = 0;
 
   /* This is a true loclistptr, fetch the initial base address and offset.  */
-  if (initial_offset_base (attr, &off, &base) != 0)
+  base = __libdw_cu_base_address (attr->cu);
+  if (base == (Dwarf_Addr) -1)
     return -1;
 
-  const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc];
-  if (d == NULL)
-    {
-      __libdw_seterrno (DWARF_E_NO_LOCLIST);
-      return -1;
-    }
+  if (initial_offset (attr, &off) != 0)
+    return -1;
+
+  size_t secidx = IDX_debug_loc;
+  const Elf_Data *d = attr->cu->dbg->sectiondata[secidx];
 
   while (got < maxlocs
          && (off = getlocations_addr (attr, off, &base, &start, &end,
-                                  address, d, &expr, &expr_len)) > 0)
+                                     address, d, &expr, &expr_len)) > 0)
     {
       /* This one matches the address.  */
       if (llbufs != NULL)
@@ -884,17 +895,17 @@ dwarf_getlocations (Dwarf_Attribute *attr, ptrdiff_t offset, Dwarf_Addr *basep,
 
       /* We must be looking at a true loclistptr, fetch the initial
         base address and offset.  */
-      if (initial_offset_base (attr, &offset, basep) != 0)
+      *basep = __libdw_cu_base_address (attr->cu);
+      if (*basep == (Dwarf_Addr) -1)
        return -1;
-    }
 
-  const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc];
-  if (d == NULL)
-    {
-      __libdw_seterrno (DWARF_E_NO_LOCLIST);
-      return -1;
+      if (initial_offset (attr, &offset) != 0)
+       return -1;
     }
 
+  size_t secidx = IDX_debug_loc;
+  const Elf_Data *d = attr->cu->dbg->sectiondata[secidx];
+
   return getlocations_addr (attr, offset, basep, startp, endp,
                            (Dwarf_Word) -1, d, expr, exprlen);
 }
index 4b6853d37d220960a0b840492794a897c7e1c9b2..dbcfa2d48773b04a7408796e24690f31aecb8570 100644 (file)
@@ -1,5 +1,5 @@
 /* Enumerate the PC ranges covered by a DIE.
-   Copyright (C) 2005, 2007, 2009 Red Hat, Inc.
+   Copyright (C) 2005, 2007, 2009, 2018 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -41,7 +41,9 @@
     - If an error occurs, don't set anything and return -1.  */
 internal_function int
 __libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index,
-                                unsigned char **addrp, int width,
+                                const unsigned char **addrp,
+                                const unsigned char *addrend,
+                                int width,
                                 Dwarf_Addr *beginp, Dwarf_Addr *endp,
                                 Dwarf_Addr *basep)
 {
@@ -50,7 +52,14 @@ __libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index,
   Dwarf_Addr begin;
   Dwarf_Addr end;
 
-  unsigned char *addr = *addrp;
+  const unsigned char *addr = *addrp;
+  if (addrend - addr < width * 2)
+    {
+    invalid:
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return -1;
+    }
+
   bool begin_relocated = READ_AND_RELOCATE (__libdw_relocate_address, begin);
   bool end_relocated = READ_AND_RELOCATE (__libdw_relocate_address, end);
   *addrp = addr;
@@ -59,13 +68,9 @@ __libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index,
   if (begin == escape && !begin_relocated)
     {
       if (unlikely (end == escape))
-       {
-         __libdw_seterrno (DWARF_E_INVALID_DWARF);
-         return -1;
-       }
+       goto invalid;
 
-      if (basep != NULL)
-       *basep = end;
+      *basep = end;
       return 1;
     }
 
@@ -75,12 +80,27 @@ __libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index,
 
   /* Don't check for begin_relocated == end_relocated.  Serve the data
      to the client even though it may be buggy.  */
-  *beginp = begin;
-  *endp = end;
+  *beginp = begin + *basep;
+  *endp = end + *basep;
 
   return 0;
 }
 
+static int
+initial_offset (Dwarf_Attribute *attr, ptrdiff_t *offset)
+{
+  size_t secidx = IDX_debug_ranges;
+
+  Dwarf_Word start_offset;
+  if (__libdw_formptr (attr, secidx,
+                      DWARF_E_NO_DEBUG_RANGES,
+                      NULL, &start_offset) == NULL)
+    return -1;
+
+  *offset = start_offset;
+  return 0;
+}
+
 ptrdiff_t
 dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
              Dwarf_Addr *startp, Dwarf_Addr *endp)
@@ -101,16 +121,11 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
     return 0;
 
   /* We have to look for a noncontiguous range.  */
+  size_t secidx = IDX_debug_ranges;
+  const Elf_Data *d = die->cu->dbg->sectiondata[secidx];
 
-  const Elf_Data *d = die->cu->dbg->sectiondata[IDX_debug_ranges];
-  if (d == NULL && offset != 0)
-    {
-      __libdw_seterrno (DWARF_E_NO_DEBUG_RANGES);
-      return -1;
-    }
-
-  unsigned char *readp;
-  unsigned char *readendp;
+  const unsigned char *readp;
+  const unsigned char *readendp;
   if (offset == 0)
     {
       Dwarf_Attribute attr_mem;
@@ -120,49 +135,30 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
        /* No PC attributes in this DIE at all, so an empty range list.  */
        return 0;
 
-      Dwarf_Word start_offset;
-      if ((readp = __libdw_formptr (attr, IDX_debug_ranges,
-                                   DWARF_E_NO_DEBUG_RANGES,
-                                   &readendp, &start_offset)) == NULL)
+      *basep = __libdw_cu_base_address (attr->cu);
+      if (*basep == (Dwarf_Addr) -1)
        return -1;
 
-      offset = start_offset;
-      assert ((Dwarf_Word) offset == start_offset);
-
-      /* Fetch the CU's base address.  */
-      Dwarf_Die cudie = CUDIE (attr->cu);
-
-      /* Find the base address of the compilation unit.  It will
-        normally be specified by DW_AT_low_pc.  In DWARF-3 draft 4,
-        the base address could be overridden by DW_AT_entry_pc.  It's
-        been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
-        for compilation units with discontinuous ranges.  */
-      if (unlikely (INTUSE(dwarf_lowpc) (&cudie, basep) != 0)
-         && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
-                                                        DW_AT_entry_pc,
-                                                        &attr_mem),
-                                    basep) != 0)
-       *basep = (Dwarf_Addr) -1;
+      if (initial_offset (attr, &offset) != 0)
+       return -1;
     }
   else
     {
       if (__libdw_offset_in_section (die->cu->dbg,
-                                    IDX_debug_ranges, offset, 1))
-       return -1l;
-
-      readp = d->d_buf + offset;
-      readendp = d->d_buf + d->d_size;
+                                    secidx, offset, 1))
+       return -1;
     }
 
- next:
-  if (readendp - readp < die->cu->address_size * 2)
-    goto invalid;
+  readp = d->d_buf + offset;
+  readendp = d->d_buf + d->d_size;
 
   Dwarf_Addr begin;
   Dwarf_Addr end;
 
-  switch (__libdw_read_begin_end_pair_inc (die->cu->dbg, IDX_debug_ranges,
-                                          &readp, die->cu->address_size,
+ next:
+  switch (__libdw_read_begin_end_pair_inc (die->cu->dbg, secidx,
+                                          &readp, readendp,
+                                          die->cu->address_size,
                                           &begin, &end, basep))
     {
     case 0:
@@ -172,22 +168,11 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
     case 2:
       return 0;
     default:
-      return -1l;
-    }
-
-  /* We have an address range entry.  Check that we have a base.  */
-  if (*basep == (Dwarf_Addr) -1)
-    {
-      if (INTUSE(dwarf_errno) () == 0)
-       {
-       invalid:
-         __libdw_seterrno (DWARF_E_INVALID_DWARF);
-       }
       return -1;
     }
 
-  *startp = *basep + begin;
-  *endp = *basep + end;
+  *startp = begin;
+  *endp = end;
   return readp - (unsigned char *) d->d_buf;
 }
 INTDEF (dwarf_ranges)
index 9413705933a973861c81fc5ca838e6bffec3eb04..594486f7a6255018d58af79dc938fee74ebf895e 100644 (file)
@@ -1,7 +1,6 @@
-/* Internal definitions for libdwarf.
+/* Internal definitions for libdw.
    Copyright (C) 2002-2011, 2013-2018 Red Hat, Inc.
    This file is part of elfutils.
-   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
 
    This file is free software; you can redistribute it and/or modify
    it under the terms of either
@@ -328,6 +327,10 @@ struct Dwarf_CU
   /* Known location lists.  */
   void *locs;
 
+  /* Base address for use with ranges and locs.
+     Don't access directly, call __libdw_cu_base_address.  */
+  Dwarf_Addr base_address;
+
   /* The offset into the .debug_addr section where index zero begins.
      Don't access directly, call __libdw_cu_addr_base.  */
   Dwarf_Off addr_base;
@@ -849,14 +852,17 @@ is_cudie (Dwarf_Die *cudie)
     - If it's end of rangelist, don't set anything and return 2
     - If an error occurs, don't set anything and return <0.  */
 int __libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index,
-                                    unsigned char **addr, int width,
+                                    const unsigned char **readp,
+                                    const unsigned char *readend,
+                                    int width,
                                     Dwarf_Addr *beginp, Dwarf_Addr *endp,
                                     Dwarf_Addr *basep)
   internal_function;
 
-unsigned char * __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
-                                int err_nodata, unsigned char **endpp,
-                                Dwarf_Off *offsetp)
+const unsigned char * __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
+                                      int err_nodata,
+                                      const unsigned char **endpp,
+                                      Dwarf_Off *offsetp)
   internal_function;
 
 /* Fills in the given attribute to point at an empty location expression.  */
@@ -877,6 +883,10 @@ int __libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
 /* Load and return value of DW_AT_comp_dir from CUDIE.  */
 const char *__libdw_getcompdir (Dwarf_Die *cudie);
 
+/* Get the base address for the CU, fetches it when not yet set.
+   This is used as initial base address for ranges and loclists.  */
+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);
 
index 04390b4567a87c7ca7c0332075d28b4f642426e3..3899c08756b10d9add401fd808533a87e6cd36f6 100644 (file)
@@ -116,6 +116,7 @@ __libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
   newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset;
   newp->lines = NULL;
   newp->locs = NULL;
+  newp->base_address = (Dwarf_Addr) -1;
   newp->addr_base = (Dwarf_Off) -1;
   newp->str_off_base = (Dwarf_Off) -1;
 
index fea1d17f3f7decd0ef3e42cd8c23aef130367d81..bcb24dc4daaf26ee2a72577105f3aeb56c9914fd 100644 (file)
@@ -1,3 +1,9 @@
+2018-04-03  Mark Wielaard  <mark@klomp.org>
+
+       * testfileranges4.debug.bz2: New testfile.
+       * run-dwarf-ranges.sh: Run on testfileranges4.debug.
+       * tests/Makefile.am (EXTRA_DIST): Add testfileranges4.debug.bz2.
+
 2018-03-06  Mark Wielaard  <mark@klomp.org>
 
        * varlocs.c (print_expr): Handle DW_OP_implicit_pointer,
index fe6c8ec563e6588ecc9243ffa978f6ee0798bca6..a8cc2df7e35d12f09a61a3ad0d213b1871979902 100644 (file)
@@ -198,6 +198,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
             run-dwfl-addr-sect.sh run-early-offscn.sh \
             run-dwarf-getmacros.sh \
             run-dwarf-ranges.sh debug-ranges-no-lowpc.o.bz2 \
+            testfileranges4.debug.bz2 \
             run-test-flag-nobits.sh \
             run-dwarf-getstring.sh run-rerequest_tag.sh run-alldts.sh \
             testfile15.bz2 testfile15.debug.bz2 \
index d202ed3ff76022eebfcda1b87131883809a951e6..f935eaf44223983d5da69674156b5a17170d3f74 100755 (executable)
@@ -1,5 +1,5 @@
 #! /bin/sh
-# Copyright (C) 2015 Red Hat, Inc.
+# Copyright (C) 2015, 2018 Red Hat, Inc.
 # This file is part of elfutils.
 #
 # This file is free software; you can redistribute it and/or modify
@@ -24,4 +24,82 @@ testrun_compare ${abs_builddir}/dwarf-ranges debug-ranges-no-lowpc.o 0xb <<\EOF
 3..4 (base 0)
 EOF
 
+# - hello.c
+# int say (const char *prefix);
+#
+# char *
+# subject (char *word, int count)
+# {
+#    return count > 0 ? word : (word + count);
+# }
+#
+# int
+# main (int argc, char **argv)
+# {
+#    return say (subject (argv[0], argc));
+# }
+#
+# int
+# no_say (const char *prefix)
+# {
+#   const char *world = subject ("World", 42);
+#   return prefix ? say (prefix) : say (world);
+# }
+#
+# - world.c
+# char * subject (char *word, int count);
+# int no_say (const char *prefix);
+#
+# static int
+# sad (char c)
+# {
+#   return c > 0 ? c : c + 1;
+# }
+#
+# static int
+# happy (const char *w)
+# {
+#   return sad (w[1]);
+# }
+#
+# int
+# say (const char *prefix)
+# {
+#   const char *world = subject ("World", 42);;
+#   return prefix ? sad (prefix[0]) : happy (world);
+# }
+#
+# char *
+# no_subject (char *word, int count)
+# {
+#    return count > 0 ? word : (word + count);
+# }
+#
+# int
+# no_main (int argc, char **argv)
+# {
+#    return no_say (no_subject (argv[0], argc));
+# }
+#
+# - gcc -c -O2 -gdwarf-4 hello.c
+# - gcc -c -O2 -gdwarf-4 world.c
+# - gcc -o testfileranges4 -O2 -gdwarf-4 hello.o world.o
+# - eu-strip -f testfileranges4.debug testfileranges4
+
+testfiles testfileranges4.debug
+testrun_compare ${abs_builddir}/dwarf-ranges testfileranges4.debug 0xb <<\EOF
+400500..40053a (base 0)
+400400..400415 (base 0)
+EOF
+
+testrun_compare ${abs_builddir}/dwarf-ranges testfileranges4.debug 0xcd <<\EOF
+400400..400402 (base 0)
+400405..40040d (base 0)
+EOF
+
+testrun_compare ${abs_builddir}/dwarf-ranges testfileranges4.debug 0x374 <<\EOF
+4005a0..4005a2 (base 400540)
+4005a5..4005ad (base 400540)
+EOF
+
 exit 0
diff --git a/tests/testfileranges4.debug.bz2 b/tests/testfileranges4.debug.bz2
new file mode 100755 (executable)
index 0000000..67ba573
Binary files /dev/null and b/tests/testfileranges4.debug.bz2 differ