This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: PATCH: PR ld/3191: Linker failed to handle DW_FORM_ref_addr properly
On Wed, Sep 27, 2006 at 05:21:15PM -0700, Jim Wilson wrote:
> On Thu, 2006-09-21 at 08:03 -0700, H. J. Lu wrote:
> > PR ld/3191
> > * dwarf2.c (_bfd_dwarf2_find_nearest_line): Adjust debug_info
> > section vma when needed.
>
> I'm willing to review a patch for this bug report, but I am still unable
> to reproduce the bug, same as last week. I tried the object files in
> the bug report, but I can't get them to fail. I also went so far as to
> try to build kdesvn, but gave up because it required too many other
> unfamiliar packages.
>
Jim, can you reproduce the problem with the new testcase? We didn't
handle DW_FORM_ref_addr properly. DW_FORM_ref_addr should be the
offset from the .debug_info section in the target file. This patch
fixes the testcase. But I don't know how to handle DW_FORM_ref_addr
references an entry in a different file.
H.J.
--
2006-09-29 H.J. Lu <hongjiu.lu@intel.com>
PR ld/3191
* dwarf2.c (find_abstract_instance_name): Pass a pointer to
attribute instead of offset. For DW_FORM_ref_addr, get the
entry at the offset from the .debug_info section.
(scan_unit_for_symbols): Updated.
(_bfd_dwarf2_find_nearest_line): Adjust debug_info
section vma when needed.
--- bfd/dwarf2.c.ref_addr 2006-09-21 13:55:25.000000000 -0700
+++ bfd/dwarf2.c 2006-09-29 10:07:14.000000000 -0700
@@ -1556,16 +1556,30 @@ lookup_symbol_in_variable_table (struct
}
static char *
-find_abstract_instance_name (struct comp_unit *unit, bfd_uint64_t die_ref)
+find_abstract_instance_name (struct comp_unit *unit,
+ struct attribute *attr_ptr)
{
bfd *abfd = unit->abfd;
bfd_byte *info_ptr;
unsigned int abbrev_number, bytes_read, i;
struct abbrev_info *abbrev;
+ bfd_uint64_t die_ref = attr_ptr->u.val;
struct attribute attr;
char *name = 0;
- info_ptr = unit->info_ptr_unit + die_ref;
+ /* DW_FORM_ref_addr can reference an entry in a different CU. It
+ is an offset from the .debug_info section, not the current CU. */
+ if (attr_ptr->form == DW_FORM_ref_addr)
+ {
+ /* FIXME: How to handle DW_FORM_ref_addr references an entry in
+ a different file? */
+ if (!die_ref)
+ abort ();
+
+ info_ptr = unit->stash->sec_info_ptr + die_ref;
+ }
+ else
+ info_ptr = unit->info_ptr_unit + die_ref;
abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
@@ -1591,7 +1605,7 @@ find_abstract_instance_name (struct comp
name = attr.u.str;
break;
case DW_AT_specification:
- name = find_abstract_instance_name (unit, attr.u.val);
+ name = find_abstract_instance_name (unit, &attr);
break;
case DW_AT_MIPS_linkage_name:
name = attr.u.str;
@@ -1751,7 +1765,7 @@ scan_unit_for_symbols (struct comp_unit
break;
case DW_AT_abstract_origin:
- func->name = find_abstract_instance_name (unit, attr.u.val);
+ func->name = find_abstract_instance_name (unit, &attr);
break;
case DW_AT_name:
@@ -2375,6 +2389,11 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd
{
bfd_size_type total_size;
asection *msec;
+ bfd_vma last_vma;
+ bfd_size_type size;
+ asection *first_msec;
+ asection **msecs = NULL;
+ unsigned int i, count;
*pinfo = stash;
@@ -2389,9 +2408,28 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd
Read them all in and produce one large stash. We do this in two
passes - in the first pass we just accumulate the section sizes.
In the second pass we read in the section's contents. The allows
- us to avoid reallocing the data as we add sections to the stash. */
+ us to avoid reallocing the data as we add sections to the stash.
+
+ We may need to adjust debug_info section vmas since we will
+ concatenate them together. Otherwise relocations may be
+ incorrect. */
+ first_msec = msec;
+ last_vma = 0;
+ count = 0;
for (total_size = 0; msec; msec = find_debug_info (abfd, msec))
- total_size += msec->size;
+ {
+ size = msec->size;
+ if (size == 0)
+ continue;
+
+ total_size += size;
+
+ BFD_ASSERT (msec->vma == 0 && msec->alignment_power == 0);
+
+ msec->vma = last_vma;
+ last_vma += size;
+ count++;
+ }
stash->info_ptr = bfd_alloc (abfd, total_size);
if (stash->info_ptr == NULL)
@@ -2399,17 +2437,27 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd
stash->info_ptr_end = stash->info_ptr;
- for (msec = find_debug_info (abfd, NULL);
+ if (count > 1)
+ {
+ count--;
+ msecs = (asection **) bfd_malloc2 (count, sizeof (*msecs));
+ }
+
+ for (i = 0, msec = first_msec;
msec;
msec = find_debug_info (abfd, msec))
{
- bfd_size_type size;
bfd_size_type start;
size = msec->size;
if (size == 0)
continue;
+ if (i && msecs)
+ msecs [i - 1] = msec;
+
+ i++;
+
start = stash->info_ptr_end - stash->info_ptr;
if ((bfd_simple_get_relocated_section_contents
@@ -2419,9 +2467,27 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd
stash->info_ptr_end = stash->info_ptr + start + size;
}
+ /* Restore section vma. */
+ if (count)
+ {
+ if (msecs)
+ {
+ for (i = 0; i < count; i++)
+ msecs [i]->vma = 0;
+ free (msecs);
+ }
+ else
+ {
+ for (msec = find_debug_info (abfd, first_msec);
+ msec;
+ msec = find_debug_info (abfd, msec))
+ msec->vma = 0;
+ }
+ }
+
BFD_ASSERT (stash->info_ptr_end == stash->info_ptr + total_size);
- stash->sec = find_debug_info (abfd, NULL);
+ stash->sec = first_msec;
stash->sec_info_ptr = stash->info_ptr;
stash->syms = symbols;
}