This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: PATCH: ld/2338: objdump -d -l doesn't work correctly
- From: "H. J. Lu" <hjl at lucon dot org>
- To: Eric Botcazou <ebotcazou at adacore dot com>, binutils at sourceware dot org
- Date: Fri, 3 Mar 2006 09:46:39 -0800
- Subject: Re: PATCH: ld/2338: objdump -d -l doesn't work correctly
- References: <20060228044341.GM7365@bubble.grove.modra.org> <20060228052156.GA4218@lucon.org> <20060228072903.GN7365@bubble.grove.modra.org> <20060228171441.GA9154@lucon.org> <20060228182352.GA9662@lucon.org> <20060228185053.GA1056@nevyn.them.org> <20060228194138.GA10210@lucon.org> <20060303024209.GB6777@bubble.grove.modra.org> <20060303051635.GA1077@lucon.org> <20060303081411.GD6777@bubble.grove.modra.org>
On Fri, Mar 03, 2006 at 06:44:11PM +1030, Alan Modra wrote:
> On Thu, Mar 02, 2006 at 09:16:35PM -0800, H. J. Lu wrote:
> > On Fri, Mar 03, 2006 at 01:12:09PM +1030, Alan Modra wrote:
> > > On Tue, Feb 28, 2006 at 11:41:38AM -0800, H. J. Lu wrote:
> > > > @@ -803,6 +815,15 @@ add_line_info (struct line_info_table *t
> > > > {
> > > > /* Abnormal but easy: lcl_head is 1) in the *middle* of the line
> > > > list and 2) the head of 'info'. */
> > > > + if (address == table->lcl_head->prev_line->address
> > > > + && end_sequence != 0
> > > > + && table->lcl_head->end_sequence != 0
> > > > + && table->lcl_head->prev_line->end_sequence == 0)
> > > > + {
> > > > + /* If the new adress is the same, we need to make sure that
> > > > + the order of end_sequence is correct. */
> > > > + table->lcl_head = table->lcl_head->prev_line;
> > > > + }
> > > > info->prev_line = table->lcl_head->prev_line;
> > > > table->lcl_head->prev_line = info;
> > > > break;
> > >
> > > Convince me that this is correct. ie. that you have actually done some
> > > analysis and that this is the only place in add_line_info that needs to
> > > do something special with end_sequence.
> >
> > We can only 2 lines pointing to the same address: one is end_sequence
> > and the other isn't. That is the only place where it can happen.
>
> "That is the only place where it can happen" isn't good enough. You are
> just making an assertion. Prove it.
>
> Yes, I can probably analyse add_line_info myself, and decide whether
> your patch is correct. This requires some work on my part, and, it's
> duplicating effort you have already made if you have done the analysis.
> Of course, if you haven't properly analysed the function yourself, then
> it's likely that your patch is wrong or incomplete.
>
We need to check end_sequence when we compare line addresses. I added
compare_line_address to do that. Here is the new patch.
H.J.
---
2006-03-03 H.J. Lu <hongjiu.lu@intel.com>
PR binutils/2338
* dwarf2.c (loadable_section): New struct.
(dwarf2_debug): Add loadable_section_count and
loadable_sections.
(compare_line_address): New.
(add_line_info): Use compare_line_address to compare line
addresses.
(check_function_name): Removed.
(unset_sections): New.
(place_sections): New.
(_bfd_dwarf2_find_nearest_line): Updated. Call place_sections
and unset_sections on relocatable files.
(_bfd_dwarf2_find_line): Likewise.
--- bfd/dwarf2.c.rel 2006-02-16 10:08:05.000000000 -0800
+++ bfd/dwarf2.c 2006-03-03 09:41:57.000000000 -0800
@@ -74,6 +74,12 @@ struct dwarf_block
bfd_byte *data;
};
+struct loadable_section
+{
+ asection *section;
+ bfd_vma adj_vma;
+};
+
struct dwarf2_debug
{
/* A list of all previously read comp_units. */
@@ -124,6 +130,12 @@ struct dwarf2_debug
calling chain for subsequent calls to bfd_find_inliner_info to
use. */
struct funcinfo *inliner_chain;
+
+ /* Number of loadable sections. */
+ unsigned int loadable_section_count;
+
+ /* Array of loadable sections. */
+ struct loadable_section *loadable_sections;
};
struct arange
@@ -744,6 +756,25 @@ struct varinfo
unsigned int stack: 1;
};
+/* 2 lines can have the same address. But their end_sequence values
+ must be different. The one with end_sequence != 0 will never be
+ reached. The one with end_sequence == 0 is real. */
+
+static bfd_boolean
+compare_line_address (bfd_vma address, int end_sequence,
+ struct line_info *line)
+{
+ if (address == line->address && end_sequence == line->end_sequence)
+ /* FIXME: Will we ever get here? */
+ abort ();
+ else if (address > line->address
+ || (address == line->address
+ && end_sequence < line->end_sequence))
+ return 1;
+ else
+ return -1;
+}
+
/* Adds a new entry to the line_info list in the line_info_table, ensuring
that the list is sorted. Note that the line_info list is sorted from
highest to lowest VMA (with possible duplicates); that is,
@@ -777,7 +808,8 @@ add_line_info (struct line_info_table *t
while (1)
if (!table->last_line
- || address >= table->last_line->address)
+ || compare_line_address (address, end_sequence,
+ table->last_line) > 0)
{
/* Normal case: add 'info' to the beginning of the list */
info->prev_line = table->last_line;
@@ -789,7 +821,8 @@ add_line_info (struct line_info_table *t
break;
}
else if (!table->lcl_head->prev_line
- && table->lcl_head->address > address)
+ && compare_line_address (address, end_sequence,
+ table->lcl_head) < 0)
{
/* Abnormal but easy: lcl_head is 1) at the *end* of the line
list and 2) the head of 'info'. */
@@ -798,8 +831,10 @@ add_line_info (struct line_info_table *t
break;
}
else if (table->lcl_head->prev_line
- && table->lcl_head->address > address
- && address >= table->lcl_head->prev_line->address)
+ && compare_line_address (address, end_sequence,
+ table->lcl_head) < 0
+ && compare_line_address (address, end_sequence,
+ table->lcl_head->prev_line) > 0)
{
/* Abnormal but easy: lcl_head is 1) in the *middle* of the line
list and 2) the head of 'info'. */
@@ -816,7 +851,9 @@ add_line_info (struct line_info_table *t
while (li1)
{
- if (li2->address > address && address >= li1->address)
+ if (compare_line_address (address, end_sequence, li2) < 0
+ && compare_line_address (address, end_sequence,
+ li1) > 0)
break;
li2 = li1; /* always non-NULL */
@@ -2179,28 +2216,91 @@ find_debug_info (bfd *abfd, asection *af
return NULL;
}
-/* Return TRUE if there is no mismatch bewteen function FUNC and
- section SECTION from symbol table SYMBOLS in ABFD. */
+/* Unset vmas for loadable sections in STASH. */
+
+static void
+unset_sections (struct dwarf2_debug *stash)
+{
+ unsigned int i;
+ struct loadable_section *p;
+
+ i = stash->loadable_section_count;
+ p = stash->loadable_sections;
+ for (; i > 0; i--, p++)
+ p->section->vma = 0;
+}
+
+/* Set unique vmas for loadable sections in ABFD and save vmas in
+ STASH for unset_sections. */
static bfd_boolean
-check_function_name (bfd *abfd, asection *section, asymbol **symbols,
- const char *func)
+place_sections (bfd *abfd, struct dwarf2_debug *stash)
{
- /* Mismatch can only happen when we have 2 functions with the same
- address. It can only occur in a relocatable file. */
- if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0
- && func != NULL
- && section != NULL
- && symbols != NULL)
- {
- asymbol **p;
-
- for (p = symbols; *p != NULL; p++)
- {
- if (((*p)->flags & BSF_FUNCTION) != 0
- && (*p)->name != NULL
- && strcmp ((*p)->name, func) == 0)
- return (*p)->section == section;
+ struct loadable_section *p;
+ unsigned int i;
+
+ if (stash->loadable_section_count != 0)
+ {
+ i = stash->loadable_section_count;
+ p = stash->loadable_sections;
+ for (; i > 0; i--, p++)
+ p->section->vma = p->adj_vma;
+ }
+ else
+ {
+ asection *sect;
+ bfd_vma last_vma = 0;
+ bfd_size_type amt;
+ struct loadable_section *p;
+
+ i = 0;
+ for (sect = abfd->sections; sect != NULL; sect = sect->next)
+ {
+ bfd_size_type sz;
+
+ if (sect->vma != 0 || (sect->flags & SEC_LOAD) == 0)
+ continue;
+
+ sz = sect->rawsize ? sect->rawsize : sect->size;
+ if (sz == 0)
+ continue;
+
+ i++;
+ }
+
+ amt = i * sizeof (struct loadable_section);
+ p = (struct loadable_section *) bfd_zalloc (abfd, amt);
+ if (! p)
+ return FALSE;
+
+ stash->loadable_sections = p;
+ stash->loadable_section_count = i;
+
+ for (sect = abfd->sections; sect != NULL; sect = sect->next)
+ {
+ bfd_size_type sz;
+
+ if (sect->vma != 0 || (sect->flags & SEC_LOAD) == 0)
+ continue;
+
+ sz = sect->rawsize ? sect->rawsize : sect->size;
+ if (sz == 0)
+ continue;
+
+ p->section = sect;
+ if (last_vma != 0)
+ {
+ /* Align the new address to the current section
+ alignment. */
+ last_vma = ((last_vma
+ + ~((bfd_vma) -1 << sect->alignment_power))
+ & ((bfd_vma) -1 << sect->alignment_power));
+ sect->vma = last_vma;
+ }
+ p->adj_vma = sect->vma;
+ last_vma += sect->vma + sz;
+
+ p++;
}
}
@@ -2239,7 +2339,27 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd
struct comp_unit* each;
+ bfd_vma found = FALSE;
+
stash = *pinfo;
+
+ if (! stash)
+ {
+ bfd_size_type amt = sizeof (struct dwarf2_debug);
+
+ stash = bfd_zalloc (abfd, amt);
+ if (! stash)
+ return FALSE;
+ }
+
+ /* In a relocatable file, 2 functions may have the same address.
+ We change the section vma so that they won't overlap. */
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+ {
+ if (! place_sections (abfd, stash))
+ return FALSE;
+ }
+
addr = offset;
if (section->output_section)
addr += section->output_section->vma + section->output_offset;
@@ -2256,15 +2376,10 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd
addr_size = 4;
BFD_ASSERT (addr_size == 4 || addr_size == 8);
- if (! stash)
+ if (! *pinfo)
{
bfd_size_type total_size;
asection *msec;
- bfd_size_type amt = sizeof (struct dwarf2_debug);
-
- stash = bfd_zalloc (abfd, amt);
- if (! stash)
- return FALSE;
*pinfo = stash;
@@ -2273,7 +2388,7 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd
/* No dwarf2 info. Note that at this point the stash
has been allocated, but contains zeros, this lets
future calls to this function fail quicker. */
- return FALSE;
+ goto done;
/* There can be more than one DWARF2 info section in a BFD these days.
Read them all in and produce one large stash. We do this in two
@@ -2285,7 +2400,7 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd
stash->info_ptr = bfd_alloc (abfd, total_size);
if (stash->info_ptr == NULL)
- return FALSE;
+ goto done;
stash->info_ptr_end = stash->info_ptr;
@@ -2319,7 +2434,7 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd
/* 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)
- return FALSE;
+ goto done;
stash->inliner_chain = NULL;
@@ -2328,10 +2443,11 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd
if (comp_unit_contains_address (each, addr)
&& comp_unit_find_nearest_line (each, addr, filename_ptr,
functionname_ptr,
- linenumber_ptr, stash)
- && check_function_name (abfd, section, symbols,
- *functionname_ptr))
- return TRUE;
+ linenumber_ptr, stash))
+ {
+ found = TRUE;
+ goto done;
+ }
/* Read each remaining comp. units checking each as they are read. */
while (stash->info_ptr < stash->info_ptr_end)
@@ -2398,15 +2514,20 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd
filename_ptr,
functionname_ptr,
linenumber_ptr,
- stash)
- && check_function_name (abfd, section, symbols,
- *functionname_ptr))
- return TRUE;
+ stash))
+ {
+ found = TRUE;
+ goto done;
+ }
}
}
}
- return FALSE;
+done:
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+ unset_sections (stash);
+
+ return found;
}
/* The DWARF2 version of find_line. Return TRUE if the line is found
@@ -2438,10 +2559,29 @@ _bfd_dwarf2_find_line (bfd *abfd,
asection *section;
- bfd_boolean found;
+ bfd_boolean found = FALSE;
section = bfd_get_section (symbol);
+ stash = *pinfo;
+
+ if (! stash)
+ {
+ bfd_size_type amt = sizeof (struct dwarf2_debug);
+
+ stash = bfd_zalloc (abfd, amt);
+ if (! stash)
+ return FALSE;
+ }
+
+ /* In a relocatable file, 2 functions may have the same address.
+ We change the section vma so that they won't overlap. */
+ if (!stash && (abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+ {
+ if (! place_sections (abfd, stash))
+ return FALSE;
+ }
+
addr = symbol->value;
if (section->output_section)
addr += section->output_section->vma + section->output_offset;
@@ -2449,19 +2589,13 @@ _bfd_dwarf2_find_line (bfd *abfd,
addr += section->vma;
*filename_ptr = NULL;
- stash = *pinfo;
*filename_ptr = NULL;
*linenumber_ptr = 0;
- if (! stash)
+ if (! *pinfo)
{
bfd_size_type total_size;
asection *msec;
- bfd_size_type amt = sizeof (struct dwarf2_debug);
-
- stash = bfd_zalloc (abfd, amt);
- if (! stash)
- return FALSE;
*pinfo = stash;
@@ -2470,7 +2604,7 @@ _bfd_dwarf2_find_line (bfd *abfd,
/* No dwarf2 info. Note that at this point the stash
has been allocated, but contains zeros, this lets
future calls to this function fail quicker. */
- return FALSE;
+ goto done;
/* There can be more than one DWARF2 info section in a BFD these days.
Read them all in and produce one large stash. We do this in two
@@ -2482,7 +2616,7 @@ _bfd_dwarf2_find_line (bfd *abfd,
stash->info_ptr = bfd_alloc (abfd, total_size);
if (stash->info_ptr == NULL)
- return FALSE;
+ goto done;
stash->info_ptr_end = stash->info_ptr;
@@ -2516,7 +2650,7 @@ _bfd_dwarf2_find_line (bfd *abfd,
/* 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)
- return FALSE;
+ goto done;
stash->inliner_chain = NULL;
@@ -2528,7 +2662,7 @@ _bfd_dwarf2_find_line (bfd *abfd,
found = comp_unit_find_line (each, symbol, addr, filename_ptr,
linenumber_ptr, stash);
if (found)
- return found;
+ goto done;
}
/* The DWARF2 spec says that the initial length field, and the
@@ -2605,12 +2739,16 @@ _bfd_dwarf2_find_line (bfd *abfd,
linenumber_ptr,
stash));
if (found)
- return TRUE;
+ goto done;
}
}
}
- return FALSE;
+done:
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+ unset_sections (stash);
+
+ return found;
}
bfd_boolean