summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2005-08-27 10:33:26 +0000
committerRoland McGrath <roland@redhat.com>2005-08-27 10:33:26 +0000
commit71e15a01742e5d5de9c6260d4526146be54e5a8a (patch)
tree2796d8ea1fa5580b4e381881314fdad12904635f
parent995f92d7d696930e2cbf08427d028d948e8c5180 (diff)
downloadelfutils-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/ChangeLog22
-rw-r--r--libdw/Makefile.am2
-rw-r--r--libdw/dwarf_diename.c6
-rw-r--r--libdw/dwarf_func_inline.c11
-rw-r--r--libdw/dwarf_func_name.c5
-rw-r--r--libdw/dwarf_getscopes.c383
-rw-r--r--libdw/dwarf_getscopes_die.c69
-rw-r--r--libdw/libdw.h9
-rw-r--r--libdw/libdw.map3
-rw-r--r--libdw/libdwP.h18
-rw-r--r--libdw/libdw_visit_scopes.c93
-rw-r--r--src/ChangeLog5
-rw-r--r--src/addr2line.c11
-rw-r--r--tests/ChangeLog25
-rw-r--r--tests/Makefile.am9
-rw-r--r--tests/addrscopes.c13
-rw-r--r--tests/funcscopes.c192
-rwxr-xr-xtests/run-addrscopes.sh18
-rw-r--r--tests/run-funcscopes.sh30
-rw-r--r--tests/testfile24.bz2bin0 -> 2644 bytes
-rw-r--r--tests/testfile25.bz2bin0 -> 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
new file mode 100644
index 00000000..2320acb3
--- /dev/null
+++ b/tests/testfile24.bz2
Binary files differ
diff --git a/tests/testfile25.bz2 b/tests/testfile25.bz2
new file mode 100644
index 00000000..51e04213
--- /dev/null
+++ b/tests/testfile25.bz2
Binary files differ