This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
[RFA] Perform relocations in dwarf2.c
- From: Michal Ludvig <mludvig at suse dot cz>
- To: binutils at sources dot redhat dot com
- Date: Thu, 24 Oct 2002 02:45:05 +0200
- Subject: [RFA] Perform relocations in dwarf2.c
- Organization: SuSE CR
Hi all,
when running following command:
$ objdump -S something.o
on rela-type dwarf2 platforms it didn't show source lines, because
_bfd_dwarf2_find_nearest_line() didn't perform relocations of symbols
and thus returned wrong results.
Also there was a problem when parsing .debug_info on 64b paltforms - as
far as I have seen, offsets in this section are always 32b (and
specification says it as well), regardless whether on 64b or on 32b
platform. There was some strange magic in
_bfd_dwarf2_find_nearest_line() to find out the right offset size, but
it didn't work anyway.
Can someone approve or comment it, please?
Michal Ludvig
--
* SuSE CR, s.r.o * mludvig@suse.cz
* (+420) 296.545.373 * http://www.suse.cz
2002-10-24 Michal Ludvig <mludvig@suse.cz>
* dwarf2.c (read_indirect_string, read_attribute,
read_attribute_value): Added parameter relp, changed prototype,
added handling of relocations.
(parse_comp_unit): Added handling of RELA relocations.
Index: dwarf2.c
===================================================================
RCS file: /cvs/src/src/bfd/dwarf2.c,v
retrieving revision 1.37
diff -u -p -r1.37 dwarf2.c
--- dwarf2.c 23 Oct 2002 12:41:32 -0000 1.37
+++ dwarf2.c 24 Oct 2002 00:18:07 -0000
@@ -216,7 +216,8 @@ static unsigned int read_4_bytes PARAMS
static bfd_vma read_8_bytes PARAMS ((bfd *, char *));
static char *read_n_bytes PARAMS ((bfd *, char *, unsigned int));
static char *read_string PARAMS ((bfd *, char *, unsigned int *));
-static char *read_indirect_string PARAMS ((struct comp_unit *, char *, unsigned int *));
+static char *read_indirect_string PARAMS ((struct comp_unit *,
+ char *, unsigned int *, arelent *));
static unsigned int read_unsigned_leb128
PARAMS ((bfd *, char *, unsigned int *));
static int read_signed_leb128
@@ -228,10 +229,10 @@ static struct abbrev_info **read_abbrevs
PARAMS ((bfd *, bfd_vma, struct dwarf2_debug *));
static char *read_attribute
PARAMS ((struct attribute *, struct attr_abbrev *,
- struct comp_unit *, char *));
+ struct comp_unit *, char *, arelent *));
static char *read_attribute_value
PARAMS ((struct attribute *, unsigned,
- struct comp_unit *, char *));
+ struct comp_unit *, char *, arelent *));
static void add_line_info
PARAMS ((struct line_info_table *, bfd_vma, char *,
unsigned int, unsigned int, int));
@@ -356,10 +357,11 @@ read_string (abfd, buf, bytes_read_ptr)
}
static char *
-read_indirect_string (unit, buf, bytes_read_ptr)
+read_indirect_string (unit, buf, bytes_read_ptr, relp)
struct comp_unit* unit;
char *buf;
unsigned int *bytes_read_ptr;
+ arelent *relp;
{
bfd_vma offset;
struct dwarf2_debug *stash = unit->stash;
@@ -369,6 +371,7 @@ read_indirect_string (unit, buf, bytes_r
else
offset = read_8_bytes (unit->abfd, buf);
*bytes_read_ptr = unit->offset_size;
+ if (relp) offset += relp->addend;
if (! stash->dwarf_str_buffer)
{
@@ -635,11 +638,12 @@ read_abbrevs (abfd, offset, stash)
/* Read an attribute value described by an attribute form. */
static char *
-read_attribute_value (attr, form, unit, info_ptr)
+read_attribute_value (attr, form, unit, info_ptr, relp)
struct attribute *attr;
unsigned form;
struct comp_unit *unit;
char *info_ptr;
+ arelent *relp;
{
bfd *abfd = unit->abfd;
unsigned int bytes_read;
@@ -654,6 +658,7 @@ read_attribute_value (attr, form, unit,
/* FIXME: DWARF3 draft sais DW_FORM_ref_addr is offset_size. */
case DW_FORM_ref_addr:
DW_ADDR (attr) = read_address (unit, info_ptr);
+ if (relp) DW_ADDR (attr) += relp->addend;
info_ptr += unit->addr_size;
break;
case DW_FORM_block2:
@@ -691,7 +696,7 @@ read_attribute_value (attr, form, unit,
info_ptr += bytes_read;
break;
case DW_FORM_strp:
- DW_STRING (attr) = read_indirect_string (unit, info_ptr, &bytes_read);
+ DW_STRING (attr) = read_indirect_string (unit, info_ptr, &bytes_read, relp);
info_ptr += bytes_read;
break;
case DW_FORM_block:
@@ -751,7 +756,7 @@ read_attribute_value (attr, form, unit,
case DW_FORM_indirect:
form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
- info_ptr = read_attribute_value (attr, form, unit, info_ptr);
+ info_ptr = read_attribute_value (attr, form, unit, info_ptr, relp);
break;
default:
(*_bfd_error_handler) (_("Dwarf Error: Invalid or unhandled FORM value: %u."),
@@ -764,14 +769,15 @@ read_attribute_value (attr, form, unit,
/* Read an attribute described by an abbreviated attribute. */
static char *
-read_attribute (attr, abbrev, unit, info_ptr)
+read_attribute (attr, abbrev, unit, info_ptr, relp)
struct attribute *attr;
struct attr_abbrev *abbrev;
struct comp_unit *unit;
char *info_ptr;
+ arelent *relp;
{
attr->name = abbrev->name;
- info_ptr = read_attribute_value (attr, abbrev->form, unit, info_ptr);
+ info_ptr = read_attribute_value (attr, abbrev->form, unit, info_ptr, relp);
return info_ptr;
}
@@ -1465,7 +1471,9 @@ scan_unit_for_functions (unit)
for (i = 0; i < abbrev->num_attrs; ++i)
{
- info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr);
+ info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr,
+ /* NULL? FIXME - we may need to do some relocations... */
+ NULL);
if (func)
{
@@ -1599,6 +1607,11 @@ parse_comp_unit (abfd, stash, unit_lengt
char *end_ptr = info_ptr + unit_length;
bfd_size_type amt;
bfd_size_type off;
+
+ asection *a = stash->sec;
+ asymbol **syms = stash->syms;
+ arelent **relpp = NULL, *relp;
+ int relsize, relcount=0, relindex;
version = read_2_bytes (abfd, info_ptr);
info_ptr += 2;
@@ -1664,6 +1677,18 @@ parse_comp_unit (abfd, stash, unit_lengt
return 0;
}
+ if(a->flags & SEC_RELOC)
+ {
+ relsize = bfd_get_reloc_upper_bound (abfd, a);
+ if (relsize > 0)
+ {
+ relpp = (arelent **) xmalloc (relsize);
+ relcount = bfd_canonicalize_reloc (abfd, a, relpp, syms);
+ if (relcount < 0)
+ return NULL;
+ }
+ }
+
amt = sizeof (struct comp_unit);
unit = (struct comp_unit*) bfd_zalloc (abfd, amt);
unit->abfd = abfd;
@@ -1673,9 +1698,20 @@ parse_comp_unit (abfd, stash, unit_lengt
unit->end_ptr = end_ptr;
unit->stash = stash;
+ relindex = 0;
for (i = 0; i < abbrev->num_attrs; ++i)
{
- info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr);
+ unsigned long xoffset = info_ptr - stash->info_ptr + offset_size;
+
+ if (relpp)
+ for (; relindex < relcount && relpp && relpp[relindex] &&
+ relpp[relindex]->address < xoffset;
+ relindex++) /* Do nothing, just find the right record */;
+
+ relp = (relpp && relpp[relindex] && relpp[relindex]->address == xoffset) ?
+ relpp[relindex] : NULL;
+
+ info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr, relp);
/* Store the data if it is of an attribute we want to keep in a
partial symbol table. */
@@ -1949,21 +1985,6 @@ _bfd_dwarf2_find_nearest_line (abfd, sec
stash->syms = symbols;
}
- /* FIXME: There is a problem with the contents of the
- .debug_info section. The 'low' and 'high' addresses of the
- comp_units are computed by relocs against symbols in the
- .text segment. We need these addresses in order to determine
- the nearest line number, and so we have to resolve the
- relocs. There is a similar problem when the .debug_line
- section is processed as well (e.g., there may be relocs
- against the operand of the DW_LNE_set_address operator).
-
- Unfortunately getting hold of the reloc information is hard...
-
- For now, this means that disassembling object files (as
- opposed to fully executables) does not always work as well as
- we would like. */
-
/* A null info_ptr indicates that there is no dwarf2 info
(or that an error occured while setting up the stash). */
if (! stash->info_ptr)
@@ -1981,28 +2002,14 @@ _bfd_dwarf2_find_nearest_line (abfd, sec
{
bfd_vma length;
boolean found;
- unsigned int offset_size = addr_size;
-
- if (addr_size == 4)
- {
- length = read_4_bytes (abfd, stash->info_ptr);
- if (length == 0xffffffff)
- {
- offset_size = 8;
- length = read_8_bytes (abfd, stash->info_ptr + 4);
- stash->info_ptr += 8;
- }
- else if (length == 0)
- {
- /* Handle (non-standard) 64-bit DWARF2 formats. */
- offset_size = 8;
- length = read_4_bytes (abfd, stash->info_ptr + 4);
- stash->info_ptr += 4;
- }
- }
- else
- length = read_8_bytes (abfd, stash->info_ptr);
- stash->info_ptr += addr_size;
+ /* All checked 64b platforms use 32b offsets in .debug_info.
+ * 32b platforms use this size as well, of course. Seems to be
+ * safe to hardcode it here.
+ * Checked on x86-64, alpha, ia64, sparc64 -- mludvig */
+ unsigned int offset_size = 4;
+
+ length = read_4_bytes (abfd, stash->info_ptr);
+ stash->info_ptr += offset_size;
if (length > 0)
{
Index: elf.c
===================================================================
RCS file: /cvs/src/src/bfd/elf.c,v
retrieving revision 1.164
diff -u -p -r1.164 elf.c
--- elf.c 19 Oct 2002 13:52:58 -0000 1.164
+++ elf.c 24 Oct 2002 00:18:08 -0000
@@ -6030,7 +6030,7 @@ _bfd_elf_find_nearest_line (abfd, sectio
if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
filename_ptr, functionname_ptr,
- line_ptr, 0,
+ line_ptr, get_elf_backend_data(abfd)->s->arch_size/8,
&elf_tdata (abfd)->dwarf2_find_line_info))
{
if (!*functionname_ptr)