libdw/
authorRoland McGrath <roland@redhat.com>
Sat, 27 Aug 2005 10:33:26 +0000 (10:33 +0000)
committerRoland McGrath <roland@redhat.com>
Sat, 27 Aug 2005 10:33:26 +0000 (10:33 +0000)
2005-08-27  Roland McGrath  <roland@redhat.com>

* dwarf_getscopes.c (dwarf_getscopes): Rewritten using
__libdw_visit_scopes.

* dwarf_getscopes_die.c: New file.
* Makefile.am (libdw_a_SOURCES): Add it.
* libdw.h: Declare dwarf_getscopes_die.
* libdw.map: Bump to 0.115 and add it.

* libdw_visit_scopes.c (__libdw_visit_scopes): Pass a struct
containing a DIE and its parent pointer, instead of just Dwarf_Die.
Take two functions for both preorder and postorder visitors.
* libdwP.h: Update decl.
(struct Dwarf_Die_Chain): New type.
* dwarf_func_inline.c: Update uses.

* dwarf_diename.c (dwarf_diename): Use dwarf_attr_integrate.
Add INTDEF.
* libdwP.h: Add INTDECL.
* dwarf_func_name.c (dwarf_func_name): Use dwarf_diename.

src/
2005-08-27  Roland McGrath  <roland@redhat.com>

* addr2line.c (dwarf_diename_integrate): Function removed.
(print_dwarf_function): Use plain dwarf_diename.

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

* run-funcscopes.sh: New file.
* testfile25.bz2: New data file.
* Makefile.am (TESTS, EXTRA_DIST): Add them.

2005-08-26  Roland McGrath  <roland@redhat.com>

* addrscopes.c (dwarf_diename_integrate): Removed.
(print_vars, handle_address): Use plain dwarf_diename.

2005-08-25  Roland McGrath  <roland@redhat.com>

* funcscopes.c: New file.
* Makefile.am (noinst_PROGRAMS): Add it.
(funcscopes_LDADD): New variable.

* run-addrscopes.sh: Add another case.
* testfile24.bz2: New data file.
* Makefile.am (EXTRA_DIST): Add it.

* addrscopes.c (handle_address): Take new argument IGNORE_INLINES,
pass it to dwarf_getscopes.
(main): Pass it, true when '=' follows an address.

21 files changed:
libdw/ChangeLog
libdw/Makefile.am
libdw/dwarf_diename.c
libdw/dwarf_func_inline.c
libdw/dwarf_func_name.c
libdw/dwarf_getscopes.c
libdw/dwarf_getscopes_die.c [new file with mode: 0644]
libdw/libdw.h
libdw/libdw.map
libdw/libdwP.h
libdw/libdw_visit_scopes.c
src/ChangeLog
src/addr2line.c
tests/ChangeLog
tests/Makefile.am
tests/addrscopes.c
tests/funcscopes.c [new file with mode: 0644]
tests/run-addrscopes.sh
tests/run-funcscopes.sh [new file with mode: 0644]
tests/testfile24.bz2 [new file with mode: 0644]
tests/testfile25.bz2 [new file with mode: 0644]

index 3b84ab9..fcae442 100644 (file)
@@ -1,3 +1,25 @@
+2005-08-27  Roland McGrath  <roland@redhat.com>
+
+       * dwarf_getscopes.c (dwarf_getscopes): Rewritten using
+       __libdw_visit_scopes.
+
+       * dwarf_getscopes_die.c: New file.
+       * Makefile.am (libdw_a_SOURCES): Add it.
+       * libdw.h: Declare dwarf_getscopes_die.
+       * libdw.map: Bump to 0.115 and add it.
+
+       * libdw_visit_scopes.c (__libdw_visit_scopes): Pass a struct
+       containing a DIE and its parent pointer, instead of just Dwarf_Die.
+       Take two functions for both preorder and postorder visitors.
+       * libdwP.h: Update decl.
+       (struct Dwarf_Die_Chain): New type.
+       * dwarf_func_inline.c: Update uses.
+
+       * dwarf_diename.c (dwarf_diename): Use dwarf_attr_integrate.
+       Add INTDEF.
+       * libdwP.h: Add INTDECL.
+       * dwarf_func_name.c (dwarf_func_name): Use dwarf_diename.
+
 2005-08-23  Roland McGrath  <roland@redhat.com>
 
        * dwarf_attr_integrate.c (dwarf_attr_integrate): Treat
index ad6b28a..264e478 100644 (file)
@@ -48,7 +48,7 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
                  dwarf_getabbrevcode.c dwarf_abbrevhaschildren.c \
                  dwarf_getattrcnt.c dwarf_getabbrevattr.c \
                  dwarf_getsrclines.c dwarf_getsrc_die.c \
-                 dwarf_getscopes.c dwarf_getscopevar.c \
+                 dwarf_getscopes.c dwarf_getscopes_die.c dwarf_getscopevar.c \
                  dwarf_linesrc.c dwarf_lineno.c dwarf_lineaddr.c \
                  dwarf_linecol.c dwarf_linebeginstatement.c \
                  dwarf_lineendsequence.c dwarf_lineblock.c \
index 41d763c..daef5fb 100644 (file)
@@ -26,6 +26,8 @@ dwarf_diename (die)
 {
   Dwarf_Attribute attr_mem;
 
-  return INTUSE(dwarf_formstring) (INTUSE(dwarf_attr) (die, DW_AT_name,
-                                                      &attr_mem));
+  return INTUSE(dwarf_formstring) (INTUSE(dwarf_attr_integrate) (die,
+                                                                DW_AT_name,
+                                                                &attr_mem));
 }
