Fix libdwfl segment table management.
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index f7a3b84..fe3e91e 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,5 +1,9 @@
2010-05-04 Roland McGrath <roland@redhat.com>
+ * segment.c (insert): Fix moving of values following insertion.
+ (reify_segments): Fix up MOD->segment backpointer indices after
+ later insertions in the main loop invalidate them.
+
* link_map.c (dwfl_link_map_report): Detect bias of embedded phdrs and
apply it to PT_DYNAMIC p_vaddr so we handle a PIE correctly.
diff --git a/libdwfl/segment.c b/libdwfl/segment.c
index 36c850f..d39fdab 100644
--- a/libdwfl/segment.c
+++ b/libdwfl/segment.c
@@ -1,5 +1,5 @@
/* Manage address space lookup table for libdwfl.
- Copyright (C) 2008, 2009 Red Hat, Inc.
+ Copyright (C) 2008, 2009, 2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -107,13 +107,14 @@
if (unlikely (i < dwfl->lookup_elts))
{
- memcpy (&dwfl->lookup_addr[i + need], &dwfl->lookup_addr[i],
- need * sizeof dwfl->lookup_addr[0]);
- memcpy (&dwfl->lookup_segndx[i + need], &dwfl->lookup_segndx[i],
- need * sizeof dwfl->lookup_segndx[0]);
+ const size_t move = dwfl->lookup_elts - i;
+ memmove (&dwfl->lookup_addr[i + need], &dwfl->lookup_addr[i],
+ move * sizeof dwfl->lookup_addr[0]);
+ memmove (&dwfl->lookup_segndx[i + need], &dwfl->lookup_segndx[i],
+ move * sizeof dwfl->lookup_segndx[0]);
if (dwfl->lookup_module != NULL)
- memcpy (&dwfl->lookup_module[i + need], &dwfl->lookup_module[i],
- need * sizeof dwfl->lookup_module[0]);
+ memmove (&dwfl->lookup_module[i + need], &dwfl->lookup_module[i],
+ move * sizeof dwfl->lookup_module[0]);
}
if (need_start)
@@ -167,11 +168,14 @@
reify_segments (Dwfl *dwfl)
{
int hint = -1;
+ int highest = -1;
+ bool fixup = false;
for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
if (! mod->gc)
{
const GElf_Addr start = segment_start (dwfl, mod->low_addr);
const GElf_Addr end = segment_end (dwfl, mod->high_addr);
+ bool resized = false;
int idx = lookup (dwfl, start, hint);
if (unlikely (idx < 0))
@@ -180,6 +184,7 @@
if (unlikely (insert (dwfl, 0, start, end, -1)))
return true;
idx = 0;
+ resized = true;
}
else if (dwfl->lookup_addr[idx] > start)
{
@@ -188,6 +193,7 @@
dwfl->lookup_segndx[idx])))
return true;
++idx;
+ resized = true;
}
else if (dwfl->lookup_addr[idx] < start)
{
@@ -196,14 +202,18 @@
if (unlikely (insert (dwfl, idx + 1, start, end, -1)))
return true;
++idx;
+ resized = true;
}
if ((size_t) idx + 1 < dwfl->lookup_elts
- && end < dwfl->lookup_addr[idx + 1]
+ && end < dwfl->lookup_addr[idx + 1])
+ {
/* The module ends in the middle of this segment. Split it. */
- && unlikely (insert (dwfl, idx + 1,
- end, dwfl->lookup_addr[idx + 1], -1)))
- return true;
+ if (unlikely (insert (dwfl, idx + 1,
+ end, dwfl->lookup_addr[idx + 1], -1)))
+ return true;
+ resized = true;
+ }
if (dwfl->lookup_module == NULL)
{
@@ -221,9 +231,23 @@
dwfl->lookup_module[idx++] = mod;
while ((size_t) idx < dwfl->lookup_elts
&& dwfl->lookup_addr[idx] < end);
+ assert (dwfl->lookup_module[mod->segment] == mod);
+
+ if (resized && idx - 1 >= highest)
+ /* Expanding the lookup tables invalidated backpointers
+ we've already stored. Reset those ones. */
+ fixup = true;
+
+ highest = idx - 1;
hint = (size_t) idx < dwfl->lookup_elts ? idx : -1;
}
+ if (fixup)
+ /* Reset backpointer indices invalidated by table insertions. */
+ for (size_t idx = 0; idx < dwfl->lookup_elts; ++idx)
+ if (dwfl->lookup_module[idx] != NULL)
+ dwfl->lookup_module[idx]->segment = idx;
+
return false;
}