]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdw/
authorRoland McGrath <roland@redhat.com>
Fri, 28 Oct 2005 06:56:24 +0000 (06:56 +0000)
committerRoland McGrath <roland@redhat.com>
Fri, 28 Oct 2005 06:56:24 +0000 (06:56 +0000)
Fixes to last changes.

tests/
2005-10-27  Roland McGrath  <roland@redhat.com>

* run-find-prologues.sh: New file.
* Makefile.am (TESTS, EXTRA_DIST): Add it.

25 files changed:
.mtn-ignore [new file with mode: 0644]
ChangeLog
NEWS
configure.ac
libdw/ChangeLog
libdw/Makefile.am
libdw/dwarf.h
libdw/dwarf_diecu.c [new file with mode: 0644]
libdw/dwarf_entry_breakpoints.c [new file with mode: 0644]
libdw/dwarf_entrypc.c [new file with mode: 0644]
libdw/dwarf_getsrc_die.c
libdw/dwarf_getsrclines.c
libdw/dwarf_haspc.c
libdw/dwarf_ranges.c [new file with mode: 0644]
libdw/libdw.h
libdw/libdw.map
libdw/libdwP.h
libdwfl/ChangeLog
libdwfl/libdwflP.h
libdwfl/linux-kernel-modules.c
libdwfl/relocate.c
tests/ChangeLog
tests/Makefile.am
tests/find-prologues.c [new file with mode: 0644]
tests/run-find-prologues.sh [new file with mode: 0755]

diff --git a/.mtn-ignore b/.mtn-ignore
new file mode 100644 (file)
index 0000000..31de38a
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile\.in
+aclocal\.m4
+config\.h\.in
+elfutils\.spec
+configure
+.*\.pot
index fc5cb13acaf78437fe41bd2242fffb62962ad531..d03a77139659c7ae74c00b60ca184094a24b8a45 100644 (file)
--- 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 1d88564f376222f929d746a382cc12a53dc186a3..d29f956f6854f3e0cefc0183e73852bbaea1e704 100644 (file)
--- 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.
index 547d11823fe7dc10879874a41116ab1c3bebfaaa..8c4fca03e2698a2977a3765973ee415fdf901677 100644 (file)
@@ -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
index db069c94a0350911a9a4552126ac444d1af23ece..b74d26b09ae46a3e69f895ffa04e00421b9615b8 100644 (file)
@@ -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.
index a35f5dcc1750c2ffbba5c6c8237987ef410d0fd0..125671393872749728f33c8c0b9616fc0d2f46ad 100644 (file)
@@ -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 =
index 2268256f7d7ed9f8ba682bbe0353e365816700e9..bf53f51d59bce6859530cd7b2b431ab4ce2ca13d 100644 (file)
@@ -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 (file)
index 0000000..5b0f1b8
--- /dev/null
@@ -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 (file)
index 0000000..30f03fd
--- /dev/null
@@ -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 (file)
index 0000000..61a1d4b
--- /dev/null
@@ -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)
index e3ce4f2ad3affe8097ef0688e9f82ecee0038a39..753d48f7ec71bc2c243df6f55d18a7766aa232be 100644 (file)
@@ -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;
index 85fe35eb1ec566c68378afb2867c5263d051063c..a207b16a244bbff31fb4dd987a2788d2a2716a30 100644 (file)
@@ -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;
 }
 
index 7f29296dc393951c071d1a7eac54028ecf0baca0..d2e737a5bbaed30dbd44e7c6556a7577b13b840d 100644 (file)
@@ -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 (file)
index 0000000..546bcac
--- /dev/null
@@ -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)
index 350aa440ee6f8c45b42ccb8e9ae78abe2da91a83..2bce26bd85a353b218f169a90ab70f1cb26c2f86 100644 (file)
@@ -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.  */
index a5324bd1834fb856dec49ac1b2e3bf99f0108d0f..3849b32048d48678480f27dd96acfaa2a0375d0c 100644 (file)
@@ -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;
index 37f287212b2113409f7c9aba1c6e2e4d2fbbde32..4dbe77e368bc897e5fc646a9f0f9b2e662fdfb63 100644 (file)
@@ -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)
 
index efffa616753db3984104a48d06c4b01a9f559ae8..60bd68b3199316c9e7c0b8d7bba60264e0f58de9 100644 (file)
@@ -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.
index ae8985db53643592ccf9f46706db1fb944417cde..c4f303ed9faa16208b8845be84222d1e10fc1603 100644 (file)
@@ -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"))                            \
index ba65c5998ae3f86c62b1704749c05bd7e73f54d7..c219c330dde4d81bfa1d8bb10f361faf75f04faa 100644 (file)
@@ -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)
index fe03d397fbee05beb96c77f31440bd53b959b363..8644fb77fbc1cd76a3d27f89a3aaf824dcbbed99 100644 (file)
@@ -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 ();
                    }
                }
index ec47a31d67082c5be62b11711ae1dfb11a194cdb..37da62c631a0a854d20afca4c2267fb9efc2c396 100644 (file)
@@ -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.
index 119e11d79b6eea359380990035d979947ef79e5e..01d7b6ad7454f422b57b3ba740a44b17379e1c78 100644 (file)
@@ -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 (file)
index 0000000..30404cd
--- /dev/null
@@ -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 (executable)
index 0000000..3e43fc5
--- /dev/null
@@ -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