+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
#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)
/* 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
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;
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. */
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;
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)
/* 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);
}
/* 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
- 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)
{
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;
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;
}
/* 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)
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;
/* 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:
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)
-/* 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
/* 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;
- 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. */
/* 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);
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;
+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,
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 \
#! /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
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