* dwarf2.c (add_line_info): Ensure that the line_info_table is

sorted even when given an out-of-order line sequence.
	(lookup_address_in_line_info_table): When an exact VMA match is
	not found, return line information with the closest VMA.
This commit is contained in:
Alan Modra 2002-10-23 12:41:32 +00:00
parent f2482cb2da
commit e82ce5296f
2 changed files with 115 additions and 20 deletions

View file

@ -1,3 +1,10 @@
2002-10-23 Nathan Tallent <eraxxon@alumni.rice.edu>
* dwarf2.c (add_line_info): Ensure that the line_info_table is
sorted even when given an out-of-order line sequence.
(lookup_address_in_line_info_table): When an exact VMA match is
not found, return line information with the closest VMA.
2002-10-23 Ross Alexander <ross.alexander@uk.neceur.com> 2002-10-23 Ross Alexander <ross.alexander@uk.neceur.com>
* elf64-hppa.c: Force DT_FLAGS to always be set. Required by * elf64-hppa.c: Force DT_FLAGS to always be set. Required by

View file

@ -402,7 +402,7 @@ read_indirect_string (unit, buf, bytes_read_ptr)
return NULL; return NULL;
} }
buf = stash->dwarf_str_buffer + offset; buf = stash->dwarf_str_buffer + offset;
if (*buf == '\0') if (*buf == '\0')
return NULL; return NULL;
return buf; return buf;
@ -614,7 +614,7 @@ read_abbrevs (abfd, offset, stash)
abbrevs[hash_number] = cur_abbrev; abbrevs[hash_number] = cur_abbrev;
/* Get next abbreviation. /* Get next abbreviation.
Under Irix6 the abbreviations for a compilation unit are not Under Irix6 the abbreviations for a compilation unit are not
always properly terminated with an abbrev number of 0. always properly terminated with an abbrev number of 0.
Exit loop if we encounter an abbreviation which we have Exit loop if we encounter an abbreviation which we have
already read (which means we are about to read the abbreviations already read (which means we are about to read the abbreviations
@ -806,7 +806,8 @@ struct line_info_table
char* comp_dir; char* comp_dir;
char** dirs; char** dirs;
struct fileinfo* files; struct fileinfo* files;
struct line_info* last_line; struct line_info* last_line; /* largest VMA */
struct line_info* lcl_head; /* local head; used in 'add_line_info' */
}; };
struct funcinfo struct funcinfo
@ -817,6 +818,11 @@ struct funcinfo
bfd_vma high; bfd_vma high;
}; };
/* add_line_info: 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, line_info->prev_line always accesses an equal
or smaller VMA. */
static void static void
add_line_info (table, address, filename, line, column, end_sequence) add_line_info (table, address, filename, line, column, end_sequence)
struct line_info_table* table; struct line_info_table* table;
@ -829,9 +835,72 @@ add_line_info (table, address, filename, line, column, end_sequence)
bfd_size_type amt = sizeof (struct line_info); bfd_size_type amt = sizeof (struct line_info);
struct line_info* info = (struct line_info*) bfd_alloc (table->abfd, amt); struct line_info* info = (struct line_info*) bfd_alloc (table->abfd, amt);
info->prev_line = table->last_line; /* Find the correct location for 'info'. Normally we will receive
table->last_line = info; new line_info data 1) in order and 2) with increasing VMAs.
However some compilers break the rules (cf. decode_line_info) and
so we include some heuristics for quickly finding the correct
location for 'info'. In particular, these heuristics optimize for
the common case in which the VMA sequence that we receive is a
list of locally sorted VMAs such as
p...z a...j (where a < j < p < z)
Note: table->lcl_head is used to head an *actual* or *possible*
sequence within the list (such as a...j) that is not directly
headed by table->last_line
Note: we may receive duplicate entries from 'decode_line_info'. */
while (1)
if (!table->last_line
|| address >= table->last_line->address)
{
/* Normal case: add 'info' to the beginning of the list */
info->prev_line = table->last_line;
table->last_line = info;
/* lcl_head: initialize to head a *possible* sequence at the end. */
if (!table->lcl_head)
table->lcl_head = info;
break;
}
else if (!table->lcl_head->prev_line
&& table->lcl_head->address > address)
{
/* Abnormal but easy: lcl_head is 1) at the *end* of the line
list and 2) the head of 'info'. */
info->prev_line = NULL;
table->lcl_head->prev_line = info;
break;
}
else if (table->lcl_head->prev_line
&& table->lcl_head->address > address
&& address >= table->lcl_head->prev_line->address)
{
/* Abnormal but easy: lcl_head is 1) in the *middle* of the line
list and 2) the head of 'info'. */
info->prev_line = table->lcl_head->prev_line;
table->lcl_head->prev_line = info;
break;
}
else
{
/* Abnormal and hard: Neither 'last_line' nor 'lcl_head' are valid
heads for 'info'. Reset 'lcl_head' and repeat. */
struct line_info* li2 = table->last_line; /* always non-NULL */
struct line_info* li1 = li2->prev_line;
while (li1)
{
if (li2->address > address && address >= li1->address)
break;
li2 = li1; /* always non-NULL */
li1 = li1->prev_line;
}
table->lcl_head = li2;
}
/* Set member data of 'info'. */
info->address = address; info->address = address;
info->filename = filename; info->filename = filename;
info->line = line; info->line = line;
@ -982,6 +1051,7 @@ decode_line_info (unit, stash)
table->files = NULL; table->files = NULL;
table->last_line = NULL; table->last_line = NULL;
table->lcl_head = NULL;
line_ptr = stash->dwarf_line_buffer + unit->line_offset; line_ptr = stash->dwarf_line_buffer + unit->line_offset;
@ -1091,10 +1161,10 @@ decode_line_info (unit, stash)
int basic_block = 0; int basic_block = 0;
int end_sequence = 0; int end_sequence = 0;
/* eraxxon@alumni.rice.edu: Against the DWARF2 specs, some /* eraxxon@alumni.rice.edu: Against the DWARF2 specs, some
compilers generate address sequences that are wildly out of compilers generate address sequences that are wildly out of
order using DW_LNE_set_address (e.g. Intel C++ 6.0 compiler order using DW_LNE_set_address (e.g. Intel C++ 6.0 compiler
for ia64-Linux). Thus, to determine the low and high for ia64-Linux). Thus, to determine the low and high
address, we must compare on every DW_LNS_copy, etc. */ address, we must compare on every DW_LNS_copy, etc. */
bfd_vma low_pc = 0; bfd_vma low_pc = 0;
bfd_vma high_pc = 0; bfd_vma high_pc = 0;
@ -1249,19 +1319,31 @@ lookup_address_in_line_info_table (table, addr, function, filename_ptr,
const char **filename_ptr; const char **filename_ptr;
unsigned int *linenumber_ptr; unsigned int *linenumber_ptr;
{ {
/* Note: table->last_line should be a descendingly sorted list. */
struct line_info* next_line = table->last_line; struct line_info* next_line = table->last_line;
struct line_info* each_line; struct line_info* each_line = NULL;
*filename_ptr = NULL;
if (!next_line) if (!next_line)
return false; return false;
each_line = next_line->prev_line; each_line = next_line->prev_line;
/* Check for large addresses */
if (addr > next_line->address)
each_line = NULL; /* ensure we skip over the normal case */
/* Normal case: search the list; save */
while (each_line && next_line) while (each_line && next_line)
{ {
if (!each_line->end_sequence /* If we have an address match, save this info. This allows us
&& addr >= each_line->address && addr < next_line->address) to return as good as results as possible for strange debugging
info. */
boolean addr_match = false;
if (each_line->address <= addr && addr <= next_line->address)
{ {
addr_match = true;
/* If this line appears to span functions, and addr is in the /* If this line appears to span functions, and addr is in the
later function, return the first line of that function instead later function, return the first line of that function instead
of the last line of the earlier one. This check is for GCC of the last line of the earlier one. This check is for GCC
@ -1278,16 +1360,22 @@ lookup_address_in_line_info_table (table, addr, function, filename_ptr,
*filename_ptr = each_line->filename; *filename_ptr = each_line->filename;
*linenumber_ptr = each_line->line; *linenumber_ptr = each_line->line;
} }
return true;
} }
if (addr_match && !each_line->end_sequence)
return true; /* we have definitely found what we want */
next_line = each_line; next_line = each_line;
each_line = each_line->prev_line; each_line = each_line->prev_line;
} }
/* At this point each_line is NULL but next_line is not. If we found the /* At this point each_line is NULL but next_line is not. If we found
containing function in this compilation unit, return the first line we a candidate end-of-sequence point in the loop above, we can return
have a number for. This is also for compatibility with GCC 2.95. */ that (compatibility with a bug in the Intel compiler); otherwise,
if (function != NULL) assuming that we found the containing function for this address in
this compilation unit, return the first line we have a number for
(compatibility with GCC 2.95). */
if (*filename_ptr == NULL && function != NULL)
{ {
*filename_ptr = next_line->filename; *filename_ptr = next_line->filename;
*linenumber_ptr = next_line->line; *linenumber_ptr = next_line->line;
@ -1701,7 +1789,7 @@ comp_unit_find_nearest_line (unit, addr, filename_ptr, functionname_ptr,
} }
if (unit->first_child_die_ptr < unit->end_ptr if (unit->first_child_die_ptr < unit->end_ptr
&& ! scan_unit_for_functions (unit)) && ! scan_unit_for_functions (unit))
{ {
unit->error = 1; unit->error = 1;
return false; return false;
@ -1821,7 +1909,7 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
return false; return false;
/* There can be more than one DWARF2 info section in a BFD these days. /* 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 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. passes - in the first pass we just accumulate the section sizes.
In the second pass we read in the section's contents. The allows 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. */
@ -1917,7 +2005,7 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
stash->info_ptr += addr_size; stash->info_ptr += addr_size;
if (length > 0) if (length > 0)
{ {
each = parse_comp_unit (abfd, stash, length, offset_size); each = parse_comp_unit (abfd, stash, length, offset_size);
stash->info_ptr += length; stash->info_ptr += length;