+INTDEF (dwarf_diename)
index 7656286..4472515 100644 (file)
@@ -14,15 +14,15 @@ struct visitor_info
 
 static int
 scope_visitor (unsigned int depth __attribute__ ((unused)),
-              Dwarf_Die *die, void *arg)
+              struct Dwarf_Die_Chain *die, void *arg)
 {
   struct visitor_info *const v = arg;
 
-  if (INTUSE(dwarf_tag) (die) != DW_TAG_inlined_subroutine)
+  if (INTUSE(dwarf_tag) (&die->die) != DW_TAG_inlined_subroutine)
     return DWARF_CB_OK;
 
   Dwarf_Attribute attr_mem;
-  Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_abstract_origin,
+  Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&die->die, DW_AT_abstract_origin,
                                              &attr_mem);
   if (attr == NULL)
     return DWARF_CB_OK;
@@ -35,7 +35,7 @@ scope_visitor (unsigned int depth __attribute__ ((unused)),
   if (origin->addr != v->die_addr)
     return DWARF_CB_OK;
 
-  return (*v->callback) (die, v->arg);
+  return (*v->callback) (&die->die, v->arg);
 }
 
 int
@@ -68,5 +68,6 @@ dwarf_func_inline_instances (Dwarf_Func *func,
                             void *arg)
 {
   struct visitor_info v = { func->die->addr, callback, arg };
-  return __libdw_visit_scopes (0, func->cudie, &scope_visitor, &v);
+  struct Dwarf_Die_Chain cu = { .die = *func->cudie, .parent = NULL };
+  return __libdw_visit_scopes (0, &cu, &scope_visitor, NULL, &v);
 }
index 4151c35..c6912aa 100644 (file)
@@ -23,8 +23,5 @@
 const char *
 dwarf_func_name (Dwarf_Func *func)
 {
-  Dwarf_Attribute attr_mem;
-
-  return INTUSE(dwarf_formstring) (INTUSE(dwarf_attr) (func->die, DW_AT_name,
-                                                      &attr_mem));
+  return INTUSE(dwarf_diename) (func->die);
 }
index 7863036..2d5345e 100644 (file)
 # include <config.h>
 #endif
 
+#include <assert.h>
 #include <stdlib.h>
 #include "libdwP.h"
 #include <dwarf.h>
 
 
-enum die_class { ignore, match, match_inline, walk, imported };
+struct args
+{
+  Dwarf_Addr pc;
+  Dwarf_Die *scopes;
+  unsigned int inlined, nscopes;
+  Dwarf_Die inlined_origin;
+};
 
-static enum die_class
-classify_die (Dwarf_Die *die)
+/* Preorder visitor: prune the traversal if this DIE does not contain PC.  */
+static int
+pc_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
 {
-  switch (INTUSE(dwarf_tag) (die))
-    {
-      /* DIEs with addresses we can try to match.  */
-    case DW_TAG_compile_unit:
-    case DW_TAG_module:
-    case DW_TAG_lexical_block:
-    case DW_TAG_with_stmt:
-    case DW_TAG_catch_block:
-    case DW_TAG_try_block:
-    case DW_TAG_entry_point:
-      return match;
-    case DW_TAG_inlined_subroutine:
-      return match_inline;
-    case DW_TAG_subprogram:
-      /* This might be a concrete out-of-line instance of an inline, in
-        which case it is not guaranteed to be owned by the right scope and
-        we will search for its origin as for DW_TAG_inlined_subroutine.  */
-      return (INTUSE(dwarf_hasattr) (die, DW_AT_abstract_origin)
-             ? match_inline : match);
-
-      /* DIEs without addresses that can own DIEs with addresses.  */
-    case DW_TAG_namespace:
-      return walk;
-
-      /* Special indirection required.  */
-    case DW_TAG_imported_unit:
-      return imported;
-
-      /* Other DIEs we have no reason to descend.  */
-    default:
-      break;
-    }
-  return ignore;
+  struct args *a = arg;
+
+  if (a->scopes != NULL || INTUSE(dwarf_haspc) (&die->die, a->pc) <= 0)
+    die->prune = true;
+  else if (INTUSE (dwarf_tag) (&die->die) == DW_TAG_inlined_subroutine)
+    a->inlined = depth;
+
+  return 0;
 }
 
-/* DIE contains PC.  Find its child that contains PC.  Returns -1 for
-   errors, 0 for no matches.  On success, *SCOPES gets the malloc'd array
-   of containing scopes.  A positive return value is the number of those
-   scopes.  A return value < -1 is -1 - number of those scopes, when the
-   outermost scope is a concrete instance of an inline subroutine.  */
+/* Preorder visitor for second partial traversal after finding a
+   concrete inlined instance.  */
 static int
