* 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:
parent
f2482cb2da
commit
e82ce5296f
2 changed files with 115 additions and 20 deletions
|
@ -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
|
||||||
|
|
106
bfd/dwarf2.c
106
bfd/dwarf2.c
|
@ -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);
|
||||||
|
|
||||||
|
/* Find the correct location for 'info'. Normally we will receive
|
||||||
|
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;
|
info->prev_line = table->last_line;
|
||||||
table->last_line = info;
|
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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue