summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mtn-ignore6
-rw-r--r--ChangeLog6
-rw-r--r--NEWS5
-rw-r--r--configure.ac2
-rw-r--r--libdw/ChangeLog60
-rw-r--r--libdw/Makefile.am11
-rw-r--r--libdw/dwarf.h2
-rw-r--r--libdw/dwarf_diecu.c46
-rw-r--r--libdw/dwarf_entry_breakpoints.c147
-rw-r--r--libdw/dwarf_entrypc.c35
-rw-r--r--libdw/dwarf_getsrc_die.c9
-rw-r--r--libdw/dwarf_getsrclines.c4
-rw-r--r--libdw/dwarf_haspc.c78
-rw-r--r--libdw/dwarf_ranges.c121
-rw-r--r--libdw/libdw.h26
-rw-r--r--libdw/libdw.map6
-rw-r--r--libdw/libdwP.h2
-rw-r--r--libdwfl/ChangeLog18
-rw-r--r--libdwfl/libdwflP.h1
-rw-r--r--libdwfl/linux-kernel-modules.c7
-rw-r--r--libdwfl/relocate.c48
-rw-r--r--tests/ChangeLog13
-rw-r--r--tests/Makefile.am7
-rw-r--r--tests/find-prologues.c106
-rwxr-xr-xtests/run-find-prologues.sh65
25 files changed, 722 insertions, 109 deletions
diff --git a/.mtn-ignore b/.mtn-ignore
new file mode 100644
index 00000000..31de38a8
--- /dev/null
+++ b/.mtn-ignore
@@ -0,0 +1,6 @@
+Makefile\.in
+aclocal\.m4
+config\.h\.in
+elfutils\.spec
+configure
+.*\.pot
diff --git a/ChangeLog b/ChangeLog
index fc5cb13a..d03a7713 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2005-09-16 Roland McGrath <roland@redhat.com>
+
+ * configure.ac (ALLOW_UNALIGNED) [__ia64__ || __alpha__]:
+ Don't set it, since on IA64 you get error messages for unaligned
+ accesses, and on Alpha it's at least very slow.
+
2005-08-29 Ulrich Drepper <drepper@redhat.com>
* configure.ac: Fix GCOV make condition generation.
diff --git a/NEWS b/NEWS
index 1d88564f..d29f956f 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,8 @@
+Version 0.116:
+
+libdw: New functions dwarf_ranges, dwarf_entrypc, dwarf_diecu,
+ dwarf_entry_breakpoints.
+
Version 0.115:
libelf: speed-ups of non-mmap reading.
diff --git a/configure.ac b/configure.ac
index 547d1182..8c4fca03 100644
--- a/configure.ac
+++ b/configure.ac
@@ -248,7 +248,7 @@ AH_BOTTOM([
/* Define ALLOW_UNALIGNED if the architecture allows operations on
unaligned memory locations. */
-#if defined __i386__ || defined __alpha__ || defined __x86_64__ || defined __ia64__
+#if defined __i386__ || defined __x86_64__
# define ALLOW_UNALIGNED 1
#else
# define ALLOW_UNALIGNED 0
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index db069c94..b74d26b0 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,63 @@
+2005-10-27 Roland McGrath <roland@redhat.com>
+
+ * dwarf_entry_breakpoints.c (search_range): Fix binary search code;
+ don't match end_sequence markers.
+
+ * dwarf_getsrclines.c (compare_lines): Sort end_sequence markers
+ before normal records at the same address.
+ * dwarf_getsrc_die.c (dwarf_getsrc_die): Don't match an end_sequence
+ marker.
+
+2005-10-26 Roland McGrath <roland@redhat.com>
+
+ * dwarf_entry_breakpoints.c: Use the second line record within the
+ function, regardless of its source location data.
+
+2005-10-25 Roland McGrath <roland@redhat.com>
+
+ * dwarf_entry_breakpoints.c: Fall back to entrypc for contiguous too.
+
+ * libdw.map: Add dwarf_entrypc, dwarf_entry_breakpoints.
+
+2005-10-14 Roland McGrath <roland@redhat.com>
+
+ * dwarf_diecu.c (dwarf_diecu): New file.
+ * Makefile.am (libdw_a_SOURCES): Add it.
+ * libdw.h: Declare dwarf_diecu.
+ * libdw.map: Export it.
+
+ * libdw.map: Bump to 0.116; export dwarf_ranges.
+
+2005-09-20 Roland McGrath <roland@redhat.com>
+
+ * dwarf_haspc.c: Use dwarf_ranges.
+ * dwarf_entry_breakpoints.c: Likewise.
+
+ * dwarf_ranges.c: New file.
+ * Makefile.am (libdw_a_SOURCES): Add it.
+ * libdw.h: Declare dwarf_ranges.
+ * libdwP.h: Add INTDECL.
+
+2005-09-14 Roland McGrath <roland@redhat.com>
+
+ * dwarf_entry_breakpoints.c (dwarf_entry_breakpoints): Fix braino in
+ prologue_end marker scanning loop.
+
+2005-09-11 Roland McGrath <roland@redhat.com>
+
+ * dwarf.h: Comment typo fix.
+
+2005-09-07 Roland McGrath <roland@redhat.com>
+
+ * dwarf_entry_breakpoints.c: New file.
+ * Makefile.am (libdw_a_SOURCES): Add it.
+ * libdw.h: Declare dwarf_entry_breakpoints.
+
+ * dwarf_entrypc.c: New file.
+ * Makefile.am (libdw_a_SOURCES): Add it.
+ * libdw.h: Declare dwarf_entrypc.
+ * libdwP.h: Add INTDECL.
+
2005-08-28 Ulrich Drepper <drepper@redhat.com>
* Makefile.am: Use $(LINK) not $(CC) when creating DSO.
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index a35f5dcc..12567139 100644
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -42,10 +42,11 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
dwarf_attr_integrate.c dwarf_hasattr_integrate.c \
dwarf_child.c dwarf_haschildren.c dwarf_formaddr.c \
dwarf_formudata.c dwarf_formsdata.c dwarf_lowpc.c \
- dwarf_haspc.c dwarf_highpc.c \
+ dwarf_entrypc.c dwarf_haspc.c dwarf_highpc.c dwarf_ranges.c \
dwarf_formref.c dwarf_formref_die.c dwarf_siblingof.c \
- dwarf_dieoffset.c dwarf_cuoffset.c dwarf_hasattr.c \
- dwarf_hasform.c dwarf_whatform.c dwarf_whatattr.c \
+ dwarf_dieoffset.c dwarf_cuoffset.c dwarf_diecu.c \
+ dwarf_hasattr.c dwarf_hasform.c \
+ dwarf_whatform.c dwarf_whatattr.c \
dwarf_bytesize.c dwarf_arrayorder.c dwarf_bitsize.c \
dwarf_bitoffset.c dwarf_srclang.c dwarf_getabbrevtag.c \
dwarf_getabbrevcode.c dwarf_abbrevhaschildren.c \
@@ -68,8 +69,8 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
dwarf_func_line.c dwarf_func_col.c dwarf_func_die.c \
dwarf_func_inline.c dwarf_getsrc_file.c \
libdw_findcu.c libdw_form.c libdw_alloc.c memory-access.c \
- libdw_visit_scopes.c
-
+ libdw_visit_scopes.c \
+ dwarf_entry_breakpoints.c
if !MUDFLAP
libdw_pic_a_SOURCES =
diff --git a/libdw/dwarf.h b/libdw/dwarf.h
index 2268256f..bf53f51d 100644
--- a/libdw/dwarf.h
+++ b/libdw/dwarf.h
@@ -516,7 +516,7 @@ enum
};
-/* DWARF extended opcide encodings. */
+/* DWARF extended opcode encodings. */
enum
{
DW_LNE_end_sequence = 1,
diff --git a/libdw/dwarf_diecu.c b/libdw/dwarf_diecu.c
new file mode 100644
index 00000000..5b0f1b8c
--- /dev/null
+++ b/libdw/dwarf_diecu.c
@@ -0,0 +1,46 @@
+/* Return CU DIE containing given DIE.
+ Copyright (C) 2005 Red Hat, Inc.
+
+ This program is Open Source software; you can redistribute it and/or
+ modify it under the terms of the Open Software License version 1.0 as
+ published by the Open Source Initiative.
+
+ You should have received a copy of the Open Software License along
+ with this program; if not, you may obtain a copy of the Open Software
+ License version 1.0 from http://www.opensource.org/licenses/osl.php or
+ by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+ 3001 King Ranch Road, Ukiah, CA 95482. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include "libdwP.h"
+
+
+Dwarf_Die *
+dwarf_diecu (die, result, address_sizep, offset_sizep)
+ Dwarf_Die *die;
+ Dwarf_Die *result;
+ uint8_t *address_sizep;
+ uint8_t *offset_sizep;
+{
+ if (die == NULL)
+ return NULL;
+
+ /* Clear the entire DIE structure. This signals we have not yet
+ determined any of the information. */
+ memset (result, '\0', sizeof (Dwarf_Die));
+
+ result->addr = ((char *) die->cu->dbg->sectiondata[IDX_debug_info]->d_buf
+ + die->cu->start + 3 * die->cu->offset_size - 4 + 3);
+ result->cu = die->cu;
+
+ if (address_sizep != NULL)
+ *address_sizep = die->cu->address_size;
+ if (offset_sizep != NULL)
+ *offset_sizep = die->cu->offset_size;
+
+ return result;
+}
diff --git a/libdw/dwarf_entry_breakpoints.c b/libdw/dwarf_entry_breakpoints.c
new file mode 100644
index 00000000..30f03fd6
--- /dev/null
+++ b/libdw/dwarf_entry_breakpoints.c
@@ -0,0 +1,147 @@
+/* Find entry breakpoint locations for a function.
+ Copyright (C) 2005 Red Hat, Inc.
+
+ This program is Open Source software; you can redistribute it and/or
+ modify it under the terms of the Open Software License version 1.0 as
+ published by the Open Source Initiative.
+
+ You should have received a copy of the Open Software License along
+ with this program; if not, you may obtain a copy of the Open Software
+ License version 1.0 from http://www.opensource.org/licenses/osl.php or
+ by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+ 3001 King Ranch Road, Ukiah, CA 95482. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "libdwP.h"
+#include <dwarf.h>
+#include <stdlib.h>
+
+
+int
+dwarf_entry_breakpoints (die, bkpts)
+ Dwarf_Die *die;
+ Dwarf_Addr **bkpts;
+{
+ int nbkpts = 0;
+ *bkpts = NULL;
+
+ /* Add one breakpoint location to the result vector. */
+ inline int add_bkpt (Dwarf_Addr pc)
+ {
+ Dwarf_Addr *newlist = realloc (*bkpts, ++nbkpts * sizeof newlist[0]);
+ if (newlist == NULL)
+ {
+ free (*bkpts);
+ *bkpts = NULL;
+ __libdw_seterrno (DWARF_E_NOMEM);
+ return -1;
+ }
+ newlist[nbkpts - 1] = pc;
+ *bkpts = newlist;
+ return nbkpts;
+ }
+
+ /* Fallback result, break at the entrypc/lowpc value. */
+ inline int entrypc_bkpt (void)
+ {
+ Dwarf_Addr pc;
+ return INTUSE(dwarf_entrypc) (die, &pc) < 0 ? -1 : add_bkpt (pc);
+ }
+
+ /* Fetch the CU's line records to look for this DIE's addresses. */
+ Dwarf_Die cudie =
+ {
+ .cu = die->cu,
+ .addr = ((char *) die->cu->dbg->sectiondata[IDX_debug_info]->d_buf
+ + die->cu->start + 3 * die->cu->offset_size - 4 + 3),
+ };
+ Dwarf_Lines *lines;
+ size_t nlines;
+ if (INTUSE(dwarf_getsrclines) (&cudie, &lines, &nlines) < 0)
+ {
+ int error = INTUSE (dwarf_errno) ();
+ if (error == DWARF_E_NO_DEBUG_LINE)
+ return entrypc_bkpt ();
+ __libdw_seterrno (error);
+ return -1;
+ }
+
+ /* Search a contiguous PC range for prologue-end markers.
+ If DWARF, look for proper markers.
+ Failing that, if ADHOC, look for the ad hoc convention. */
+ inline int search_range (Dwarf_Addr low, Dwarf_Addr high,
+ bool dwarf, bool adhoc)
+ {
+ size_t l = 0, u = nlines;
+ while (l < u)
+ {
+ size_t idx = (l + u) / 2;
+ if (lines->info[idx].addr < low)
+ l = idx + 1;
+ else if (lines->info[idx].addr > low)
+ u = idx;
+ else if (lines->info[idx].end_sequence)
+ l = idx + 1;
+ else
+ {
+ l = idx;
+ break;
+ }
+ }
+ if (l < u)
+ {
+ if (dwarf)
+ for (size_t i = l; i < u && lines->info[i].addr < high; ++i)
+ if (lines->info[i].prologue_end
+ && add_bkpt (lines->info[i].addr) < 0)
+ return -1;
+ if (adhoc && nbkpts == 0)
+ while (++l < nlines && lines->info[l].addr < high)
+ if (!lines->info[l].end_sequence)
+ return add_bkpt (lines->info[l].addr);
+ return nbkpts;
+ }
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
+
+ /* Search each contiguous address range for DWARF prologue_end markers. */
+
+ Dwarf_Addr base;
+ Dwarf_Addr begin;
+ Dwarf_Addr end;
+ ptrdiff_t offset = INTUSE(dwarf_ranges) (die, 0, &base, &begin, &end);
+ if (offset < 0)
+ return -1;
+
+ /* Most often there is a single contiguous PC range for the DIE. */
+ if (offset == 1)
+ return search_range (begin, end, true, true) ?: entrypc_bkpt ();
+
+ Dwarf_Addr lowpc = (Dwarf_Addr) -1l;
+ Dwarf_Addr highpc = (Dwarf_Addr) -1l;
+ while (offset > 0)
+ {
+ /* We have an address range entry. */
+ if (search_range (begin, end, true, false) < 0)
+ return -1;
+
+ if (begin < lowpc)
+ {
+ lowpc = begin;
+ highpc = end;
+ }
+
+ offset = INTUSE(dwarf_ranges) (die, offset, &base, &begin, &end);
+ }
+
+ /* If we didn't find any proper DWARF markers, then look in the
+ lowest-addressed range for an ad hoc marker. Failing that,
+ fall back to just using the entrypc value. */
+ return (nbkpts
+ ?: (lowpc == (Dwarf_Addr) -1l ? 0
+ : search_range (lowpc, highpc, false, true))
+ ?: entrypc_bkpt ());
+}
diff --git a/libdw/dwarf_entrypc.c b/libdw/dwarf_entrypc.c
new file mode 100644
index 00000000..61a1d4be
--- /dev/null
+++ b/libdw/dwarf_entrypc.c
@@ -0,0 +1,35 @@
+/* Return entry PC attribute of DIE.
+ Copyright (C) 2003, 2005 Red Hat, Inc.
+
+ This program is Open Source software; you can redistribute it and/or
+ modify it under the terms of the Open Software License version 1.0 as
+ published by the Open Source Initiative.
+
+ You should have received a copy of the Open Software License along
+ with this program; if not, you may obtain a copy of the Open Software
+ License version 1.0 from http://www.opensource.org/licenses/osl.php or
+ by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+ 3001 King Ranch Road, Ukiah, CA 95482. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_entrypc (die, return_addr)
+ Dwarf_Die *die;
+ Dwarf_Addr *return_addr;
+{
+ Dwarf_Attribute attr_mem;
+
+ return INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_entry_pc,
+ &attr_mem)
+ ?: INTUSE(dwarf_attr) (die, DW_AT_low_pc,
+ &attr_mem),
+ return_addr);
+}
+INTDEF(dwarf_entrypc)
diff --git a/libdw/dwarf_getsrc_die.c b/libdw/dwarf_getsrc_die.c
index e3ce4f2a..753d48f7 100644
--- a/libdw/dwarf_getsrc_die.c
+++ b/libdw/dwarf_getsrc_die.c
@@ -36,7 +36,7 @@ dwarf_getsrc_die (Dwarf_Die *cudie, Dwarf_Addr addr)
size_t idx = (l + u) / 2;
if (addr < lines->info[idx].addr)
u = idx;
- else if (addr > lines->info[idx].addr)
+ else if (addr > lines->info[idx].addr || lines->info[idx].end_sequence)
l = idx + 1;
else
return &lines->info[idx];
@@ -51,7 +51,12 @@ dwarf_getsrc_die (Dwarf_Die *cudie, Dwarf_Addr addr)
information is faulty and no end-sequence marker is present, we
still ignore it. */
if (u > 0 && u < nlines && addr > lines->info[u - 1].addr)
- return &lines->info[u - 1];
+ {
+ while (lines->info[u - 1].end_sequence && u > 0)
+ --u;
+ if (u > 0)
+ return &lines->info[u - 1];
+ }
__libdw_seterrno (DWARF_E_ADDR_OUTOFRANGE);
return NULL;
diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c
index 85fe35eb..a207b16a 100644
--- a/libdw/dwarf_getsrclines.c
+++ b/libdw/dwarf_getsrclines.c
@@ -43,6 +43,10 @@ compare_lines (const void *a, const void *b)
Dwarf_Line *const *p1 = a;
Dwarf_Line *const *p2 = b;
+ if ((*p1)->addr == (*p2)->addr)
+ /* An end_sequence marker precedes a normal record at the same address. */
+ return (*p2)->end_sequence - (*p1)->end_sequence;
+
return (*p1)->addr - (*p2)->addr;
}
diff --git a/libdw/dwarf_haspc.c b/libdw/dwarf_haspc.c
index 7f29296d..d2e737a5 100644
--- a/libdw/dwarf_haspc.c
+++ b/libdw/dwarf_haspc.c
@@ -25,81 +25,15 @@ dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc)
if (die == NULL)
return -1;
- /* Usually there is a single contiguous range. */
- Dwarf_Addr lowpc, highpc;
- if (INTUSE(dwarf_highpc) (die, &highpc) == 0
- && INTUSE(dwarf_lowpc) (die, &lowpc) == 0)
- return pc >= lowpc && pc < highpc;
-
- /* We have to look for a noncontiguous range. */
- Dwarf_Attribute attr_mem;
- Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges, &attr_mem);
- if (attr == NULL)
- return -1;
-
- /* Must have the form data4 or data8 which act as an offset. */
- Dwarf_Word offset;
- if (INTUSE(dwarf_formudata) (attr, &offset) != 0)
- return -1;
-
- const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_ranges];
- if (d == NULL)
- {
- __libdw_seterrno (DWARF_E_NO_DEBUG_RANGES);
- return -1;
- }
-
- /* Fetch the CU's base address. */
Dwarf_Addr base;
- Dwarf_Die cudie =
- {
- .cu = attr->cu,
- .addr = ((char *) attr->cu->dbg->sectiondata[IDX_debug_info]->d_buf
- + attr->cu->start + 3 * attr->cu->offset_size - 4 + 3),
- };
- if (INTUSE(dwarf_lowpc) (&cudie, &base) != 0)
- return -1;
-
- unsigned char *readp = d->d_buf + offset;
Dwarf_Addr begin;
Dwarf_Addr end;
- do
- {
- next:
- if ((unsigned char *) d->d_buf + d->d_size - readp
- < attr->cu->address_size * 2)
- {
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- return -1;
- }
-
- if (attr->cu->address_size == 8)
- {
- begin = read_8ubyte_unaligned_inc (attr->cu->dbg, readp);
- end = read_8ubyte_unaligned_inc (attr->cu->dbg, readp);
- }
- else
- {
- begin = (Dwarf_Sword) read_4sbyte_unaligned_inc (attr->cu->dbg,
- readp);
- end = read_4ubyte_unaligned_inc (attr->cu->dbg, readp);
- }
-
- if (begin == (Dwarf_Addr) -1l) /* Base address entry. */
- {
- base = end;
- goto next;
- }
-
- if (begin == 0 && end == 0) /* End of list entry. */
- /* This is not the droid you are looking for. */
- return 0;
-
- /* We have an address range entry. */
- }
- while (pc < base + begin || pc >= base + end);
+ ptrdiff_t offset = 0;
+ while ((offset = INTUSE(dwarf_ranges) (die, offset, &base,
+ &begin, &end)) > 0)
+ if (pc >= begin && pc < end)
+ return 1;
- /* This one matches the address. */
- return 1;
+ return offset;
}
INTDEF (dwarf_haspc)
diff --git a/libdw/dwarf_ranges.c b/libdw/dwarf_ranges.c
new file mode 100644
index 00000000..546bcac0
--- /dev/null
+++ b/libdw/dwarf_ranges.c
@@ -0,0 +1,121 @@
+/* Enumerate the PC ranges covered by a DIE.
+ Copyright (C) 2005 Red Hat, Inc.
+
+ This program is Open Source software; you can redistribute it and/or
+ modify it under the terms of the Open Software License version 1.0 as
+ published by the Open Source Initiative.
+
+ You should have received a copy of the Open Software License along
+ with this program; if not, you may obtain a copy of the Open Software
+ License version 1.0 from http://www.opensource.org/licenses/osl.php or
+ by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+ 3001 King Ranch Road, Ukiah, CA 95482. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include <dwarf.h>
+#include <assert.h>
+
+
+ptrdiff_t
+dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
+ Dwarf_Addr *startp, Dwarf_Addr *endp)
+{
+ if (die == NULL)
+ return -1;
+
+ if (offset == 0
+ /* Usually there is a single contiguous range. */
+ && INTUSE(dwarf_highpc) (die, endp) == 0
+ && INTUSE(dwarf_lowpc) (die, startp) == 0)
+ /* A offset into .debug_ranges will never be 1, it must be at least a
+ multiple of 4. So we can return 1 as a special case value to mark
+ there are no ranges to look for on the next call. */
+ return 1;
+
+ if (offset == 1)
+ return 0;
+
+ /* We have to look for a noncontiguous range. */
+
+ const Elf_Data *d = die->cu->dbg->sectiondata[IDX_debug_ranges];
+ if (d == NULL)
+ {
+ __libdw_seterrno (DWARF_E_NO_DEBUG_RANGES);
+ return -1;
+ }
+
+ if (offset == 0)
+ {
+ Dwarf_Attribute attr_mem;
+ Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges,
+ &attr_mem);
+ if (attr == NULL)
+ return -1;
+
+ /* Must have the form data4 or data8 which act as an offset. */
+ Dwarf_Word start_offset;
+ if (INTUSE(dwarf_formudata) (attr, &start_offset) != 0)
+ return -1;
+
+ offset = start_offset;
+ assert ((Dwarf_Word) offset == start_offset);
+
+ /* Fetch the CU's base address. */
+ Dwarf_Die cudie =
+ {
+ .cu = attr->cu,
+ .addr = ((char *) attr->cu->dbg->sectiondata[IDX_debug_info]->d_buf
+ + attr->cu->start + 3 * attr->cu->offset_size - 4 + 3),
+ };
+ if (INTUSE(dwarf_lowpc) (&cudie, basep) != 0)
+ return -1;
+ }
+ else if (offset < 0 || (size_t) offset >= d->d_size)
+ {
+ __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+ return -1l;
+ }
+
+ unsigned char *readp = d->d_buf + offset;
+
+ next:
+ if ((unsigned char *) d->d_buf + d->d_size - readp
+ < die->cu->address_size * 2)
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
+
+ Dwarf_Addr begin;
+ Dwarf_Addr end;
+ if (die->cu->address_size == 8)
+ {
+ begin = read_8ubyte_unaligned_inc (die->cu->dbg, readp);
+ end = read_8ubyte_unaligned_inc (die->cu->dbg, readp);
+ }
+ else
+ {
+ begin = (Dwarf_Sword) read_4sbyte_unaligned_inc (die->cu->dbg,
+ readp);
+ end = read_4ubyte_unaligned_inc (die->cu->dbg, readp);
+ }
+
+ if (begin == (Dwarf_Addr) -1l) /* Base address entry. */
+ {
+ *basep = end;
+ goto next;
+ }
+
+ if (begin == 0 && end == 0) /* End of list entry. */
+ return 0;
+
+ /* We have an address range entry. */
+ *startp = *basep + begin;
+ *endp = *basep + end;
+ return readp - (unsigned char *) d->d_buf;
+}
+INTDEF (dwarf_ranges)
diff --git a/libdw/libdw.h b/libdw/libdw.h
index 350aa440..2bce26bd 100644
--- a/libdw/libdw.h
+++ b/libdw/libdw.h
@@ -194,6 +194,10 @@ extern Dwarf_Off dwarf_dieoffset (Dwarf_Die *die);
/* Return offset of DIE in CU. */
extern Dwarf_Off dwarf_cuoffset (Dwarf_Die *die);
+/* Return CU DIE containing given DIE. */
+extern Dwarf_Die *dwarf_diecu (Dwarf_Die *die, Dwarf_Die *result,
+ uint8_t *address_sizep, uint8_t *offset_sizep);
+
/* Return CU DIE containing given address. */
extern Dwarf_Die *dwarf_addrdie (Dwarf *dbg, Dwarf_Addr addr,
Dwarf_Die *result) __nonnull_attribute__ (3);
@@ -292,10 +296,26 @@ extern int dwarf_highpc (Dwarf_Die *die, Dwarf_Addr *return_addr)
extern int dwarf_lowpc (Dwarf_Die *die, Dwarf_Addr *return_addr)
__nonnull_attribute__ (2);
+/* Return entry_pc or low_pc attribute of DIE. */
+extern int dwarf_entrypc (Dwarf_Die *die, Dwarf_Addr *return_addr)
+ __nonnull_attribute__ (2);
+
/* Return 1 if DIE's lowpc/highpc or ranges attributes match the PC address,
0 if not, or -1 for errors. */
extern int dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc);
+/* Enumerate the PC address ranges covered by this DIE, covering all
+ addresses where dwarf_haspc returns true. In the first call OFFSET
+ should be zero and *BASEP need not be initialized. Returns -1 for
+ errors, zero when there are no more address ranges to report, or a
+ nonzero OFFSET value to pass to the next call. Each subsequent call
+ must preserve *BASEP from the prior call. Successful calls fill in
+ *STARTP and *ENDP with a contiguous address range. */
+extern ptrdiff_t dwarf_ranges (Dwarf_Die *die,
+ ptrdiff_t offset, Dwarf_Addr *basep,
+ Dwarf_Addr *startp, Dwarf_Addr *endp);
+
+
/* Return byte size attribute of DIE. */
extern int dwarf_bytesize (Dwarf_Die *die);
@@ -530,6 +550,12 @@ extern int dwarf_func_inline_instances (Dwarf_Func *func,
void *arg);
+/* Find the appropriate PC location or locations for function entry
+ breakpoints for the given DW_TAG_subprogram DIE. Returns -1 for errors.
+ On success, returns the number of breakpoint locations (never zero)
+ and sets *BKPTS to a malloc'd vector of addresses. */
+extern int dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts);
+
/* Call callback function for each of the macro information entry for
the CU. */
diff --git a/libdw/libdw.map b/libdw/libdw.map
index a5324bd1..3849b320 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -1,5 +1,5 @@
ELFUTILS_0 { };
-ELFUTILS_0.115 {
+ELFUTILS_0.116 {
global:
dwarf_abbrevhaschildren;
dwarf_addrdie;
@@ -16,9 +16,12 @@ ELFUTILS_0.115 {
dwarf_cuoffset;
dwarf_diename;
dwarf_dieoffset;
+ dwarf_diecu;
dwarf_end;
dwarf_errmsg;
dwarf_errno;
+ dwarf_entrypc;
+ dwarf_entry_breakpoints;
dwarf_filesrc;
dwarf_formaddr;
dwarf_formblock;
@@ -86,6 +89,7 @@ ELFUTILS_0.115 {
dwarf_onesrcline;
dwarf_nextcu;
dwarf_new_oom_handler;
+ dwarf_ranges;
dwarf_siblingof;
dwarf_srclang;
dwarf_tag;
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 37f28721..4dbe77e3 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -373,6 +373,7 @@ INTDECL (dwarf_child)
INTDECL (dwarf_dieoffset)
INTDECL (dwarf_diename)
INTDECL (dwarf_end)
+INTDECL (dwarf_entrypc)
INTDECL (dwarf_errmsg)
INTDECL (dwarf_formaddr)
INTDECL (dwarf_formblock)
@@ -393,6 +394,7 @@ INTDECL (dwarf_highpc)
INTDECL (dwarf_lowpc)
INTDECL (dwarf_nextcu)
INTDECL (dwarf_offdie)
+INTDECL (dwarf_ranges)
INTDECL (dwarf_siblingof)
INTDECL (dwarf_tag)
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index efffa616..60bd68b3 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,21 @@
+2005-10-20 Roland McGrath <roland@redhat.com>
+
+ * libdwflP.h (DWFL_ERRORS): New error UNKNOWN_MACHINE.
+ * relocate.c (__libdwfl_relocate): Return DWFL_E_UNKNOWN_MACHINE
+ instead of DWFL_E_BADRELTYPE if ebl_get_elfmachine yields EM_NONE.
+
+2005-10-01 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (report_kernel): Return ENOENT if we fail
+ with errno 0.
+
+2005-09-19 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (dwfl_linux_kernel_report_modules): Use
+ PRIx64 instead of PRIi64, lest addresses with high bits set overflow
+ the signed integer reading; they will just have to be in hexadecimal.
+ (dwfl_linux_kernel_module_section_address): Likewise.
+
2005-08-28 Ulrich Drepper <drepper@redhat.com>
* Makefile.am (%.os): Use COMPILE.os.
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index ae8985db..c4f303ed 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -38,6 +38,7 @@
DWFL_ERROR (LIBELF, N_("See elf_errno")) \
DWFL_ERROR (LIBDW, N_("See dwarf_errno")) \
DWFL_ERROR (LIBEBL, N_("See ebl_errno (XXX missing)")) \
+ DWFL_ERROR (UNKNOWN_MACHINE, N_("no support library found for machine")) \
DWFL_ERROR (NOREL, N_("Callbacks missing for ET_REL file")) \
DWFL_ERROR (BADRELTYPE, N_("Unsupported relocation type")) \
DWFL_ERROR (BADRELOFF, N_("r_offset is bogus")) \
diff --git a/libdwfl/linux-kernel-modules.c b/libdwfl/linux-kernel-modules.c
index ba65c599..c219c330 100644
--- a/libdwfl/linux-kernel-modules.c
+++ b/libdwfl/linux-kernel-modules.c
@@ -88,7 +88,8 @@ report_kernel (Dwfl *dwfl, const char *release,
int result = 0;
if (fd < 0)
- result = (predicate != NULL && !(*predicate) ("kernel", NULL)) ? 0 : errno;
+ result = ((predicate != NULL && !(*predicate) ("kernel", NULL))
+ ? 0 : errno ?: ENOENT);
else
{
bool report = true;
@@ -398,7 +399,7 @@ dwfl_linux_kernel_module_section_address
(void) __fsetlocking (f, FSETLOCKING_BYCALLER);
- int result = (fscanf (f, "%" PRIi64 "\n", addr) == 1 ? 0
+ int result = (fscanf (f, "%" PRIx64 "\n", addr) == 1 ? 0
: ferror_unlocked (f) ? errno : ENOEXEC);
fclose (f);
@@ -423,7 +424,7 @@ dwfl_linux_kernel_report_modules (Dwfl *dwfl)
Dwarf_Addr modaddr;
unsigned long int modsz;
char modname[128];
- while (fscanf (f, "%128s %lu %*s %*s %*s %" PRIi64 "\n",
+ while (fscanf (f, "%128s %lu %*s %*s %*s %" PRIx64 "\n",
modname, &modsz, &modaddr) == 3)
if (INTUSE(dwfl_report_module) (dwfl, modname,
modaddr, modaddr + modsz) == NULL)
diff --git a/libdwfl/relocate.c b/libdwfl/relocate.c
index fe03d397..8644fb77 100644
--- a/libdwfl/relocate.c
+++ b/libdwfl/relocate.c
@@ -168,20 +168,24 @@ __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile)
}
/* These are the types we can relocate. */
-#define TYPES DO_TYPE (BYTE, Byte) DO_TYPE (HALF, Half) \
- DO_TYPE (WORD, Word) DO_TYPE (SWORD, Sword) \
- DO_TYPE (XWORD, Xword) DO_TYPE (SXWORD, Sxword)
+#define TYPES DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half); \
+ DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword); \
+ DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
size_t size;
Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype);
switch (type)
{
-#define DO_TYPE(NAME, Name) \
- case ELF_T_##NAME: \
- size = sizeof (GElf_##Name); \
- break;
- TYPES
+#define DO_TYPE(NAME, Name) \
+ case ELF_T_##NAME: \
+ size = sizeof (GElf_##Name); \
+ break
+ TYPES;
#undef DO_TYPE
- default:
+ default:
+ /* This might be because ebl_openbackend failed to find
+ any libebl_CPU.so library. Diagnose that clearly. */
+ if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
+ return DWFL_E_UNKNOWN_MACHINE;
return DWFL_E_BADRELTYPE;
}
@@ -189,7 +193,7 @@ __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile)
return DWFL_E_BADRELOFF;
#define DO_TYPE(NAME, Name) GElf_##Name Name;
- union { TYPES } tmpbuf;
+ union { TYPES; } tmpbuf;
#undef DO_TYPE
Elf_Data tmpdata =
{
@@ -213,13 +217,13 @@ __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile)
value += *addend;
switch (type)
{
-#define DO_TYPE(NAME, Name) \
- case ELF_T_##NAME: \
- tmpbuf.Name = value; \
- break;
- TYPES
+#define DO_TYPE(NAME, Name) \
+ case ELF_T_##NAME: \
+ tmpbuf.Name = value; \
+ break
+ TYPES;
#undef DO_TYPE
- default:
+ default:
abort ();
}
}
@@ -233,13 +237,13 @@ __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile)
assert (d == &tmpdata);
switch (type)
{
-#define DO_TYPE(NAME, Name) \
- case ELF_T_##NAME: \
- tmpbuf.Name += (GElf_##Name) value; \
- break;
- TYPES
+#define DO_TYPE(NAME, Name) \
+ case ELF_T_##NAME: \
+ tmpbuf.Name += (GElf_##Name) value; \
+ break
+ TYPES;
#undef DO_TYPE
- default:
+ default:
abort ();
}
}
diff --git a/tests/ChangeLog b/tests/ChangeLog
index ec47a31d..37da62c6 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,16 @@
+2005-10-27 Roland McGrath <roland@redhat.com>
+
+ * run-find-prologues.sh: New file.
+ * Makefile.am (TESTS, EXTRA_DIST): Add it.
+
+ * find-prologues.c (handle_function): Skip inlines.
+
+2005-10-25 Roland McGrath <roland@redhat.com>
+
+ * find-prologues.c: New file.
+ * Makefile.am (noinst_PROGRAMS): Add it.
+ (find_prologues_LDADD): New variable.
+
2005-09-02 Ulrich Drepper <drepper@redhat.com>
* run-strings-test.sh: Remove strings.out in the end.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 119e11d7..01d7b6ad 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -33,7 +33,7 @@ noinst_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
get-aranges allfcts line2addr addrscopes funcscopes \
show-abbrev hash asm-tst1 asm-tst2 asm-tst3 \
asm-tst4 asm-tst5 asm-tst6 asm-tst7 asm-tst8 asm-tst9 \
- msg_tst newscn ecp dwflmodtest
+ msg_tst newscn ecp dwflmodtest find-prologues
# get-ciefde
TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
@@ -47,7 +47,8 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
run-strip-test6.sh run-ecp-test.sh run-ecp-test2.sh \
run-elflint-test.sh run-elflint-self.sh run-ranlib-test.sh \
run-ranlib-test2.sh run-ranlib-test3.sh run-ranlib-test4.sh \
- run-addrscopes.sh run-strings-test.sh run-funcscopes.sh
+ run-addrscopes.sh run-strings-test.sh run-funcscopes.sh \
+ run-find-prologues.sh
# run-show-ciefde.sh
EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
@@ -64,6 +65,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
run-elflint-self.sh run-ranlib-test.sh run-ranlib-test2.sh \
run-ranlib-test3.sh run-ranlib-test4.sh \
run-addrscopes.sh run-strings-test.sh run-funcscopes.sh \
+ run-find-prologues.sh \
testfile15.bz2 testfile15.debug.bz2 \
testfile16.bz2 testfile16.debug.bz2 \
testfile17.bz2 testfile17.debug.bz2 \
@@ -116,6 +118,7 @@ line2addr_no_Wformat = yes
line2addr_LDADD = $(libdw) $(libmudflap)
addrscopes_LDADD = $(libdw) $(libmudflap)
funcscopes_LDADD = $(libdw) $(libmudflap)
+find_prologues_LDADD = $(libdw) $(libmudflap)
#show_ciefde_LDADD = ../libdwarf/libdwarf.so $(libelf) $(libmudflap)
asm_tst1_LDADD = $(libasm) $(libebl) $(libelf) $(libmudflap) -ldl
asm_tst2_LDADD = $(libasm) $(libebl) $(libelf) $(libmudflap) -ldl
diff --git a/tests/find-prologues.c b/tests/find-prologues.c
new file mode 100644
index 00000000..30404cda
--- /dev/null
+++ b/tests/find-prologues.c
@@ -0,0 +1,106 @@
+/* Test program for dwarf_entry_breakpoints.
+ Copyright (C) 2005 Red Hat, Inc.
+
+ This program is Open Source software; you can redistribute it and/or
+ modify it under the terms of the Open Software License version 1.0 as
+ published by the Open Source Initiative.
+
+ You should have received a copy of the Open Software License along
+ with this program; if not, you may obtain a copy of the Open Software
+ License version 1.0 from http://www.opensource.org/licenses/osl.php or
+ by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+ 3001 King Ranch Road, Ukiah, CA 95482. */
+
+#include <config.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <libdwfl.h>
+#include <dwarf.h>
+#include <argp.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <error.h>
+#include <string.h>
+#include <fnmatch.h>
+
+
+struct args
+{
+ Dwfl *dwfl;
+ Dwarf_Die *cu;
+ Dwarf_Addr dwbias;
+ char **argv;
+};
+
+static int
+handle_function (Dwarf_Func *func, void *arg)
+{
+ struct args *a = arg;
+
+ const char *name = dwarf_func_name (func);
+ char **argv = a->argv;
+ if (argv[0] != NULL)
+ {
+ bool match;
+ do
+ match = fnmatch (*argv, name, 0) == 0;
+ while (!match && *++argv);
+ if (!match)
+ return 0;
+ }
+
+ Dwarf_Die funcdie_mem;
+ Dwarf_Die *funcdie = dwarf_func_die (func, &funcdie_mem);
+ assert (funcdie == &funcdie_mem);
+
+ if (dwarf_func_inline (func))
+ return 0;
+
+ Dwarf_Addr entrypc;
+ if (dwarf_entrypc (funcdie, &entrypc) != 0)
+ error (EXIT_FAILURE, 0, "dwarf_entrypc: %s: %s",
+ dwarf_diename (funcdie), dwarf_errmsg (-1));
+ entrypc += a->dwbias;
+
+ printf ("%-16s %#.16" PRIx64, dwarf_diename (funcdie), entrypc);
+
+ Dwarf_Addr *bkpts = NULL;
+ int result = dwarf_entry_breakpoints (funcdie, &bkpts);
+ if (result <= 0)
+ printf ("\t%s\n", dwarf_errmsg (-1));
+ else
+ {
+ for (int i = 0; i < result; ++i)
+ printf (" %#.16" PRIx64 "%s", bkpts[i] + a->dwbias,
+ i == result - 1 ? "\n" : "");
+ free (bkpts);
+ }
+
+ return 0;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ int remaining;
+
+ /* Set locale. */
+ (void) setlocale (LC_ALL, "");
+
+ struct args a = { .dwfl = NULL, .cu = NULL };
+
+ (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &remaining,
+ &a.dwfl);
+ assert (a.dwfl != NULL);
+ a.argv = &argv[remaining];
+
+ int result = 0;
+
+ while ((a.cu = dwfl_nextcu (a.dwfl, a.cu, &a.dwbias)) != NULL)
+ dwarf_getfuncs (a.cu, &handle_function, &a, 0);
+
+ return result;
+}
diff --git a/tests/run-find-prologues.sh b/tests/run-find-prologues.sh
new file mode 100755
index 00000000..3e43fc53
--- /dev/null
+++ b/tests/run-find-prologues.sh
@@ -0,0 +1,65 @@
+#! /bin/sh
+# Copyright (C) 2005 Red Hat, Inc.
+#
+# This program is Open Source software; you can redistribute it and/or
+# modify it under the terms of the Open Software License version 1.0 as
+# published by the Open Source Initiative.
+#
+# You should have received a copy of the Open Software License along
+# with this program; if not, you may obtain a copy of the Open Software
+# License version 1.0 from http://www.opensource.org/licenses/osl.php or
+# by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+# 3001 King Ranch Road, Ukiah, CA 95482.
+set -e
+
+files="testfile testfile11 testfile22 testfile24 \
+testfile25 testfile3 testfile4 testfile5 testfile6"
+
+for file in $files; do
+ # Don't fail if we cannot decompress the file.
+ bunzip2 -c $srcdir/$file.bz2 > $file 2>/dev/null || exit 77
+done
+
+for file in $files; do
+ ./find-prologues -e $file || :
+done > find-prologues-test.out 2>&1
+
+diff -Bbu find-prologues-test.out - <<\EOF
+main 0x000000000804842c 0x0000000008048432
+bar 0x000000000804845c 0x000000000804845f
+foo 0x0000000008048468 0x000000000804846b
+main 0x00000000080489b8 0x00000000080489cd
+gnu_obj_2 0x0000000008048c9e 0x0000000008048ca4
+gnu_obj_3 0x0000000008048cd8 0x0000000008048cde
+gnu_obj_2 0x0000000008048cf4 0x0000000008048cfa
+~invalid_argument 0x0000000008048d2e 0x0000000008048d34
+gnu_obj_1 0x0000000008048d62 0x0000000008048d65
+gnu_obj_1 0x0000000008048d8a 0x0000000008048d8d
+~invalid_argument 0x0000000008048db2 0x0000000008048db8
+function 0x0000000008048348 0x000000000804834e
+main 0x000000000804835b 0x0000000008048377
+incr 0x0000000008048348 0x000000000804834e
+main 0x0000000008048354 0x0000000008048360
+incr 0x0000000008048348 0x000000000804834c
+main 0x000000000804842c 0x0000000008048433
+bar 0x0000000008048458 0x000000000804845b
+foo 0x0000000008048464 0x0000000008048467
+get 0x00000000080493fc 0x0000000008049402
+main 0x0000000008049498 0x000000000804949e
+a 0x000000000804d85c 0x000000000804d85c
+__tfPCc 0x000000000804d86c 0x000000000804d872
+__tfCc 0x000000000804d8a4 0x000000000804d8a4
+bar 0x000000000804842c 0x000000000804842f
+foo 0x0000000008048438 0x000000000804843b
+main 0x0000000008048444 0x000000000804844a
+main 0x00000000080489b8 0x00000000080489cd
+gnu_obj_2 0x0000000008048c9e 0x0000000008048ca4
+gnu_obj_3 0x0000000008048cd8 0x0000000008048cde
+gnu_obj_2 0x0000000008048cf4 0x0000000008048cfa
+~invalid_argument 0x0000000008048d2e 0x0000000008048d34
+gnu_obj_1 0x0000000008048d62 0x0000000008048d65
+gnu_obj_1 0x0000000008048d8a 0x0000000008048d8d
+~invalid_argument 0x0000000008048db2 0x0000000008048db8
+EOF
+
+rm -f find-prologues-test.out $files