Greatly improve the speed if looking up DWARF line number information.
* dwarf2.c (comp_unit): Add new fields 'lookup_funcinfo_table' and 'number_of_functions' to keep lookup table and number of entries in the table. (line_sequence): Add new fields 'line_info_lookup' and 'num_lines' to keep lookup table and number of entries in the table. (lookup_funcinfo): New structure for lookup table for function references. (build_line_info_table): New function to create and build the lookup table for line information. (lookup_address_in_line_info_table): Use the lookup table instead of traverse a linked list. (compare_lookup_funcinfos): New compare fuction used in sorting of lookup table for function references. (build_lookup_funcinfo_table): New function to create, build and sort the lookup table for functions references. (lookup_address_in_function_table): Use the table instead of traverse a linked list. (_bfd_dwarf2_cleanup_debug_info): Free memory from function references lookup table.
This commit is contained in:
parent
20955dbf71
commit
089e3718bd
2 changed files with 320 additions and 85 deletions
|
@ -1,3 +1,25 @@
|
|||
2016-11-08 Igor Tsimbalist <tigor.tools@gmail.com>
|
||||
|
||||
* dwarf2.c (comp_unit): Add new fields 'lookup_funcinfo_table' and
|
||||
'number_of_functions' to keep lookup table and number of entries in
|
||||
the table.
|
||||
(line_sequence): Add new fields 'line_info_lookup' and 'num_lines'
|
||||
to keep lookup table and number of entries in the table.
|
||||
(lookup_funcinfo): New structure for lookup table for function
|
||||
references.
|
||||
(build_line_info_table): New function to create and build the lookup
|
||||
table for line information.
|
||||
(lookup_address_in_line_info_table): Use the lookup table instead of
|
||||
traverse a linked list.
|
||||
(compare_lookup_funcinfos): New compare fuction used in sorting of
|
||||
lookup table for function references.
|
||||
(build_lookup_funcinfo_table): New function to create, build and
|
||||
sort the lookup table for functions references.
|
||||
(lookup_address_in_function_table): Use the table instead of
|
||||
traverse a linked list.
|
||||
(_bfd_dwarf2_cleanup_debug_info): Free memory from function references
|
||||
lookup table.
|
||||
|
||||
2016-11-04 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
* targets.c (bfd_target_vector): Only add riscv_elf32_vec target
|
||||
|
|
383
bfd/dwarf2.c
383
bfd/dwarf2.c
|
@ -144,16 +144,16 @@ struct dwarf2_debug
|
|||
/* Length of the loaded .debug_str section. */
|
||||
bfd_size_type dwarf_str_size;
|
||||
|
||||
/* Pointer to the .debug_ranges section loaded into memory. */
|
||||
/* Pointer to the .debug_ranges section loaded into memory. */
|
||||
bfd_byte *dwarf_ranges_buffer;
|
||||
|
||||
/* Length of the loaded .debug_ranges section. */
|
||||
/* Length of the loaded .debug_ranges section. */
|
||||
bfd_size_type dwarf_ranges_size;
|
||||
|
||||
/* If the most recent call to bfd_find_nearest_line was given an
|
||||
address in an inlined function, preserve a pointer into the
|
||||
calling chain for subsequent calls to bfd_find_inliner_info to
|
||||
use. */
|
||||
use. */
|
||||
struct funcinfo *inliner_chain;
|
||||
|
||||
/* Section VMAs at the time the stash was built. */
|
||||
|
@ -256,6 +256,12 @@ struct comp_unit
|
|||
/* A list of the functions found in this comp. unit. */
|
||||
struct funcinfo *function_table;
|
||||
|
||||
/* A table of function information references searchable by address. */
|
||||
struct lookup_funcinfo *lookup_funcinfo_table;
|
||||
|
||||
/* Number of functions in the function_table and sorted_function_table. */
|
||||
bfd_size_type number_of_functions;
|
||||
|
||||
/* A list of the variables found in this comp. unit. */
|
||||
struct varinfo *variable_table;
|
||||
|
||||
|
@ -390,7 +396,7 @@ struct info_hash_table
|
|||
struct bfd_hash_table base;
|
||||
};
|
||||
|
||||
/* Function to create a new entry in info hash table. */
|
||||
/* Function to create a new entry in info hash table. */
|
||||
|
||||
static struct bfd_hash_entry *
|
||||
info_hash_table_newfunc (struct bfd_hash_entry *entry,
|
||||
|
@ -476,7 +482,7 @@ insert_info_hash_table (struct info_hash_table *hash_table,
|
|||
}
|
||||
|
||||
/* Look up an info entry list from an info hash table. Return NULL
|
||||
if there is none. */
|
||||
if there is none. */
|
||||
|
||||
static struct info_list_node *
|
||||
lookup_info_hash_table (struct info_hash_table *hash_table, const char *key)
|
||||
|
@ -1214,22 +1220,22 @@ non_mangled (int lang)
|
|||
|
||||
struct line_info
|
||||
{
|
||||
struct line_info* prev_line;
|
||||
bfd_vma address;
|
||||
char *filename;
|
||||
unsigned int line;
|
||||
unsigned int column;
|
||||
unsigned int discriminator;
|
||||
unsigned char op_index;
|
||||
unsigned char end_sequence; /* End of (sequential) code sequence. */
|
||||
struct line_info * prev_line;
|
||||
bfd_vma address;
|
||||
char * filename;
|
||||
unsigned int line;
|
||||
unsigned int column;
|
||||
unsigned int discriminator;
|
||||
unsigned char op_index;
|
||||
unsigned char end_sequence; /* End of (sequential) code sequence. */
|
||||
};
|
||||
|
||||
struct fileinfo
|
||||
{
|
||||
char *name;
|
||||
unsigned int dir;
|
||||
unsigned int time;
|
||||
unsigned int size;
|
||||
char * name;
|
||||
unsigned int dir;
|
||||
unsigned int time;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
struct line_sequence
|
||||
|
@ -1237,11 +1243,13 @@ struct line_sequence
|
|||
bfd_vma low_pc;
|
||||
struct line_sequence* prev_sequence;
|
||||
struct line_info* last_line; /* Largest VMA. */
|
||||
struct line_info** line_info_lookup;
|
||||
bfd_size_type num_lines;
|
||||
};
|
||||
|
||||
struct line_info_table
|
||||
{
|
||||
bfd* abfd;
|
||||
bfd * abfd;
|
||||
unsigned int num_files;
|
||||
unsigned int num_dirs;
|
||||
unsigned int num_sequences;
|
||||
|
@ -1260,23 +1268,37 @@ struct line_info_table
|
|||
struct funcinfo
|
||||
{
|
||||
/* Pointer to previous function in list of all functions. */
|
||||
struct funcinfo *prev_func;
|
||||
struct funcinfo * prev_func;
|
||||
/* Pointer to function one scope higher. */
|
||||
struct funcinfo *caller_func;
|
||||
struct funcinfo * caller_func;
|
||||
/* Source location file name where caller_func inlines this func. */
|
||||
char *caller_file;
|
||||
char * caller_file;
|
||||
/* Source location file name. */
|
||||
char *file;
|
||||
char * file;
|
||||
/* Source location line number where caller_func inlines this func. */
|
||||
int caller_line;
|
||||
int caller_line;
|
||||
/* Source location line number. */
|
||||
int line;
|
||||
int tag;
|
||||
bfd_boolean is_linkage;
|
||||
const char *name;
|
||||
struct arange arange;
|
||||
int line;
|
||||
int tag;
|
||||
bfd boolean is_linkage;
|
||||
const char * name;
|
||||
struct arange arange;
|
||||
/* Where the symbol is defined. */
|
||||
asection *sec;
|
||||
asection * sec;
|
||||
};
|
||||
|
||||
struct lookup_funcinfo
|
||||
{
|
||||
/* Function information corresponding to this lookup table entry. */
|
||||
struct funcinfo * funcinfo;
|
||||
|
||||
/* The lowest address for this specific function. */
|
||||
bfd_vma low_addr;
|
||||
|
||||
/* The highest address of this function before the lookup table is sorted.
|
||||
The highest address of all prior functions after the lookup table is
|
||||
sorted, which is used for binary search. */
|
||||
bfd_vma high_addr;
|
||||
};
|
||||
|
||||
struct varinfo
|
||||
|
@ -1539,7 +1561,7 @@ arange_add (const struct comp_unit *unit, struct arange *first_arange,
|
|||
while (arange);
|
||||
|
||||
/* Need to allocate a new arange and insert it into the arange list.
|
||||
Order isn't significant, so just insert after the first arange. */
|
||||
Order isn't significant, so just insert after the first arange. */
|
||||
arange = (struct arange *) bfd_alloc (unit->abfd, sizeof (*arange));
|
||||
if (arange == NULL)
|
||||
return FALSE;
|
||||
|
@ -1579,17 +1601,62 @@ compare_sequences (const void* a, const void* b)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Construct the line information table for quick lookup. */
|
||||
|
||||
static bfd_boolean
|
||||
build_line_info_table (struct line_info_table * table,
|
||||
struct line_sequence * seq)
|
||||
{
|
||||
bfd_size_type amt;
|
||||
struct line_info** line_info_lookup;
|
||||
struct line_info* each_line;
|
||||
unsigned int num_lines;
|
||||
unsigned int index;
|
||||
|
||||
if (seq->line_info_lookup != NULL)
|
||||
return TRUE;
|
||||
|
||||
/* Count the number of line information entries. We could do this while
|
||||
scanning the debug information, but some entries may be added via
|
||||
lcl_head without having a sequence handy to increment the number of
|
||||
lines. */
|
||||
num_lines = 0;
|
||||
for (each_line = seq->last_line; each_line; each_line = each_line->prev_line)
|
||||
num_lines++;
|
||||
|
||||
if (num_lines == 0)
|
||||
return TRUE;
|
||||
|
||||
/* Allocate space for the line information lookup table. */
|
||||
amt = sizeof (struct line_info*) * num_lines;
|
||||
line_info_lookup = (struct line_info**) bfd_alloc (table->abfd, amt);
|
||||
if (line_info_lookup == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* Create the line information lookup table. */
|
||||
index = num_lines;
|
||||
for (each_line = seq->last_line; each_line; each_line = each_line->prev_line)
|
||||
line_info_lookup[--index] = each_line;
|
||||
|
||||
BFD_ASSERT (index == 0);
|
||||
|
||||
seq->num_lines = num_lines;
|
||||
seq->line_info_lookup = line_info_lookup;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Sort the line sequences for quick lookup. */
|
||||
|
||||
static bfd_boolean
|
||||
sort_line_sequences (struct line_info_table* table)
|
||||
{
|
||||
bfd_size_type amt;
|
||||
struct line_sequence* sequences;
|
||||
struct line_sequence* seq;
|
||||
unsigned int n = 0;
|
||||
unsigned int num_sequences = table->num_sequences;
|
||||
bfd_vma last_high_pc;
|
||||
bfd_size_type amt;
|
||||
struct line_sequence* sequences;
|
||||
struct line_sequence* seq;
|
||||
unsigned int n = 0;
|
||||
unsigned int num_sequences = table->num_sequences;
|
||||
bfd_vma last_high_pc;
|
||||
|
||||
if (num_sequences == 0)
|
||||
return TRUE;
|
||||
|
@ -1610,6 +1677,8 @@ sort_line_sequences (struct line_info_table* table)
|
|||
sequences[n].low_pc = seq->low_pc;
|
||||
sequences[n].prev_sequence = NULL;
|
||||
sequences[n].last_line = seq->last_line;
|
||||
sequences[n].line_info_lookup = NULL;
|
||||
sequences[n].num_lines = 0;
|
||||
seq = seq->prev_sequence;
|
||||
free (last_seq);
|
||||
}
|
||||
|
@ -2091,7 +2160,7 @@ lookup_address_in_line_info_table (struct line_info_table *table,
|
|||
unsigned int *discriminator_ptr)
|
||||
{
|
||||
struct line_sequence *seq = NULL;
|
||||
struct line_info *each_line;
|
||||
struct line_info *info;
|
||||
int low, high, mid;
|
||||
|
||||
/* Binary search the array of sequences. */
|
||||
|
@ -2109,26 +2178,43 @@ lookup_address_in_line_info_table (struct line_info_table *table,
|
|||
break;
|
||||
}
|
||||
|
||||
if (seq && addr >= seq->low_pc && addr < seq->last_line->address)
|
||||
{
|
||||
/* Note: seq->last_line should be a descendingly sorted list. */
|
||||
for (each_line = seq->last_line;
|
||||
each_line;
|
||||
each_line = each_line->prev_line)
|
||||
if (addr >= each_line->address)
|
||||
break;
|
||||
/* Check for a valid sequence. */
|
||||
if (!seq || addr < seq->low_pc || addr >= seq->last_line->address)
|
||||
goto fail;
|
||||
|
||||
if (each_line
|
||||
&& !(each_line->end_sequence || each_line == seq->last_line))
|
||||
{
|
||||
*filename_ptr = each_line->filename;
|
||||
*linenumber_ptr = each_line->line;
|
||||
if (discriminator_ptr)
|
||||
*discriminator_ptr = each_line->discriminator;
|
||||
return seq->last_line->address - seq->low_pc;
|
||||
}
|
||||
if (!build_line_info_table (table, seq))
|
||||
goto fail;
|
||||
|
||||
/* Binary search the array of line information. */
|
||||
low = 0;
|
||||
high = seq->num_lines;
|
||||
info = NULL;
|
||||
while (low < high)
|
||||
{
|
||||
mid = (low + high) / 2;
|
||||
info = seq->line_info_lookup[mid];
|
||||
if (addr < info->address)
|
||||
high = mid;
|
||||
else if (addr >= seq->line_info_lookup[mid + 1]->address)
|
||||
low = mid + 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check for a valid line information entry. */
|
||||
if (info
|
||||
&& addr >= info->address
|
||||
&& addr < seq->line_info_lookup[mid + 1]->address
|
||||
&& !(info->end_sequence || info == seq->last_line))
|
||||
{
|
||||
*filename_ptr = info->filename;
|
||||
*linenumber_ptr = info->line;
|
||||
if (discriminator_ptr)
|
||||
*discriminator_ptr = info->discriminator;
|
||||
return seq->last_line->address - seq->low_pc;
|
||||
}
|
||||
|
||||
fail:
|
||||
*filename_ptr = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
@ -2136,16 +2222,102 @@ lookup_address_in_line_info_table (struct line_info_table *table,
|
|||
/* Read in the .debug_ranges section for future reference. */
|
||||
|
||||
static bfd_boolean
|
||||
read_debug_ranges (struct comp_unit *unit)
|
||||
read_debug_ranges (struct comp_unit * unit)
|
||||
{
|
||||
struct dwarf2_debug *stash = unit->stash;
|
||||
struct dwarf2_debug * stash = unit->stash;
|
||||
|
||||
return read_section (unit->abfd, &stash->debug_sections[debug_ranges],
|
||||
stash->syms, 0,
|
||||
&stash->dwarf_ranges_buffer, &stash->dwarf_ranges_size);
|
||||
&stash->dwarf_ranges_buffer,
|
||||
&stash->dwarf_ranges_size);
|
||||
}
|
||||
|
||||
/* Function table functions. */
|
||||
|
||||
static int
|
||||
compare_lookup_funcinfos (const void * a, const void * b)
|
||||
{
|
||||
const struct lookup_funcinfo * lookup1 = a;
|
||||
const struct lookup_funcinfo * lookup2 = b;
|
||||
|
||||
if (lookup1->low_addr < lookup2->low_addr)
|
||||
return -1;
|
||||
if (lookup1->low_addr > lookup2->low_addr)
|
||||
return 1;
|
||||
if (lookup1->high_addr < lookup2->high_addr)
|
||||
return -1;
|
||||
if (lookup1->high_addr > lookup2->high_addr)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bfd_boolean
|
||||
build_lookup_funcinfo_table (struct comp_unit * unit)
|
||||
{
|
||||
struct lookup_funcinfo *lookup_funcinfo_table = unit->lookup_funcinfo_table;
|
||||
unsigned int number_of_functions = unit->number_of_functions;
|
||||
struct funcinfo *each;
|
||||
struct lookup_funcinfo *entry;
|
||||
size_t index;
|
||||
struct arange *range;
|
||||
bfd_vma low_addr, high_addr;
|
||||
|
||||
if (lookup_funcinfo_table || number_of_functions == 0)
|
||||
return TRUE;
|
||||
|
||||
/* Create the function info lookup table. */
|
||||
lookup_funcinfo_table = (struct lookup_funcinfo *)
|
||||
bfd_malloc (number_of_functions * sizeof (struct lookup_funcinfo));
|
||||
if (lookup_funcinfo_table == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* Populate the function info lookup table. */
|
||||
index = number_of_functions;
|
||||
for (each = unit->function_table; each; each = each->prev_func)
|
||||
{
|
||||
entry = &lookup_funcinfo_table[--index];
|
||||
entry->funcinfo = each;
|
||||
|
||||
/* Calculate the lowest and highest address for this function entry. */
|
||||
low_addr = entry->funcinfo->arange.low;
|
||||
high_addr = entry->funcinfo->arange.high;
|
||||
|
||||
for (range = entry->funcinfo->arange.next; range; range = range->next)
|
||||
{
|
||||
if (range->low < low_addr)
|
||||
low_addr = range->low;
|
||||
if (range->high > high_addr)
|
||||
high_addr = range->high;
|
||||
}
|
||||
|
||||
entry->low_addr = low_addr;
|
||||
entry->high_addr = high_addr;
|
||||
}
|
||||
|
||||
BFD_ASSERT (index == 0);
|
||||
|
||||
/* Sort the function by address. */
|
||||
qsort (lookup_funcinfo_table,
|
||||
number_of_functions,
|
||||
sizeof (struct lookup_funcinfo),
|
||||
compare_lookup_funcinfos);
|
||||
|
||||
/* Calculate the high watermark for each function in the lookup table. */
|
||||
high_addr = lookup_funcinfo_table[0].high_addr;
|
||||
for (index = 1; index < number_of_functions; index++)
|
||||
{
|
||||
entry = &lookup_funcinfo_table[index];
|
||||
if (entry->high_addr > high_addr)
|
||||
high_addr = entry->high_addr;
|
||||
else
|
||||
entry->high_addr = high_addr;
|
||||
}
|
||||
|
||||
unit->lookup_funcinfo_table = lookup_funcinfo_table;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* If ADDR is within UNIT's function tables, set FUNCTION_PTR, and return
|
||||
TRUE. Note that we need to find the function that has the smallest range
|
||||
that contains ADDR, to handle inlined functions without depending upon
|
||||
|
@ -2156,37 +2328,71 @@ lookup_address_in_function_table (struct comp_unit *unit,
|
|||
bfd_vma addr,
|
||||
struct funcinfo **function_ptr)
|
||||
{
|
||||
struct funcinfo* each_func;
|
||||
unsigned int number_of_functions = unit->number_of_functions;
|
||||
struct lookup_funcinfo* lookup_funcinfo = NULL;
|
||||
struct funcinfo* funcinfo = NULL;
|
||||
struct funcinfo* best_fit = NULL;
|
||||
bfd_vma best_fit_len = 0;
|
||||
bfd_size_type low, high, mid, first;
|
||||
struct arange *arange;
|
||||
|
||||
for (each_func = unit->function_table;
|
||||
each_func;
|
||||
each_func = each_func->prev_func)
|
||||
if (!build_lookup_funcinfo_table (unit))
|
||||
return FALSE;
|
||||
|
||||
/* Find the first function in the lookup table which may contain the
|
||||
specified address. */
|
||||
low = 0;
|
||||
high = number_of_functions;
|
||||
first = high;
|
||||
while (low < high)
|
||||
{
|
||||
for (arange = &each_func->arange;
|
||||
arange;
|
||||
arange = arange->next)
|
||||
{
|
||||
if (addr >= arange->low && addr < arange->high)
|
||||
{
|
||||
if (!best_fit
|
||||
|| arange->high - arange->low < best_fit_len)
|
||||
{
|
||||
best_fit = each_func;
|
||||
best_fit_len = arange->high - arange->low;
|
||||
}
|
||||
}
|
||||
}
|
||||
mid = (low + high) / 2;
|
||||
lookup_funcinfo = &unit->lookup_funcinfo_table[mid];
|
||||
if (addr < lookup_funcinfo->low_addr)
|
||||
high = mid;
|
||||
else if (addr >= lookup_funcinfo->high_addr)
|
||||
low = mid + 1;
|
||||
else
|
||||
high = first = mid;
|
||||
}
|
||||
|
||||
if (best_fit)
|
||||
/* Find the 'best' match for the address. The prior algorithm defined the
|
||||
best match as the function with the smallest address range containing
|
||||
the specified address. This definition should probably be changed to the
|
||||
innermost inline routine containing the address, but right now we want
|
||||
to get the same results we did before. */
|
||||
while (first < number_of_functions)
|
||||
{
|
||||
*function_ptr = best_fit;
|
||||
return TRUE;
|
||||
if (addr < unit->lookup_funcinfo_table[first].low_addr)
|
||||
break;
|
||||
funcinfo = unit->lookup_funcinfo_table[first].funcinfo;
|
||||
|
||||
for (arange = &funcinfo->arange; arange; arange = arange->next)
|
||||
{
|
||||
if (addr < arange->low || addr >= arange->high)
|
||||
continue;
|
||||
|
||||
if (!best_fit
|
||||
|| arange->high - arange->low < best_fit_len
|
||||
/* The following comparison is designed to return the same
|
||||
match as the previous algorithm for routines which have the
|
||||
same best fit length. */
|
||||
|| (arange->high - arange->low == best_fit_len
|
||||
&& funcinfo > best_fit))
|
||||
{
|
||||
best_fit = funcinfo;
|
||||
best_fit_len = arange->high - arange->low;
|
||||
}
|
||||
}
|
||||
|
||||
first++;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
if (!best_fit)
|
||||
return FALSE;
|
||||
|
||||
*function_ptr = best_fit;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* If SYM at ADDR is within function table of UNIT, set FILENAME_PTR
|
||||
|
@ -2271,8 +2477,8 @@ lookup_symbol_in_variable_table (struct comp_unit *unit,
|
|||
*linenumber_ptr = each->line;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static char *
|
||||
|
@ -2515,6 +2721,7 @@ scan_unit_for_symbols (struct comp_unit *unit)
|
|||
func->tag = abbrev->tag;
|
||||
func->prev_func = unit->function_table;
|
||||
unit->function_table = func;
|
||||
unit->number_of_functions++;
|
||||
BFD_ASSERT (!unit->cached);
|
||||
|
||||
if (func->tag == DW_TAG_inlined_subroutine)
|
||||
|
@ -2856,7 +3063,7 @@ parse_comp_unit (struct dwarf2_debug *stash,
|
|||
low_pc = attr.u.val;
|
||||
/* If the compilation unit DIE has a DW_AT_low_pc attribute,
|
||||
this is the base address to use when reading location
|
||||
lists or range lists. */
|
||||
lists or range lists. */
|
||||
if (abbrev->tag == DW_TAG_compile_unit)
|
||||
unit->base_address = low_pc;
|
||||
break;
|
||||
|
@ -3127,7 +3334,7 @@ comp_unit_hash_info (struct dwarf2_debug *stash,
|
|||
each_func && okay;
|
||||
each_func = each_func->prev_func)
|
||||
{
|
||||
/* Skip nameless functions. */
|
||||
/* Skip nameless functions. */
|
||||
if (each_func->name)
|
||||
/* There is no need to copy name string into hash table as
|
||||
name string is either in the dwarf string buffer or
|
||||
|
@ -3509,7 +3716,7 @@ stash_maybe_update_info_hash_tables (struct dwarf2_debug *stash)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/* Check consistency of info hash tables. This is for debugging only. */
|
||||
/* Check consistency of info hash tables. This is for debugging only. */
|
||||
|
||||
static void ATTRIBUTE_UNUSED
|
||||
stash_verify_info_hash_table (struct dwarf2_debug *stash)
|
||||
|
@ -3943,7 +4150,7 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
|
|||
stash_maybe_enable_info_hash_tables (abfd, stash);
|
||||
|
||||
/* Keep info hash table up to date if they are available. Note that we
|
||||
may disable the hash tables if there is any error duing update. */
|
||||
may disable the hash tables if there is any error duing update. */
|
||||
if (stash->info_hash_status == STASH_INFO_HASH_ON)
|
||||
stash_maybe_update_info_hash_tables (stash);
|
||||
|
||||
|
@ -4244,6 +4451,12 @@ _bfd_dwarf2_cleanup_debug_info (bfd *abfd, void **pinfo)
|
|||
function_table = function_table->prev_func;
|
||||
}
|
||||
|
||||
if (each->lookup_funcinfo_table)
|
||||
{
|
||||
free (each->lookup_funcinfo_table);
|
||||
each->lookup_funcinfo_table = NULL;
|
||||
}
|
||||
|
||||
while (variable_table)
|
||||
{
|
||||
if (variable_table->file)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue