diff options
-rw-r--r-- | .mtn-ignore | 6 | ||||
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | NEWS | 5 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | libdw/ChangeLog | 60 | ||||
-rw-r--r-- | libdw/Makefile.am | 11 | ||||
-rw-r--r-- | libdw/dwarf.h | 2 | ||||
-rw-r--r-- | libdw/dwarf_diecu.c | 46 | ||||
-rw-r--r-- | libdw/dwarf_entry_breakpoints.c | 147 | ||||
-rw-r--r-- | libdw/dwarf_entrypc.c | 35 | ||||
-rw-r--r-- | libdw/dwarf_getsrc_die.c | 9 | ||||
-rw-r--r-- | libdw/dwarf_getsrclines.c | 4 | ||||
-rw-r--r-- | libdw/dwarf_haspc.c | 78 | ||||
-rw-r--r-- | libdw/dwarf_ranges.c | 121 | ||||
-rw-r--r-- | libdw/libdw.h | 26 | ||||
-rw-r--r-- | libdw/libdw.map | 6 | ||||
-rw-r--r-- | libdw/libdwP.h | 2 | ||||
-rw-r--r-- | libdwfl/ChangeLog | 18 | ||||
-rw-r--r-- | libdwfl/libdwflP.h | 1 | ||||
-rw-r--r-- | libdwfl/linux-kernel-modules.c | 7 | ||||
-rw-r--r-- | libdwfl/relocate.c | 48 | ||||
-rw-r--r-- | tests/ChangeLog | 13 | ||||
-rw-r--r-- | tests/Makefile.am | 7 | ||||
-rw-r--r-- | tests/find-prologues.c | 106 | ||||
-rwxr-xr-x | tests/run-find-prologues.sh | 65 |
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 @@ -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. @@ -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 |