-find_pc (unsigned int depth, Dwarf_Die *die, Dwarf_Addr pc, Dwarf_Die **scopes)
+origin_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
 {
-  Dwarf_Die child;
-  if (INTUSE(dwarf_child) (die, &child) != 0)
-    return -1;
+  struct args *a = arg;
+
+  if (die->die.addr != a->inlined_origin.addr)
+    return 0;
 
-  /* Recurse on this DIE to search within its children.
-     Return nonzero if this gets an error or a final result.  */
-  inline int search_child (void)
+  /* We have a winner!  This is the abstract definition of the inline
+     function of which A->scopes[A->nscopes - 1] is a concrete instance.
+  */
+
+  unsigned int nscopes = a->nscopes + depth;
+  Dwarf_Die *scopes = realloc (a->scopes, nscopes * sizeof scopes[0]);
+  if (scopes == NULL)
     {
-      int n = find_pc (depth + 1, &child, pc, scopes);
-      if (n > 0)
-       /* That stored the N innermost scopes.  Now store ours.  */
-       (*scopes)[n++] = child;
-      return n;
+      free (a->scopes);
+      __libdw_seterrno (DWARF_E_NOMEM);
+      return -1;
     }
 
-  /* Check each of our child DIEs.  */
-  enum die_class got = ignore;
+  a->scopes = scopes;
   do
     {
-      enum die_class child_class = classify_die (&child);
-      switch (child_class)
-       {
-       case match:
-       case match_inline:
-         if (INTUSE(dwarf_haspc) (&child, pc) > 0)
-           break;
-         continue;
-
-       case walk:
-         if (INTUSE(dwarf_haschildren) (&child))
-           got = walk;
-         continue;
-
-       case imported:
-         got = walk;
-         continue;
-
-       default:
-       case ignore:
-         continue;
-       }
-
-      /* We get here only when the PC has matched.  */
-      got = child_class;
-      break;
+      die = die->parent;
+      scopes[a->nscopes++] = die->die;
     }
-  while (INTUSE(dwarf_siblingof) (&child, &child) == 0);
+  while (a->nscopes < nscopes);
+  assert (die->parent == NULL);
+  return a->nscopes;
+}
+
+/* Postorder visitor: first (innermost) call wins.  */
+static int
+pc_record (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
+{
+  struct args *a = arg;
 
-  switch (got)
+  if (a->scopes == NULL)
     {
-    case match:
-    case match_inline:
-      /* We have a DIE that matched the PC.  */
-      if (INTUSE(dwarf_haschildren) (&child))
-       {
-         /* Recurse on this DIE to narrow within its children.
-            Return now if this gets an error or a final result.  */
-         int result = search_child ();
-         if (result < 0 || (got == match && result > 0))
-           return result;
-         if (result > 0)       /* got == match_inline */
-           /* We have a winner, but CHILD is a concrete inline instance
-              so DIE and its containing scopes do not actually apply.
-              DIE is the scope that inlined the function.  Our root
-              caller must find the abstract scope that defines us.  */
-           return -1 - result;
-       }
+      if (die->prune)
+       return 0;
+
+      /* We have hit the innermost DIE that contains the target PC.  */
 
-      /* This DIE has no children containing the PC, so this is it.  */
-      *scopes = malloc (depth * sizeof (*scopes)[0]);
-      if (*scopes == NULL)
+      a->nscopes = depth + 1 - a->inlined;
+      a->scopes = malloc (a->nscopes * sizeof a->scopes[0]);
+      if (a->scopes == NULL)
        {
          __libdw_seterrno (DWARF_E_NOMEM);
          return -1;
        }
-      (*scopes)[0] = child;
-      return got == match ? 1 : -2;
 
-    case walk:
-      /* We don't have anything matching the PC, but we have some things
-        we might descend to find one.  Recurse on each of those.  */
-      if (INTUSE(dwarf_child) (die, &child) != 0)
-       return -1;
-      do
-       switch (classify_die (&child))
-         {
-         case walk:
-           if (INTUSE(dwarf_haschildren) (&child))
-             {
-               /* Recurse on this DIE to look for the PC within its children.
-                  Return now if this gets an error or a final result.  */
-               int result = search_child ();
-               if (result != 0)
-                 return result;
-             }
-           break;
-
-         case imported:
-           {
-             /* This imports another compilation unit to appear
-                as part of this one, inside the current scope.
-                Recurse to search the referenced unit, but without
-                recording it as an inner scoping level.  */
-
-             Dwarf_Attribute attr_mem;
-             Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&child, DW_AT_import,
-                                                         &attr_mem);
-             if (INTUSE(dwarf_formref_die) (attr, &child) != NULL)
-               {
-                 int result = find_pc (depth, &child, pc, scopes);
-                 if (result != 0)
-                   return result;
-               }
-           }
-           break;
-
-         default:
-           break;
-         }
-      while (INTUSE(dwarf_siblingof) (&child, &child) == 0);
-      break;
-
-    default:
-    case ignore:
-      /* Nothing to see here.  */
-      break;
-    }
+      for (unsigned int i = 0; i < a->nscopes; ++i)
+       {
+         a->scopes[i] = die->die;
+         die = die->parent;
+       }
 
-  /* No matches.  */
-  return 0;
-}
+      if (a->inlined == 0)
+       {
+         assert (die == NULL);
+         return a->nscopes;
+       }
 
+      /* This is the concrete inlined instance itself.
+        Record its abstract_origin pointer.  */
+      Dwarf_Die *const inlinedie = &a->scopes[depth - a->inlined];
 
