summaryrefslogtreecommitdiff
path: root/libdwfl/cu.c
diff options
context:
space:
mode:
authorMark Wielaard <mjw@redhat.com>2015-05-07 18:35:48 +0200
committerMark Wielaard <mjw@redhat.com>2015-05-12 16:54:05 +0200
commitf0855403012fe34aee248353e4435d0b5c6576ef (patch)
treed2a30b4d07c7d6b2719b86dc5441059d62a22fa5 /libdwfl/cu.c
parent281bb49c71665f306b23107cbf821636f59211e0 (diff)
downloadelfutils-f0855403012fe34aee248353e4435d0b5c6576ef.tar.gz
libdwfl: Only intern CU when not EOF marker and cuoff points to a DIE.
We need to check the cuoff points to a real Dwarf_Die before trying to intern the cu with tsearch. Otherwise bogus keys might end up in the search tree with NULL cus. That will cause crashes in compare_cukey during next insertion or deletion of cus. We also don't want to insert the EOF marker and unconditionally tdestroy the lazy_cu_root. The EOF could be caused by bad DWARF from a bogus agranges entry. https://bugzilla.redhat.com/show_bug.cgi?id=1170810#c30 Signed-off-by: Mark Wielaard <mjw@redhat.com>
Diffstat (limited to 'libdwfl/cu.c')
-rw-r--r--libdwfl/cu.c84
1 files changed, 44 insertions, 40 deletions
diff --git a/libdwfl/cu.c b/libdwfl/cu.c
index 3ac341e4..5182054d 100644
--- a/libdwfl/cu.c
+++ b/libdwfl/cu.c
@@ -171,63 +171,67 @@ compare_cukey (const void *a, const void *b)
static Dwfl_Error
intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
{
- struct Dwarf_CU dwkey;
- struct dwfl_cu key;
- key.die.cu = &dwkey;
- dwkey.offset_size = 0;
- dwkey.start = cuoff - (3 * 0 - 4 + 3);
- struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
- if (unlikely (found == NULL))
- return DWFL_E_NOMEM;
-
- if (*found == &key || *found == NULL)
+ if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size))
{
- if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size))
+ if (likely (mod->lazycu == 1))
{
/* This is the EOF marker. Now we have interned all the CUs.
One increment in MOD->lazycu counts not having hit EOF yet. */
- *found = *result = (void *) -1;
+ *result = (void *) -1;
less_lazy (mod);
return DWFL_E_NOERROR;
}
else
{
- /* This is a new entry, meaning we haven't looked at this CU. */
+ /* Unexpected EOF, most likely a bogus aranges. */
+ return (DWFL_E (LIBDW, DWARF_E_INVALID_DWARF));
+ }
+ }
- *found = NULL;
+ /* Make sure the cuoff points to a real DIE. */
+ Dwarf_Die cudie;
+ Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cudie);
+ if (die == NULL)
+ return DWFL_E_LIBDW;
- struct dwfl_cu *cu = malloc (sizeof *cu);
- if (unlikely (cu == NULL))
- return DWFL_E_NOMEM;
+ struct Dwarf_CU dwkey;
+ struct dwfl_cu key;
+ key.die.cu = &dwkey;
+ dwkey.offset_size = 0;
+ dwkey.start = cuoff - (3 * 0 - 4 + 3);
+ struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
+ if (unlikely (found == NULL))
+ return DWFL_E_NOMEM;
- cu->mod = mod;
- cu->next = NULL;
- cu->lines = NULL;
+ if (*found == &key || *found == NULL)
+ {
+ /* This is a new entry, meaning we haven't looked at this CU. */
- /* XXX use non-searching lookup */
- Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cu->die);
- if (die == NULL)
- {
- free (cu);
- return DWFL_E_LIBDW;
- }
- assert (die == &cu->die);
+ *found = NULL;
- struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1)
- * sizeof (mod->cu[0])));
- if (newvec == NULL)
- {
- free (cu);
- return DWFL_E_NOMEM;
- }
- mod->cu = newvec;
+ struct dwfl_cu *cu = malloc (sizeof *cu);
+ if (unlikely (cu == NULL))
+ return DWFL_E_NOMEM;
- mod->cu[mod->ncu++] = cu;
- if (cu->die.cu->start == 0)
- mod->first_cu = cu;
+ cu->mod = mod;
+ cu->next = NULL;
+ cu->lines = NULL;
+ cu->die = cudie;
- *found = cu;
+ struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1)
+ * sizeof (mod->cu[0])));
+ if (newvec == NULL)
+ {
+ free (cu);
+ return DWFL_E_NOMEM;
}
+ mod->cu = newvec;
+
+ mod->cu[mod->ncu++] = cu;
+ if (cu->die.cu->start == 0)
+ mod->first_cu = cu;
+
+ *found = cu;
}
*result = *found;