diff options
Diffstat (limited to 'bfd/dwarf2.c')
-rw-r--r-- | bfd/dwarf2.c | 147 |
1 files changed, 93 insertions, 54 deletions
diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c index 57f5482..e05dac6 100644 --- a/bfd/dwarf2.c +++ b/bfd/dwarf2.c @@ -104,6 +104,11 @@ struct dwarf2_debug { char *dwarf_line_buffer; }; +struct arange { + struct arange *next; + bfd_vma low; + bfd_vma high; +}; /* A minimal decoding of DWARF2 compilation units. We only decode @@ -119,8 +124,7 @@ struct comp_unit { /* The lowest and higest addresses contained in this compilation unit as specified in the compilation unit header. */ - bfd_vma low; - bfd_vma high; + struct arange arange; /* The DW_AT_name attribute (for error messages). */ char* name; @@ -705,6 +709,50 @@ concat_filename (table, file) } } +static void +arange_add (unit, low_pc, high_pc) + struct comp_unit *unit; + bfd_vma low_pc; + bfd_vma high_pc; +{ + struct arange *arange; + + /* first see if we can cheaply extend an existing range: */ + arange = &unit->arange; + do + { + if (low_pc == arange->high) + { + arange->high = high_pc; + return; + } + if (high_pc == arange->low) + { + arange->low = low_pc; + return; + } + arange = arange->next; + } + while (arange); + + if (unit->arange.high == 0) + { + /* this is the first address range: store it in unit->arange: */ + unit->arange.next = 0; + unit->arange.low = low_pc; + unit->arange.high = high_pc; + return; + } + + /* need to allocate a new arange and insert it into the arange list: */ + arange = bfd_zalloc (unit->abfd, sizeof (*arange)); + arange->low = low_pc; + arange->high = high_pc; + + arange->next = unit->arange.next; + unit->arange.next = arange; +} + /* Decode the line number information for UNIT. */ static struct line_info_table* @@ -723,12 +771,6 @@ decode_line_info (unit) unsigned int i, bytes_read; char *cur_file, *cur_dir; unsigned char op_code, extended_op, adj_opcode; -#if 0 - /* This optimization unfortunately does not work well on programs - that have multiple sections containing text (such as Linux which - uses .text, and .text.init, for example. */ - bfd_vma hi_pc = 0, lo_pc = ~ (bfd_vma) 0; -#endif stash = elf_tdata (abfd)->dwarf2_find_line_info; @@ -747,11 +789,11 @@ decode_line_info (unit) size = bfd_get_section_size_before_reloc (msec); stash->dwarf_line_buffer = (char *) bfd_alloc (abfd, size); - if (! dwarf_line_buffer) + if (! stash->dwarf_line_buffer) return 0; if (! bfd_get_section_contents (abfd, msec, - dwarf_line_buffer, 0, + stash->dwarf_line_buffer, 0, size)) return 0; @@ -856,7 +898,8 @@ decode_line_info (unit) unsigned int column = 0; int is_stmt = lh.default_is_stmt; int basic_block = 0; - int end_sequence = 0; + int end_sequence = 0, need_low_pc = 1; + bfd_vma low_pc = 0; /* Decode the table. */ while (! end_sequence) @@ -873,7 +916,14 @@ decode_line_info (unit) { case DW_LNE_end_sequence: end_sequence = 1; - add_line_info (table, address, filename, line, column, end_sequence); + add_line_info (table, address, filename, line, column, + end_sequence); + if (need_low_pc) + { + need_low_pc = 0; + low_pc = address; + } + arange_add (unit, low_pc, address); break; case DW_LNE_set_address: address = read_address (unit, line_ptr); @@ -912,6 +962,11 @@ decode_line_info (unit) case DW_LNS_copy: add_line_info (table, address, filename, line, column, 0); basic_block = 0; + if (need_low_pc) + { + need_low_pc = 0; + low_pc = address; + } break; case DW_LNS_advance_pc: address += lh.minimum_instruction_length @@ -959,25 +1014,14 @@ decode_line_info (unit) /* append row to matrix using current values */ add_line_info (table, address, filename, line, column, 0); basic_block = 1; + if (need_low_pc) + { + need_low_pc = 0; + low_pc = address; + } } -#if 0 - if (unit->high == 0) - { - if (address > hi_pc) - hi_pc = address; - if (address < lo_pc) - lo_pc = address; - } -#endif } } -#if 0 - if (unit->high == 0 && hi_pc != 0) - { - unit->high = hi_pc; - unit->low = lo_pc; - } -#endif return table; } @@ -1275,11 +1319,11 @@ parse_comp_unit (abfd, info_ptr, end_ptr) break; case DW_AT_low_pc: - unit->low = DW_ADDR (&attr); + unit->arange.low = DW_ADDR (&attr); break; case DW_AT_high_pc: - unit->high = DW_ADDR (&attr); + unit->arange.high = DW_ADDR (&attr); break; case DW_AT_comp_dir: @@ -1318,8 +1362,20 @@ comp_unit_contains_address (unit, addr) struct comp_unit* unit; bfd_vma addr; { - return ! unit->error - && (addr >= unit->low && addr <= unit->high); + struct arange *arange; + + if (unit->error) + return 0; + + arange = &unit->arange; + do + { + if (addr >= arange->low && addr < arange->high) + return 1; + arange = arange->next; + } + while (arange); + return 0; } @@ -1410,8 +1466,6 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset, struct comp_unit* each; - boolean found; - *filename_ptr = NULL; *functionname_ptr = NULL; *linenumber_ptr = 0; @@ -1478,31 +1532,16 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset, /* Check the previously read comp. units first. */ for (each = stash->all_comp_units; each; each = each->next_unit) - { - if (each->high > 0) - { - if (comp_unit_contains_address (each, addr)) - return comp_unit_find_nearest_line (each, addr, - filename_ptr, - functionname_ptr, - linenumber_ptr); - } - else - { - found = comp_unit_find_nearest_line (each, addr, - filename_ptr, - functionname_ptr, - linenumber_ptr); - if (found) - return true; - } - } + if (comp_unit_contains_address (each, addr)) + return comp_unit_find_nearest_line (each, addr, filename_ptr, + functionname_ptr, linenumber_ptr); /* Read each remaining comp. units checking each as they are read. */ while (stash->info_ptr < stash->info_ptr_end) { struct comp_unit* each; unsigned int length; + boolean found; length = read_4_bytes (abfd, stash->info_ptr); stash->info_ptr += 4; @@ -1523,7 +1562,7 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset, unit->high == 0), we need to consult the line info table to see if a compilation unit contains the given address. */ - if (each->high > 0) + if (each->arange.high > 0) { if (comp_unit_contains_address (each, addr)) return comp_unit_find_nearest_line (each, addr, |