-/* OWNER owns OWNED.  Find intermediate scopes.  *SCOPES was allocated by
-   find_pc and has SKIP elements.  We realloc it, append more containing
-   scopes, and return 1 + the number appended.  Returns -1 on errors,
-   or 0 when OWNED was not found within OWNER.  */
-static int
-find_die (unsigned int depth, Dwarf_Die *owner, Dwarf_Die *owned,
-         Dwarf_Die **scopes, unsigned int skip)
-{
-  Dwarf_Die child;
-  if (INTUSE(dwarf_child) (owner, &child) != 0)
-    return -1;
+      assert (INTUSE (dwarf_tag) (inlinedie) == DW_TAG_inlined_subroutine);
+      Dwarf_Attribute attr_mem;
+      Dwarf_Attribute *attr = INTUSE (dwarf_attr) (inlinedie,
+                                                  DW_AT_abstract_origin,
+                                                  &attr_mem);
+      if (INTUSE (dwarf_formref_die) (attr, &a->inlined_origin) == NULL)
+       return -1;
+      return 0;
+    }
 
-  do
-    {
-      if (child.addr == owned->addr)
-       /* This is the one.  OWNER is the innermost owner.  */
-       return 1;
 
-      /* Unfortunately we cannot short-circuit the dead-end paths just by
-        checking the physical layout to see if OWNED falls within CHILD.
-        If it doesn't, there may still be a DW_TAG_imported_unit that
-        refers to its true owner indirectly.  */
+  /* We've recorded the scopes back to one that is a concrete inlined
+     instance.  Now return out of the traversal back to the scope
+     containing that instance.  */
 
-      switch (classify_die (&child))
-       {
-       case match:
-       case match_inline:
-       case walk:
-         if (INTUSE(dwarf_haschildren) (&child))
-           {
-             /* Recurse on this DIE to look for OWNED within its children.
-                Return now if this gets an error or a final result.  */
-             int n = find_die (depth + 1, &child, owned, scopes, skip);
-             if (n < 0)
-               return n;
-             if (n > 1)
-               {
-                 /* We have a winner.  CHILD owns the owner of OWNED.  */
-                 (*scopes)[skip + n - 1] = child;
-                 return n + 1;
-               }
-             if (n > 0)        /* n == 1 */
-               {
-                 /* CHILD is the direct owner of OWNED.  */
-                 Dwarf_Die *nscopes = realloc (*scopes,
-                                               (skip + depth)
-                                               * sizeof nscopes[0]);
-                 if (nscopes == NULL)
-                   {
-                     free (*scopes);
-                     *scopes = NULL;
-                     __libdw_seterrno (DWARF_E_NOMEM);
-                     return -1;
-                   }
-                 nscopes[skip] = child;
-                 *scopes = nscopes;
-                 return 2;
-               }
-           }
-         break;
-
-       case imported:
-         {
-           /* This is imports another compilation unit to appear
-              as part of this one, inside the current scope.
-              Recurse to search the referenced unit, but without
-              recording it as an inner scoping level.  */
-
-           Dwarf_Attribute attr_mem;
-           Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&child, DW_AT_import,
-                                                       &attr_mem);
-           if (INTUSE(dwarf_formref_die) (attr, &child) != NULL)
-             {
-               int result = find_die (depth, &child, owner, scopes, skip);
-               if (result != 0)
-                 return result;
-             }
-         }
-         break;
-
-       default:
-         break;
-       }
-    }
-  while (INTUSE(dwarf_siblingof) (&child, &child) == 0);
+  assert (a->inlined);
+  if (depth >= a->inlined)
+    /* Not there yet.  */
+    return 0;
 
-  return 0;
+  /* Now we are in a scope that contains the concrete inlined instance.
+     Search it for the inline function's abstract definition.
+     If we don't find it, return to search the containing scope.
+     If we do find it, the nonzero return value will bail us out
+     of the postorder traversal.  */
+  return __libdw_visit_scopes (depth, die, &origin_match, NULL, &a);
 }
 
 
@@ -297,47 +149,16 @@ dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, Dwarf_Die **scopes)
   if (cudie == NULL)
     return -1;
 
-  int n = find_pc (2, cudie, pc, scopes);
-  if (likely (n >= 0))
-    {
-      /* We have a final result.  Now store the outermost scope, the CU.  */
-      (*scopes)[n++] = *cudie;
-      return n;
-    }
-  if (n == -1)
-    return n;
-
-  /* We have the scopes out to one that is a concrete instance of an
-     inlined subroutine (usually DW_TAG_inlined_subroutine, but can
-     be DW_TAG_subprogram for a concrete out-of-line instance).
-     Now we must find the lexical scopes that contain the
-     corresponding abstract inline subroutine definition.  */
-
-  n = -n - 1;
-
-  Dwarf_Attribute attr_mem;
-  Dwarf_Die die_mem;
-  Dwarf_Die *origin = INTUSE(dwarf_formref_die)
-    (INTUSE(dwarf_attr) (&(*scopes)[n - 1], DW_AT_abstract_origin, &attr_mem),
-     &die_mem);
-  if (unlikely (origin == NULL))
-    goto invalid;
-
-  int result = find_die (0, cudie, origin, scopes, n);
-  if (likely (result > 0))
-    {
-      n = n + result - 1;
-      (*scopes)[n++] = *cudie;
-      return n;
-    }
+  struct Dwarf_Die_Chain cu = { .parent = NULL, .die = *cudie };
+  struct args a = { .pc = pc };
 
-  if (result == 0)             /* No match, shouldn't happen.  */
-    {
-    invalid:
-      __libdw_seterrno (DWARF_E_INVALID_DWARF);
-    }
+  int result = __libdw_visit_scopes (0, &cu, &pc_match, &pc_record, &a);
+
+  if (result == 0 && a.scopes != NULL)
+    result = __libdw_visit_scopes (0, &cu, &origin_match, NULL, &a);
+
+  if (result > 0)
+    *scopes = a.scopes;
 
