diff options
author | Roland McGrath <roland@redhat.com> | 2005-08-27 10:33:26 +0000 |
---|---|---|
committer | Roland McGrath <roland@redhat.com> | 2005-08-27 10:33:26 +0000 |
commit | 71e15a01742e5d5de9c6260d4526146be54e5a8a (patch) | |
tree | 2796d8ea1fa5580b4e381881314fdad12904635f | |
parent | 995f92d7d696930e2cbf08427d028d948e8c5180 (diff) | |
download | elfutils-71e15a01742e5d5de9c6260d4526146be54e5a8a.tar.gz |
libdw/
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.
-rw-r--r-- | libdw/ChangeLog | 22 | ||||
-rw-r--r-- | libdw/Makefile.am | 2 | ||||
-rw-r--r-- | libdw/dwarf_diename.c | 6 | ||||
-rw-r--r-- | libdw/dwarf_func_inline.c | 11 | ||||
-rw-r--r-- | libdw/dwarf_func_name.c | 5 | ||||
-rw-r--r-- | libdw/dwarf_getscopes.c | 383 | ||||
-rw-r--r-- | libdw/dwarf_getscopes_die.c | 69 | ||||
-rw-r--r-- | libdw/libdw.h | 9 | ||||
-rw-r--r-- | libdw/libdw.map | 3 | ||||
-rw-r--r-- | libdw/libdwP.h | 18 | ||||
-rw-r--r-- | libdw/libdw_visit_scopes.c | 93 | ||||
-rw-r--r-- | src/ChangeLog | 5 | ||||
-rw-r--r-- | src/addr2line.c | 11 | ||||
-rw-r--r-- | tests/ChangeLog | 25 | ||||
-rw-r--r-- | tests/Makefile.am | 9 | ||||
-rw-r--r-- | tests/addrscopes.c | 13 | ||||
-rw-r--r-- | tests/funcscopes.c | 192 | ||||
-rwxr-xr-x | tests/run-addrscopes.sh | 18 | ||||
-rw-r--r-- | tests/run-funcscopes.sh | 30 | ||||
-rw-r--r-- | tests/testfile24.bz2 | bin | 0 -> 2644 bytes | |||
-rw-r--r-- | tests/testfile25.bz2 | bin | 0 -> 2575 bytes |
21 files changed, 569 insertions, 355 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 3b84ab9e..fcae4422 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -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 diff --git a/libdw/Makefile.am b/libdw/Makefile.am index ad6b28a1..264e4784 100644 --- a/libdw/Makefile.am +++ b/libdw/Makefile.am @@ -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 \ diff --git a/libdw/dwarf_diename.c b/libdw/dwarf_diename.c index 41d763c5..daef5fbd 100644 --- a/libdw/dwarf_diename.c +++ b/libdw/dwarf_diename.c @@ -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) diff --git a/libdw/dwarf_func_inline.c b/libdw/dwarf_func_inline.c index 7656286f..4472515d 100644 --- a/libdw/dwarf_func_inline.c +++ b/libdw/dwarf_func_inline.c @@ -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); } diff --git a/libdw/dwarf_func_name.c b/libdw/dwarf_func_name.c index 4151c359..c6912aa6 100644 --- a/libdw/dwarf_func_name.c +++ b/libdw/dwarf_func_name.c @@ -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); } diff --git a/libdw/dwarf_getscopes.c b/libdw/dwarf_getscopes.c index 7863036b..2d5345ed 100644 --- a/libdw/dwarf_getscopes.c +++ b/libdw/dwarf_getscopes.c @@ -15,279 +15,131 @@ # 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 index 00000000..bdcee354 --- /dev/null +++ b/libdw/dwarf_getscopes_die.c @@ -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; +} diff --git a/libdw/libdw.h b/libdw/libdw.h index e6b30597..350aa440 100644 --- a/libdw/libdw.h +++ b/libdw/libdw.h @@ -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; diff --git a/libdw/libdw.map b/libdw/libdw.map index 01ee5f60..a5324bd1 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -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; diff --git a/libdw/libdwP.h b/libdw/libdwP.h index 5f15cf9d..37f28721 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -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) diff --git a/libdw/libdw_visit_scopes.c b/libdw/libdw_visit_scopes.c index 06168fb1..3b92ea09 100644 --- a/libdw/libdw_visit_scopes.c +++ b/libdw/libdw_visit_scopes.c @@ -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; } diff --git a/src/ChangeLog b/src/ChangeLog index 7707ac17..1d485fe6 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -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 diff --git a/src/addr2line.c b/src/addr2line.c index 97eaed10..f79dc5f3 100644 --- a/src/addr2line.c +++ b/src/addr2line.c @@ -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); diff --git a/tests/ChangeLog b/tests/ChangeLog index bf58cb5a..821d7e54 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -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. diff --git a/tests/Makefile.am b/tests/Makefile.am index b4cc1b04..3b88ff09 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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 diff --git a/tests/addrscopes.c b/tests/addrscopes.c index 4ef00648..9870175c 100644 --- a/tests/addrscopes.c +++ b/tests/addrscopes.c @@ -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 index 00000000..a74e8d87 --- /dev/null +++ b/tests/funcscopes.c @@ -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; +} diff --git a/tests/run-addrscopes.sh b/tests/run-addrscopes.sh index 901d02e1..57a610b8 100755 --- a/tests/run-addrscopes.sh +++ b/tests/run-addrscopes.sh @@ -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 index 00000000..7236ef91 --- /dev/null +++ b/tests/run-funcscopes.sh @@ -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 Binary files differnew file mode 100644 index 00000000..2320acb3 --- /dev/null +++ b/tests/testfile24.bz2 diff --git a/tests/testfile25.bz2 b/tests/testfile25.bz2 Binary files differnew file mode 100644 index 00000000..51e04213 --- /dev/null +++ b/tests/testfile25.bz2 |