-  free (*scopes);
-  *scopes = NULL;
-  return -1;
+  return result;
 }
diff --git a/libdw/dwarf_getscopes_die.c b/libdw/dwarf_getscopes_die.c
new file mode 100644 (file)
index 0000000..bdcee35
--- /dev/null
@@ -0,0 +1,69 @@
+/* Return scope DIEs 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 "libdwP.h"
+#include <assert.h>
+#include <stdlib.h>
+
+static int
+scope_visitor (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
+{
+  if (die->die.addr != *(void **) arg)
+    return 0;
+
+  Dwarf_Die *scopes = malloc (depth * sizeof scopes[0]);
+  if (scopes == NULL)
+    {
+      __libdw_seterrno (DWARF_E_NOMEM);
+      return -1;
+    }
+
+  unsigned int i = 0;
+  do
+    {
+      scopes[i++] = die->die;
+      die = die->parent;
+    }
+  while (die != NULL);
+  assert (i == depth);
+
+  *(void **) arg = scopes;
+  return depth;
+}
+
+int
+dwarf_getscopes_die (Dwarf_Die *die, Dwarf_Die **scopes)
+{
+  if (die == NULL)
+    return -1;
+
+  struct Dwarf_Die_Chain cu =
+    {
+      .parent = NULL,
+      .die =
+      {
+       .cu = die->cu,
+       .addr = ((char *) die->cu->dbg->sectiondata[IDX_debug_info]->d_buf
+                + die->cu->start + 3 * die->cu->offset_size - 4 + 3),
+      }
+    };
+
+  void *info = die->addr;
+  int result = __libdw_visit_scopes (1, &cu, &scope_visitor, NULL, &info);
+  if (result > 0)
+    *scopes = info;
+  return result;
+}
index e6b3059..350aa44 100644 (file)
@@ -442,6 +442,15 @@ extern int dwarf_addrloclists (Dwarf_Attribute *attr, Dwarf_Addr address,
 extern int dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc,
                            Dwarf_Die **scopes);
 
+/* Return scope DIEs containing the given DIE.
+   Sets *SCOPES to a malloc'd array of Dwarf_Die structures,
+   and returns the number of elements in the array.
+   (*SCOPES)[0] is a copy of DIE.
+   (*SCOPES)[1] is the DIE for the scope containing that scope, and so on.
+   Returns -1 for errors or 0 if DIE is not found in any scope entry.  */
+extern int dwarf_getscopes_die (Dwarf_Die *die, Dwarf_Die **scopes);
+
+
 /* Search SCOPES[0..NSCOPES-1] for a variable called NAME.
    Ignore the first SKIP_SHADOWS scopes that match the name.
    If MATCH_FILE is not null, accept only declaration in that source file;
index 01ee5f6..a5324bd 100644 (file)
@@ -1,5 +1,5 @@
 ELFUTILS_0 { };
-ELFUTILS_0.114 {
+ELFUTILS_0.115 {
   global:
     dwarf_abbrevhaschildren;
     dwarf_addrdie;
@@ -53,6 +53,7 @@ ELFUTILS_0.114 {
     dwarf_getmacros;
     dwarf_getpubnames;
     dwarf_getscopes;
+    dwarf_getscopes_die;
     dwarf_getscopevar;
     dwarf_getscn_info;
     dwarf_getsrc_die;
index 5f15cf9..37f2872 100644 (file)
@@ -343,9 +343,20 @@ extern int __libdw_func_intval (Dwarf_Func *func, int *linep, int attval)
      __nonnull_attribute__ (1, 2) internal_function;
 
 /* Helper function to walk scopes.  */
-extern int __libdw_visit_scopes (unsigned int depth, Dwarf_Die *root,
-                                int (*visit) (unsigned int depth,
-                                              Dwarf_Die *die, void *arg),
+struct Dwarf_Die_Chain
+{
+  Dwarf_Die die;
+  struct Dwarf_Die_Chain *parent;
+  bool prune;                  /* The PREVISIT function can set this.  */
+};
+extern int __libdw_visit_scopes (unsigned int depth,
+                                struct Dwarf_Die_Chain *root,
+                                int (*previsit) (unsigned int depth,
+                                                 struct Dwarf_Die_Chain *,
+                                                 void *arg),
+                                int (*postvisit) (unsigned int depth,
+                                                  struct Dwarf_Die_Chain *,
+                                                  void *arg),
                                 void *arg)
   __nonnull_attribute__ (2, 3) internal_function;
 
@@ -360,6 +371,7 @@ INTDECL (dwarf_attr_integrate)
 INTDECL (dwarf_begin_elf)
 INTDECL (dwarf_child)
 INTDECL (dwarf_dieoffset)
+INTDECL (dwarf_diename)
 INTDECL (dwarf_end)
 INTDECL (dwarf_errmsg)
 INTDECL (dwarf_formaddr)
index 06168fb..3b92ea0 100644 (file)
@@ -46,59 +46,82 @@ classify_die (Dwarf_Die *die)
 }
 
 int
-__libdw_visit_scopes (depth, root, visit, arg)
+__libdw_visit_scopes (depth, root, previsit, postvisit, arg)
      unsigned int depth;
-     Dwarf_Die *root;
-     int (*visit) (unsigned int depth, Dwarf_Die *die, void *arg);
+     struct Dwarf_Die_Chain *root;
+     int (*previsit) (unsigned int depth, struct Dwarf_Die_Chain *, void *);
+     int (*postvisit) (unsigned int depth, struct Dwarf_Die_Chain *, void *);
      void *arg;
 {
-  Dwarf_Die child;
-  if (INTUSE(dwarf_child) (root, &child) != 0)
+  struct Dwarf_Die_Chain child;
+
+  child.parent = root;
+  if (INTUSE(dwarf_child) (&root->die, &child.die) != 0)
     return -1;
 
+  inline int recurse (void)
+    {
+      return __libdw_visit_scopes (depth + 1, &child,
+                                  previsit, postvisit, arg);
+    }
+
   do
     {
-      int result = (*visit) (depth, &child, arg);
-      if (result != DWARF_CB_OK)
-       return result;
+      child.prune = false;
 
-      switch (classify_die (&child))
+      if (previsit != NULL)
        {
-       case match:
-       case match_inline:
-       case walk:
-         if (INTUSE(dwarf_haschildren) (&child))
-           {
-             result = __libdw_visit_scopes (depth + 1, &child, visit, arg);
-             if (result != DWARF_CB_OK)
-               return result;
-           }
-         break;
+         int result = (*previsit) (depth + 1, &child, arg);
+         if (result != DWARF_CB_OK)
+           return result;
+       }
 
-       case imported:
+      if (!child.prune)
+       switch (classify_die (&child.die))
          {
-           /* This is imports another compilation unit to appear
-              as part of this one, inside the current scope.
-              Recurse to searesulth the referenced unit, but without
-              recording it as an inner scoping level.  */
-
-           Dwarf_Attribute attr_mem;
-           Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&child, DW_AT_import,
-                                                       &attr_mem);
-           if (INTUSE(dwarf_formref_die) (attr, &child) != NULL)
+         case match:
+         case match_inline:
+         case walk:
+           if (INTUSE(dwarf_haschildren) (&child.die))
              {
-               result = __libdw_visit_scopes (depth + 1, &child, visit, arg);
-               if (result != 0)
+               int result = recurse ();
+               if (result != DWARF_CB_OK)
                  return result;
              }
+           break;
+
+         case imported:
+           {
+             /* This imports another compilation unit to appear
+                as part of this one, inside the current scope.
+                Recurse to search the referenced unit, but without
+                recording it as an inner scoping level.  */
+
+             Dwarf_Attribute attr_mem;
+             Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&child.die,
+                                                         DW_AT_import,
+                                                         &attr_mem);
+             if (INTUSE(dwarf_formref_die) (attr, &child.die) != NULL)
+               {
+                 int result = recurse ();
+                 if (result != DWARF_CB_OK)
+                   return result;
+               }
+           }
+           break;
+
+         default:
+           break;
          }
-         break;
 
-       default:
-         break;
+      if (postvisit != NULL)
+       {
+         int result = (*postvisit) (depth + 1, &child, arg);
+         if (result != DWARF_CB_OK)
+           return result;
        }
     }
-  while (INTUSE(dwarf_siblingof) (&child, &child) == 0);
+  while (INTUSE(dwarf_siblingof) (&child.die, &child.die) == 0);
 
   return 0;
 }
index 7707ac1..1d485fe 100644 (file)
@@ -1,3 +1,8 @@
+2005-08-27  Roland McGrath  <roland@redhat.com>
+
+       * addr2line.c (dwarf_diename_integrate): Function removed.
+       (print_dwarf_function): Use plain dwarf_diename.
+
 2005-08-24  Ulrich Drepper  <drepper@redhat.com>
 
        * elflint.c (check_versym): Versioned symbols should not have
index 97eaed1..f79dc5f 100644 (file)
@@ -206,13 +206,6 @@ parse_opt (int key, char *arg __attribute__ ((unused)),
 }
 
 
-static const char *
-dwarf_diename_integrate (Dwarf_Die *die)
-{
-  Dwarf_Attribute attr_mem;
-  return dwarf_formstring (dwarf_attr_integrate (die, DW_AT_name, &attr_mem));
-}
-
 static bool
 print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr)
 {
@@ -229,7 +222,7 @@ print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr)
       {
       case DW_TAG_subprogram:
        {
-         const char *name = dwarf_diename_integrate (&scopes[i]);
+         const char *name = dwarf_diename (&scopes[i]);
          if (name == NULL)
            return false;
          puts (name);
@@ -238,7 +231,7 @@ print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr)
 
       case DW_TAG_inlined_subroutine:
        {
-         const char *name = dwarf_diename_integrate (&scopes[i]);
+         const char *name = dwarf_diename (&scopes[i]);
          if (name == NULL)
            return false;
          printf ("%s inlined", name);
index bf58cb5..821d7e5 100644 (file)
@@ -1,3 +1,28 @@
+2005-08-27  Roland McGrath  <roland@redhat.com>
+
+       * run-funcscopes.sh: New file.
+       * testfile25.bz2: New data file.
+       * Makefile.am (TESTS, EXTRA_DIST): Add them.
+
+2005-08-26  Roland McGrath  <roland@redhat.com>
+
+       * addrscopes.c (dwarf_diename_integrate): Removed.
+       (print_vars, handle_address): Use plain dwarf_diename.
+
+2005-08-25  Roland McGrath  <roland@redhat.com>
+
+       * funcscopes.c: New file.
+       * Makefile.am (noinst_PROGRAMS): Add it.
+       (funcscopes_LDADD): New variable.
+
+       * run-addrscopes.sh: Add another case.
+       * testfile24.bz2: New data file.
+       * Makefile.am (EXTRA_DIST): Add it.
+
+       * addrscopes.c (handle_address): Take new argument IGNORE_INLINES,
+       pass it to dwarf_getscopes.
+       (main): Pass it, true when '=' follows an address.
+
 2005-08-24  Roland McGrath  <roland@redhat.com>
 
        * line2addr.c (print_address): Omit () for DSOs.
index b4cc1b0..3b88ff0 100644 (file)
@@ -30,7 +30,7 @@ INCLUDES = -I$(top_srcdir)/libasm -I$(top_srcdir)/libdw \
 noinst_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
                  showptable update1 update2 update3 update4 test-nlist \
                  show-die-info get-files get-lines get-pubnames \
-                 get-aranges allfcts line2addr addrscopes \
+                 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
@@ -47,7 +47,7 @@ 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-addrscopes.sh run-funcscopes.sh
 # run-show-ciefde.sh
 
 EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
@@ -63,14 +63,14 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
             run-strip-test4.sh run-strip-test5.sh run-strip-test6.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-addrscopes.sh run-funcscopes.sh \
             testfile15.bz2 testfile15.debug.bz2 \
             testfile16.bz2 testfile16.debug.bz2 \
             testfile17.bz2 testfile17.debug.bz2 \
             testfile18.bz2 testfile19.bz2 testfile19.index.bz2 \
             testfile20.bz2 testfile20.index.bz2 \
             testfile21.bz2 testfile21.index.bz2 \
-            testfile22.bz2 testfile23.bz2
+            testfile22.bz2 testfile23.bz2 testfile24.bz2 testfile25.bz2
 
 if MUDFLAP
 static_build=yes
@@ -114,6 +114,7 @@ allfcts_LDADD = $(libdw) $(libelf) $(libmudflap)
 line2addr_no_Wformat = yes
 line2addr_LDADD = $(libdw) $(libmudflap)
 addrscopes_LDADD = $(libdw) $(libmudflap)
+funcscopes_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
index 4ef0064..9870175 100644 (file)
@@ -45,13 +45,6 @@ paddr (const char *prefix, Dwarf_Addr addr, Dwfl_Line *line)
     printf ("%s%#" PRIx64, prefix, addr);
 }
 
-static const char *
-dwarf_diename_integrate (Dwarf_Die *die)
-{
-  Dwarf_Attribute attr_mem;
-  return dwarf_formstring (dwarf_attr_integrate (die, DW_AT_name, &attr_mem));
-}
-
 static void
 print_vars (unsigned int indent, Dwarf_Die *die)
 {
@@ -63,7 +56,7 @@ print_vars (unsigned int indent, Dwarf_Die *die)
        case DW_TAG_variable:
        case DW_TAG_formal_parameter:
          printf ("%*s%-30s[%6" PRIx64 "]\n", indent, "",
-                 dwarf_diename_integrate (&child),
+                 dwarf_diename (&child),
                  (uint64_t) dwarf_dieoffset (&child));
          break;
        default:
@@ -83,7 +76,7 @@ print_vars (unsigned int indent, Dwarf_Die *die)
        case DW_TAG_variable:
        case DW_TAG_formal_parameter:
          printf ("%*s%s (abstract)\n", indent, "",
-                 dwarf_diename_integrate (&child));
+                 dwarf_diename (&child));
          break;
        default:
          break;
@@ -118,7 +111,7 @@ handle_address (GElf_Addr pc, Dwfl *dwfl)
 
          indent += INDENT;
          printf ("%*s%s (%#x)", indent, "",
-                 dwarf_diename_integrate (die) ?: "<unnamed>",
+                 dwarf_diename (die) ?: "<unnamed>",
                  dwarf_tag (die));
 
          Dwarf_Addr lowpc, highpc;
diff --git a/tests/funcscopes.c b/tests/funcscopes.c
new file mode 100644 (file)
index 0000000..a74e8d8
--- /dev/null
@@ -0,0 +1,192 @@
+/* Test program for dwarf_getscopes.
+   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>
+
+
+static void
+paddr (const char *prefix, Dwarf_Addr addr, Dwfl_Line *line)
+{
+  const char *src;
+  int lineno, linecol;
+  if (line != NULL
+      && (src = dwfl_lineinfo (line, &addr, &lineno, &linecol,
+                              NULL, NULL)) != NULL)
+    {
+      if (linecol != 0)
+       printf ("%s%#" PRIx64 " (%s:%d:%d)",
+               prefix, addr, src, lineno, linecol);
+      else
+       printf ("%s%#" PRIx64 " (%s:%d)",
+               prefix, addr, src, lineno);
+    }
+  else
+    printf ("%s%#" PRIx64, prefix, addr);
+}
+
+
+static void
+print_vars (unsigned int indent, Dwarf_Die *die)
+{
+  Dwarf_Die child;
+  if (dwarf_child (die, &child) == 0)
+    do
+      switch (dwarf_tag (&child))
+       {
+       case DW_TAG_variable:
+       case DW_TAG_formal_parameter:
+         printf ("%*s%-30s[%6" PRIx64 "]\n", indent, "",
+                 dwarf_diename (&child),
+                 (uint64_t) dwarf_dieoffset (&child));
+         break;
+       default:
+         break;
+       }
+    while (dwarf_siblingof (&child, &child) == 0);
+
+  Dwarf_Attribute attr_mem;
+  Dwarf_Die origin;
+  if (dwarf_hasattr (die, DW_AT_abstract_origin)
+      && dwarf_formref_die (dwarf_attr (die, DW_AT_abstract_origin, &attr_mem),
+                           &origin) != NULL
+      && dwarf_child (&origin, &child) == 0)
+    do
+      switch (dwarf_tag (&child))
+       {
+       case DW_TAG_variable:
+       case DW_TAG_formal_parameter:
+         printf ("%*s%s (abstract)\n", indent, "",
+                 dwarf_diename (&child));
+         break;
+       default:
+         break;
+       }
+    while (dwarf_siblingof (&child, &child) == 0);
+}
+
+
+#define INDENT 4
+
+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);
+
+  Dwarf_Die *scopes;
+  int n = dwarf_getscopes_die (funcdie, &scopes);
+  if (n <= 0)
+    error (EXIT_FAILURE, 0, "dwarf_getscopes_die: %s", dwarf_errmsg (-1));
+  else
+    {
+      Dwarf_Addr start, end;
+      const char *fname;
+      const char *modname = dwfl_module_info (dwfl_cumodule (a->cu), NULL,
+                                             &start, &end,
+                                             NULL, NULL,
+                                             &fname, NULL);
+      if (modname == NULL)
+       error (EXIT_FAILURE, 0, "dwfl_module_info: %s", dwarf_errmsg (-1));
+      if (modname[0] == '\0')
+       modname = fname;
+      printf ("%s: %#" PRIx64 " .. %#" PRIx64 "\n", modname, start, end);
+
+      unsigned int indent = 0;
+      while (n-- > 0)
+       {
+         Dwarf_Die *const die = &scopes[n];
+
+         indent += INDENT;
+         printf ("%*s%s (%#x)", indent, "",
+                 dwarf_diename (die) ?: "<unnamed>",
+                 dwarf_tag (die));
+
+         Dwarf_Addr lowpc, highpc;
+         if (dwarf_lowpc (die, &lowpc) == 0
+             && dwarf_highpc (die, &highpc) == 0)
+           {
+             lowpc += a->dwbias;
+             highpc += a->dwbias;
+             Dwfl_Line *loline = dwfl_getsrc (a->dwfl, lowpc);
+             Dwfl_Line *hiline = dwfl_getsrc (a->dwfl, highpc);
+             paddr (": ", lowpc, loline);
+             if (highpc != lowpc)
+               paddr (" .. ", lowpc, hiline == loline ? NULL : hiline);
+           }
+         puts ("");
+
+         print_vars (indent + INDENT, die);
+       }
+    }
+
+  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;
+}
index 901d02e..57a610b 100755 (executable)
@@ -28,4 +28,22 @@ EOF
 
 rm -f testfile22 addrscopes-test.out
 
+# Don't fail if we cannot decompress the file.
+bunzip2 -c $srcdir/testfile24.bz2 > testfile24 2>/dev/null || exit 0
+
+LD_LIBRARY_PATH=../libdw:../libebl:../libelf${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH \
+  ./addrscopes -e testfile24 0x804834e >& addrscopes-test.out || :
+
+diff -Bbu addrscopes-test.out - <<\EOF
+0x804834e:
+    inline-test.c (0x11): 0x8048348 (/home/roland/build/stock-elfutils/inline-test.c:7) .. 0x8048364 (/home/roland/build/stock-elfutils/inline-test.c:16)
+        add (0x1d): 0x804834e (/home/roland/build/stock-elfutils/inline-test.c:3) .. 0x8048350 (/home/roland/build/stock-elfutils/inline-test.c:9)
+            y                             [    9d]
+            x                             [    a2]
+            x (abstract)
+            y (abstract)
+EOF
+
+rm -f testfile24 addrscopes-test.out
+
 exit 0
diff --git a/tests/run-funcscopes.sh b/tests/run-funcscopes.sh
new file mode 100644 (file)
index 0000000..7236ef9
--- /dev/null
@@ -0,0 +1,30 @@
+#! /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
+
+# Don't fail if we cannot decompress the file.
+bunzip2 -c $srcdir/testfile25.bz2 > testfile25 2>/dev/null || exit 0
+
+LD_LIBRARY_PATH=../libdw:../libebl:../libelf${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH \
+  ./funcscopes -e testfile25 incr >& funcscopes-test.out || :
+
+diff -Bbu funcscopes-test.out - <<\EOF
+testfile25: 0x8048000 .. 0x8049528
+    inline-test.c (0x11): 0x8048348 (/home/roland/build/stock-elfutils/inline-test.c:7) .. 0x804834f (/home/roland/build/stock-elfutils/inline-test.c:9)
+        incr (0x2e): 0x8048348 (/home/roland/build/stock-elfutils/inline-test.c:7) .. 0x804834f (/home/roland/build/stock-elfutils/inline-test.c:9)
+            x                             [    66]
+EOF
+
+rm -f testfile25 funcscopes-test.out
+
+exit 0
diff --git a/tests/testfile24.bz2 b/tests/testfile24.bz2
new file mode 100644 (file)
index 0000000..2320acb
Binary files /dev/null and b/tests/testfile24.bz2 differ
diff --git a/tests/testfile25.bz2 b/tests/testfile25.bz2
new file mode 100644 (file)
index 0000000..51e0421
Binary files /dev/null and b/tests/testfile25.bz2 differ