diff options
Diffstat (limited to 'contrib/binutils/bfd/dwarf2.c')
-rw-r--r-- | contrib/binutils/bfd/dwarf2.c | 581 |
1 files changed, 314 insertions, 267 deletions
diff --git a/contrib/binutils/bfd/dwarf2.c b/contrib/binutils/bfd/dwarf2.c index b6de261..141c686 100644 --- a/contrib/binutils/bfd/dwarf2.c +++ b/contrib/binutils/bfd/dwarf2.c @@ -36,36 +36,38 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "elf/dwarf2.h" /* The data in the .debug_line statement prologue looks like this. */ + struct line_head - { - unsigned int total_length; - unsigned short version; - unsigned int prologue_length; - unsigned char minimum_instruction_length; - unsigned char default_is_stmt; - int line_base; - unsigned char line_range; - unsigned char opcode_base; - unsigned char *standard_opcode_lengths; - }; - -/* Attributes have a name and a value */ +{ + unsigned int total_length; + unsigned short version; + unsigned int prologue_length; + unsigned char minimum_instruction_length; + unsigned char default_is_stmt; + int line_base; + unsigned char line_range; + unsigned char opcode_base; + unsigned char *standard_opcode_lengths; +}; + +/* Attributes have a name and a value. */ + struct attribute +{ + enum dwarf_attribute name; + enum dwarf_form form; + union { - enum dwarf_attribute name; - enum dwarf_form form; - union - { - char *str; - struct dwarf_block *blk; - unsigned int unsnd; - int snd; - bfd_vma addr; - } - u; - }; - -/* Get at parts of an attribute structure */ + char *str; + struct dwarf_block *blk; + unsigned int unsnd; + int snd; + bfd_vma addr; + } + u; +}; + +/* Get at parts of an attribute structure. */ #define DW_STRING(attr) ((attr)->u.str) #define DW_UNSND(attr) ((attr)->u.unsnd) @@ -73,100 +75,100 @@ struct attribute #define DW_SND(attr) ((attr)->u.snd) #define DW_ADDR(attr) ((attr)->u.addr) -/* Blocks are a bunch of untyped bytes. */ +/* Blocks are a bunch of untyped bytes. */ struct dwarf_block - { - unsigned int size; - char *data; - }; - - -struct dwarf2_debug { +{ + unsigned int size; + char *data; +}; - /* A list of all previously read comp_units. */ +struct dwarf2_debug +{ + /* A list of all previously read comp_units. */ struct comp_unit* all_comp_units; /* The next unread compilation unit within the .debug_info section. Zero indicates that the .debug_info section has not been loaded - into a buffer yet.*/ + into a buffer yet. */ char* info_ptr; - /* Pointer to the end of the .debug_info section memory buffer. */ + /* Pointer to the end of the .debug_info section memory buffer. */ char* info_ptr_end; - /* Pointer to the .debug_abbrev section loaded into memory. */ + /* Pointer to the .debug_abbrev section loaded into memory. */ char* dwarf_abbrev_buffer; - /* Length of the loaded .debug_abbrev section. */ + /* Length of the loaded .debug_abbrev section. */ unsigned long dwarf_abbrev_size; /* Buffer for decode_line_info. */ char *dwarf_line_buffer; + + /* Length of the loaded .debug_line section. */ + unsigned long dwarf_line_size; }; -struct arange { +struct arange +{ struct arange *next; bfd_vma low; bfd_vma high; }; - /* A minimal decoding of DWARF2 compilation units. We only decode - what's needed to get to the line number information. */ - -struct comp_unit { + what's needed to get to the line number information. */ - /* Chain the previously read compilation units. */ +struct comp_unit +{ + /* Chain the previously read compilation units. */ struct comp_unit* next_unit; - /* Keep the bdf convenient (for memory allocation). */ + /* Keep the bdf convenient (for memory allocation). */ bfd* abfd; /* The lowest and higest addresses contained in this compilation - unit as specified in the compilation unit header. */ + unit as specified in the compilation unit header. */ struct arange arange; - /* The DW_AT_name attribute (for error messages). */ + /* The DW_AT_name attribute (for error messages). */ char* name; - /* The abbrev hash table. */ + /* The abbrev hash table. */ struct abbrev_info** abbrevs; - /* Note that an error was found by comp_unit_find_nearest_line. */ + /* Note that an error was found by comp_unit_find_nearest_line. */ int error; - /* The DW_AT_comp_dir attribute */ + /* The DW_AT_comp_dir attribute. */ char* comp_dir; - /* True if there is a line number table associated with this comp. unit. */ + /* True if there is a line number table associated with this comp. unit. */ int stmtlist; - - /* The offset into .debug_line of the line number table. */ + + /* The offset into .debug_line of the line number table. */ unsigned long line_offset; - /* Pointer to the first child die for the comp unit. */ + /* Pointer to the first child die for the comp unit. */ char *first_child_die_ptr; - /* The end of the comp unit. */ + /* The end of the comp unit. */ char *end_ptr; - /* The decoded line number, NULL if not yet decoded. */ + /* The decoded line number, NULL if not yet decoded. */ struct line_info_table* line_table; - /* A list of the functions found in this comp. unit. */ - struct funcinfo* function_table; + /* A list of the functions found in this comp. unit. */ + struct funcinfo* function_table; - /* Address size for this unit - from unit header */ + /* Address size for this unit - from unit header. */ unsigned char addr_size; }; +/* VERBATIM + The following function up to the END VERBATIM mark are + copied directly from dwarf2read.c. */ - -/* VERBATIM - The following function up to the END VERBATIM mark are - copied directly from dwarf2read.c. */ - -/* read dwarf information from a buffer */ +/* Read dwarf information from a buffer. */ static unsigned int read_1_byte (abfd, buf) @@ -192,9 +194,7 @@ read_2_bytes (abfd, buf) return bfd_get_16 (abfd, (bfd_byte *) buf); } -#if 0 - -/* This is not used. */ +#if 0 /* This is not used. */ static int read_2_signed_bytes (abfd, buf) @@ -214,9 +214,7 @@ read_4_bytes (abfd, buf) return bfd_get_32 (abfd, (bfd_byte *) buf); } -#if 0 - -/* This is not used. */ +#if 0 /* This is not used. */ static int read_4_signed_bytes (abfd, buf) @@ -262,6 +260,7 @@ read_string (abfd, buf, bytes_read_ptr) *bytes_read_ptr = 1; return NULL; } + *bytes_read_ptr = strlen (buf) + 1; return buf; } @@ -280,7 +279,7 @@ read_unsigned_leb128 (abfd, buf, bytes_read_ptr) result = 0; shift = 0; num_read = 0; - + do { byte = bfd_get_8 (abfd, (bfd_byte *) buf); @@ -290,9 +289,9 @@ read_unsigned_leb128 (abfd, buf, bytes_read_ptr) shift += 7; } while (byte & 0x80); - + * bytes_read_ptr = num_read; - + return result; } @@ -320,12 +319,12 @@ read_signed_leb128 (abfd, buf, bytes_read_ptr) shift += 7; } while (byte & 0x80); - + if ((shift < 32) && (byte & 0x40)) result |= -(1 << shift); * bytes_read_ptr = num_read; - + return result; } @@ -349,26 +348,22 @@ read_address (unit, buf) } } - - - - -/* This data structure holds the information of an abbrev. */ +/* This data structure holds the information of an abbrev. */ struct abbrev_info - { - unsigned int number; /* number identifying abbrev */ - enum dwarf_tag tag; /* dwarf tag */ - int has_children; /* boolean */ - unsigned int num_attrs; /* number of attributes */ - struct attr_abbrev *attrs; /* an array of attribute descriptions */ - struct abbrev_info *next; /* next in chain */ - }; +{ + unsigned int number; /* Number identifying abbrev. */ + enum dwarf_tag tag; /* DWARF tag. */ + int has_children; /* Boolean. */ + unsigned int num_attrs; /* Number of attributes. */ + struct attr_abbrev *attrs; /* An array of attribute descriptions. */ + struct abbrev_info *next; /* Next in chain. */ +}; struct attr_abbrev - { - enum dwarf_attribute name; - enum dwarf_form form; - }; +{ + enum dwarf_attribute name; + enum dwarf_form form; +}; #ifndef ABBREV_HASH_SIZE #define ABBREV_HASH_SIZE 121 @@ -397,6 +392,7 @@ lookup_abbrev (number,abbrevs) else abbrev = abbrev->next; } + return NULL; } @@ -406,18 +402,16 @@ lookup_abbrev (number,abbrevs) in a hash table. */ static struct abbrev_info** -read_abbrevs (abfd, offset) +read_abbrevs (abfd, offset, stash) bfd * abfd; unsigned int offset; + struct dwarf2_debug *stash; { struct abbrev_info **abbrevs; char *abbrev_ptr; struct abbrev_info *cur_abbrev; unsigned int abbrev_number, bytes_read, abbrev_name; unsigned int abbrev_form, hash_number; - struct dwarf2_debug *stash; - - stash = elf_tdata(abfd)->dwarf2_find_line_info; if (! stash->dwarf_abbrev_buffer) { @@ -430,13 +424,13 @@ read_abbrevs (abfd, offset) bfd_set_error (bfd_error_bad_value); return 0; } - + stash->dwarf_abbrev_size = msec->_raw_size; stash->dwarf_abbrev_buffer = (char*) bfd_alloc (abfd, stash->dwarf_abbrev_size); if (! stash->dwarf_abbrev_buffer) return 0; - - if (! bfd_get_section_contents (abfd, msec, + + if (! bfd_get_section_contents (abfd, msec, stash->dwarf_abbrev_buffer, 0, stash->dwarf_abbrev_size)) return 0; @@ -444,35 +438,36 @@ read_abbrevs (abfd, offset) if (offset > stash->dwarf_abbrev_size) { - (*_bfd_error_handler) (_("Dwarf Error: Abbrev offset (%u) bigger than abbrev size (%u)."), + (*_bfd_error_handler) (_("Dwarf Error: Abbrev offset (%u) bigger than abbrev size (%u)."), offset, stash->dwarf_abbrev_size ); bfd_set_error (bfd_error_bad_value); return 0; } - abbrevs = (struct abbrev_info**) bfd_zalloc (abfd, sizeof(struct abbrev_info*) * ABBREV_HASH_SIZE); + abbrevs = (struct abbrev_info**) bfd_zalloc (abfd, sizeof (struct abbrev_info*) * ABBREV_HASH_SIZE); abbrev_ptr = stash->dwarf_abbrev_buffer + offset; abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); abbrev_ptr += bytes_read; - /* loop until we reach an abbrev number of 0 */ + /* Loop until we reach an abbrev number of 0. */ while (abbrev_number) { cur_abbrev = (struct abbrev_info*)bfd_zalloc (abfd, sizeof (struct abbrev_info)); - /* read in abbrev header */ + /* Read in abbrev header. */ cur_abbrev->number = abbrev_number; cur_abbrev->tag = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); abbrev_ptr += bytes_read; cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr); abbrev_ptr += 1; - /* now read in declarations */ + /* Now read in declarations. */ abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); abbrev_ptr += bytes_read; abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); abbrev_ptr += bytes_read; + while (abbrev_name) { if ((cur_abbrev->num_attrs % ATTR_ALLOC_CHUNK) == 0) @@ -484,6 +479,7 @@ read_abbrevs (abfd, offset) if (! cur_abbrev->attrs) return 0; } + cur_abbrev->attrs[cur_abbrev->num_attrs].name = abbrev_name; cur_abbrev->attrs[cur_abbrev->num_attrs++].form = abbrev_form; abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); @@ -530,6 +526,7 @@ read_attribute (attr, abbrev, unit, info_ptr) attr->name = abbrev->name; attr->form = abbrev->form; + switch (abbrev->form) { case DW_FORM_addr: @@ -631,42 +628,41 @@ read_attribute (attr, abbrev, unit, info_ptr) return info_ptr; } - -/* Source line information table routines. */ +/* Source line information table routines. */ #define FILE_ALLOC_CHUNK 5 #define DIR_ALLOC_CHUNK 5 -struct line_info { +struct line_info +{ struct line_info* prev_line; - bfd_vma address; char* filename; unsigned int line; unsigned int column; - int end_sequence; /* end of (sequential) code sequence */ + int end_sequence; /* End of (sequential) code sequence. */ }; -struct fileinfo { +struct fileinfo +{ char *name; unsigned int dir; unsigned int time; unsigned int size; }; -struct line_info_table { +struct line_info_table +{ bfd* abfd; - unsigned int num_files; unsigned int num_dirs; - char* comp_dir; char** dirs; struct fileinfo* files; struct line_info* last_line; }; -static void +static void add_line_info (table, address, filename, line, column, end_sequence) struct line_info_table* table; bfd_vma address; @@ -688,7 +684,7 @@ add_line_info (table, address, filename, line, column, end_sequence) info->end_sequence = end_sequence; } -static char* +static char * concat_filename (table, file) struct line_info_table* table; unsigned int file; @@ -703,7 +699,7 @@ concat_filename (table, file) } filename = table->files[file - 1].name; - if (*filename == '/') + if (IS_ABSOLUTE_PATH(filename)) return filename; else @@ -723,8 +719,9 @@ arange_add (unit, low_pc, high_pc) { struct arange *arange; - /* first see if we can cheaply extend an existing range: */ + /* First see if we can cheaply extend an existing range. */ arange = &unit->arange; + do { if (low_pc == arange->high) @@ -743,14 +740,14 @@ arange_add (unit, low_pc, high_pc) if (unit->arange.high == 0) { - /* this is the first address range: store it in unit->arange: */ + /* 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: */ + /* 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; @@ -759,18 +756,15 @@ arange_add (unit, low_pc, high_pc) unit->arange.next = arange; } -/* Decode the line number information for UNIT. */ +/* Decode the line number information for UNIT. */ static struct line_info_table* -decode_line_info (unit) +decode_line_info (unit, stash) struct comp_unit *unit; + struct dwarf2_debug *stash; { bfd *abfd = unit->abfd; - - struct dwarf2_debug *stash; - struct line_info_table* table; - char *line_ptr; char *line_end; struct line_head lh; @@ -778,12 +772,9 @@ decode_line_info (unit) char *cur_file, *cur_dir; unsigned char op_code, extended_op, adj_opcode; - stash = elf_tdata (abfd)->dwarf2_find_line_info; - if (! stash->dwarf_line_buffer) { asection *msec; - unsigned long size; msec = bfd_get_section_by_name (abfd, ".debug_line"); if (! msec) @@ -792,22 +783,33 @@ decode_line_info (unit) bfd_set_error (bfd_error_bad_value); return 0; } - - size = msec->_raw_size; - stash->dwarf_line_buffer = (char *) bfd_alloc (abfd, size); + + stash->dwarf_line_size = msec->_raw_size; + stash->dwarf_line_buffer = (char *) bfd_alloc (abfd, stash->dwarf_line_size); if (! stash->dwarf_line_buffer) return 0; - if (! bfd_get_section_contents (abfd, msec, + if (! bfd_get_section_contents (abfd, msec, stash->dwarf_line_buffer, 0, - size)) + stash->dwarf_line_size)) return 0; /* FIXME: We ought to apply the relocs against this section before - we process it.... */ + we process it... */ + } + + /* Since we are using un-relocated data, it is possible to get a bad value + for the line_offset. Validate it here so that we won't get a segfault + below. */ + if (unit->line_offset >= stash->dwarf_line_size) + { + (*_bfd_error_handler) (_("Dwarf Error: Line offset (%u) bigger than line size (%u)."), + unit->line_offset, stash->dwarf_line_size); + bfd_set_error (bfd_error_bad_value); + return 0; } - table = (struct line_info_table*) bfd_alloc (abfd, + table = (struct line_info_table*) bfd_alloc (abfd, sizeof (struct line_info_table)); table->abfd = abfd; table->comp_dir = unit->comp_dir; @@ -823,7 +825,7 @@ decode_line_info (unit) line_ptr = stash->dwarf_line_buffer + unit->line_offset; - /* read in the prologue */ + /* Read in the prologue. */ lh.total_length = read_4_bytes (abfd, line_ptr); line_ptr += 4; line_end = line_ptr + lh.total_length; @@ -845,16 +847,18 @@ decode_line_info (unit) bfd_alloc (abfd, lh.opcode_base * sizeof (unsigned char)); lh.standard_opcode_lengths[0] = 1; + for (i = 1; i < lh.opcode_base; ++i) { lh.standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr); line_ptr += 1; } - /* Read directory table */ + /* Read directory table. */ while ((cur_dir = read_string (abfd, line_ptr, &bytes_read)) != NULL) { line_ptr += bytes_read; + if ((table->num_dirs % DIR_ALLOC_CHUNK) == 0) { table->dirs = (char **) @@ -863,14 +867,17 @@ decode_line_info (unit) if (! table->dirs) return 0; } + table->dirs[table->num_dirs++] = cur_dir; } + line_ptr += bytes_read; - /* Read file name table */ + /* Read file name table. */ while ((cur_file = read_string (abfd, line_ptr, &bytes_read)) != NULL) { line_ptr += bytes_read; + if ((table->num_files % FILE_ALLOC_CHUNK) == 0) { table->files = (struct fileinfo *) @@ -880,6 +887,7 @@ decode_line_info (unit) if (! table->files) return 0; } + table->files[table->num_files].name = cur_file; table->files[table->num_files].dir = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); @@ -892,12 +900,13 @@ decode_line_info (unit) line_ptr += bytes_read; table->num_files++; } + line_ptr += bytes_read; /* Read the statement sequences until there's nothing left. */ while (line_ptr < line_end) { - /* state machine registers */ + /* State machine registers. */ bfd_vma address = 0; char* filename = concat_filename (table, 1); unsigned int line = 1; @@ -907,15 +916,16 @@ decode_line_info (unit) int end_sequence = 0, need_low_pc = 1; bfd_vma low_pc = 0; - /* Decode the table. */ + /* Decode the table. */ while (! end_sequence) { op_code = read_1_byte (abfd, line_ptr); line_ptr += 1; + switch (op_code) { case DW_LNS_extended_op: - line_ptr += 1; /* ignore length */ + line_ptr += 1; /* Ignore length. */ extended_op = read_1_byte (abfd, line_ptr); line_ptr += 1; switch (extended_op) @@ -1012,12 +1022,12 @@ decode_line_info (unit) address += read_2_bytes (abfd, line_ptr); line_ptr += 2; break; - default: /* special operand */ + default: /* Special operand. */ adj_opcode = op_code - lh.opcode_base; address += (adj_opcode / lh.line_range) * lh.minimum_instruction_length; line += lh.line_base + (adj_opcode % lh.line_range); - /* append row to matrix using current values */ + /* Append row to matrix using current values. */ add_line_info (table, address, filename, line, column, 0); basic_block = 1; if (need_low_pc) @@ -1032,15 +1042,14 @@ decode_line_info (unit) return table; } - /* If ADDR is within TABLE set the output parameters and return true, otherwise return false. The output parameters, FILENAME_PTR and - LINENUMBER_PTR, are pointers to the objects to be filled in. */ + LINENUMBER_PTR, are pointers to the objects to be filled in. */ static boolean -lookup_address_in_line_info_table (table, +lookup_address_in_line_info_table (table, addr, - filename_ptr, + filename_ptr, linenumber_ptr) struct line_info_table* table; bfd_vma addr; @@ -1049,7 +1058,7 @@ lookup_address_in_line_info_table (table, { struct line_info* next_line = table->last_line; struct line_info* each_line; - + if (!next_line) return false; @@ -1067,28 +1076,24 @@ lookup_address_in_line_info_table (table, next_line = each_line; each_line = each_line->prev_line; } - + return false; } - - - -/* Function table functions. */ +/* Function table functions. */ -struct funcinfo { +struct funcinfo +{ struct funcinfo *prev_func; - char* name; bfd_vma low; bfd_vma high; }; - -/* If ADDR is within TABLE, set FUNCTIONNAME_PTR, and return true. */ +/* If ADDR is within TABLE, set FUNCTIONNAME_PTR, and return true. */ static boolean -lookup_address_in_function_table (table, +lookup_address_in_function_table (table, addr, functionname_ptr) struct funcinfo* table; @@ -1107,18 +1112,14 @@ lookup_address_in_function_table (table, return true; } } - + return false; } - - - -/* DWARF2 Compilation unit functions. */ - +/* DWARF2 Compilation unit functions. */ /* Scan over each die in a comp. unit looking for functions to add - to the function table. */ + to the function table. */ static boolean scan_unit_for_functions (unit) @@ -1144,16 +1145,16 @@ scan_unit_for_functions (unit) nesting_level--; continue; } - + abbrev = lookup_abbrev (abbrev_number,unit->abbrevs); if (! abbrev) { - (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %d."), + (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %d."), abbrev_number); bfd_set_error (bfd_error_bad_value); return false; } - + if (abbrev->tag == DW_TAG_subprogram) { func = (struct funcinfo*) bfd_zalloc (abfd, sizeof (struct funcinfo)); @@ -1162,24 +1163,24 @@ scan_unit_for_functions (unit) } else func = NULL; - + for (i = 0; i < abbrev->num_attrs; ++i) { info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr); - + if (func) { switch (attr.name) { case DW_AT_name: - + name = DW_STRING (&attr); /* Prefer DW_AT_MIPS_linkage_name over DW_AT_name. */ if (func->name == NULL) func->name = DW_STRING (&attr); break; - + case DW_AT_MIPS_linkage_name: func->name = DW_STRING (&attr); break; @@ -1203,7 +1204,7 @@ scan_unit_for_functions (unit) case DW_AT_name: name = DW_STRING (&attr); break; - + default: break; } @@ -1217,11 +1218,6 @@ scan_unit_for_functions (unit) return true; } - - - - - /* Parse a DWARF2 compilation unit starting at INFO_PTR. This includes the compilation unit header that proceeds the DIE's, but does not include the length field that preceeds each compilation @@ -1233,10 +1229,10 @@ scan_unit_for_functions (unit) to get to the line number information for the compilation unit. */ static struct comp_unit * -parse_comp_unit (abfd, info_ptr, end_ptr, abbrev_length) +parse_comp_unit (abfd, stash, unit_length, abbrev_length) bfd* abfd; - char* info_ptr; - char* end_ptr; + struct dwarf2_debug *stash; + bfd_vma unit_length; unsigned int abbrev_length; { struct comp_unit* unit; @@ -1250,6 +1246,9 @@ parse_comp_unit (abfd, info_ptr, end_ptr, abbrev_length) struct abbrev_info *abbrev; struct attribute attr; + char *info_ptr = stash->info_ptr; + char *end_ptr = info_ptr + unit_length; + version = read_2_bytes (abfd, info_ptr); info_ptr += 2; BFD_ASSERT (abbrev_length == 0 @@ -1286,8 +1285,8 @@ parse_comp_unit (abfd, info_ptr, end_ptr, abbrev_length) return 0; } - /* Read the abbrevs for this compilation unit into a table */ - abbrevs = read_abbrevs (abfd, abbrev_offset); + /* Read the abbrevs for this compilation unit into a table. */ + abbrevs = read_abbrevs (abfd, abbrev_offset, stash); if (! abbrevs) return 0; @@ -1309,10 +1308,10 @@ parse_comp_unit (abfd, info_ptr, end_ptr, abbrev_length) bfd_set_error (bfd_error_bad_value); return 0; } - + unit = (struct comp_unit*) bfd_zalloc (abfd, sizeof (struct comp_unit)); unit->abfd = abfd; - unit->addr_size = addr_size; + unit->addr_size = addr_size; unit->abbrevs = abbrevs; unit->end_ptr = end_ptr; @@ -1366,11 +1365,7 @@ parse_comp_unit (abfd, info_ptr, end_ptr, abbrev_length) return unit; } - - - - -/* Return true if UNIT contains the address given by ADDR. */ +/* Return true if UNIT contains the address given by ADDR. */ static boolean comp_unit_contains_address (unit, addr) @@ -1390,30 +1385,32 @@ comp_unit_contains_address (unit, addr) arange = arange->next; } while (arange); + return 0; } - /* If UNIT contains ADDR, set the output parameters to the values for the line containing ADDR. The output parameters, FILENAME_PTR, FUNCTIONNAME_PTR, and LINENUMBER_PTR, are pointers to the objects - to be filled in. + to be filled in. Return true of UNIT contains ADDR, and no errors were encountered; false otherwise. */ static boolean comp_unit_find_nearest_line (unit, addr, - filename_ptr, functionname_ptr, linenumber_ptr) + filename_ptr, functionname_ptr, linenumber_ptr, + stash) struct comp_unit* unit; bfd_vma addr; const char **filename_ptr; const char **functionname_ptr; unsigned int *linenumber_ptr; + struct dwarf2_debug *stash; { boolean line_p; boolean func_p; - + if (unit->error) return false; @@ -1424,15 +1421,15 @@ comp_unit_find_nearest_line (unit, addr, unit->error = 1; return false; } - - unit->line_table = decode_line_info (unit); + + unit->line_table = decode_line_info (unit, stash); if (! unit->line_table) { unit->error = 1; return false; } - + if (! scan_unit_for_functions (unit)) { unit->error = 1; @@ -1442,14 +1439,51 @@ comp_unit_find_nearest_line (unit, addr, line_p = lookup_address_in_line_info_table (unit->line_table, addr, - filename_ptr, + filename_ptr, linenumber_ptr); - func_p = lookup_address_in_function_table (unit->function_table, + func_p = lookup_address_in_function_table (unit->function_table, addr, functionname_ptr); return line_p || func_p; } +/* Locate a section in a BFD containing debugging info. The search starts from the + section after AFTER_SEC, or from the first section in the BFD if AFTER_SEC is + NULL. The search works by examining the names of the sections. There are two + permissiable names. The first is .debug_info. This is the standard DWARF2 name. + The second is a prefix .gnu.linkonce.wi. This is a variation on the .debug_info + section which has a checksum describing the contents appended onto the name. This + allows the linker to identify and discard duplicate debugging sections for + different compilation units. */ +#define DWARF2_DEBUG_INFO ".debug_info" +#define GNU_LINKONCE_INFO ".gnu.linkonce.wi." + +static asection * +find_debug_info (abfd, after_sec) + bfd * abfd; + asection * after_sec; +{ + asection * msec; + + if (after_sec) + msec = after_sec->next; + else + msec = abfd->sections; + + while (msec) + { + if (strcmp (msec->name, DWARF2_DEBUG_INFO) == 0) + return msec; + + if (strncmp (msec->name, GNU_LINKONCE_INFO, strlen (GNU_LINKONCE_INFO)) == 0) + return msec; + + msec = msec->next; + } + + return NULL; +} + /* The DWARF2 version of find_nearest line. Return true if the line is found without error. ADDR_SIZE is the number of bytes in the initial .debug_info length field and in the abbreviation offset. @@ -1460,7 +1494,7 @@ boolean _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset, filename_ptr, functionname_ptr, linenumber_ptr, - addr_size) + addr_size, pinfo) bfd *abfd; asection *section; asymbol **symbols ATTRIBUTE_UNUSED; @@ -1469,24 +1503,23 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset, const char **functionname_ptr; unsigned int *linenumber_ptr; unsigned int addr_size; + PTR *pinfo; { /* Read each compilation unit from the section .debug_info, and check to see if it contains the address we are searching for. If yes, lookup the address, and return the line number info. If no, go - on to the next compilation unit. + on to the next compilation unit. We keep a list of all the previously read compilation units, and - a pointer to the next un-read compilation unit. Check the - previously read units before reading more. - */ + a pointer to the next un-read compilation unit. Check the + previously read units before reading more. */ + struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo; - struct dwarf2_debug *stash = elf_tdata (abfd)->dwarf2_find_line_info; - - /* What address are we looking for? */ + /* What address are we looking for? */ bfd_vma addr = offset + section->vma; struct comp_unit* each; - + *filename_ptr = NULL; *functionname_ptr = NULL; *linenumber_ptr = 0; @@ -1497,74 +1530,90 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset, if (addr_size == 0) addr_size = 4; BFD_ASSERT (addr_size == 4 || addr_size == 8); - + if (! stash) { + unsigned long total_size; asection *msec; - unsigned long size; - - stash = elf_tdata (abfd)->dwarf2_find_line_info = + + stash = (struct dwarf2_debug*) bfd_zalloc (abfd, sizeof (struct dwarf2_debug)); - if (! stash) return false; - - msec = bfd_get_section_by_name (abfd, ".debug_info"); - if (! msec) - { - /* 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; - } - size = msec->_raw_size; - if (size == 0) - return false; - - stash->info_ptr = (char *) bfd_alloc (abfd, size); - - if (! stash->info_ptr) + *pinfo = (PTR) stash; + + msec = find_debug_info (abfd, NULL); + if (! msec) + /* 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; + + /* 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 + passes - in the first pass we just accumulate the section sizes. + 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. */ + for (total_size = 0; msec; msec = find_debug_info (abfd, msec)) + total_size += msec->_raw_size; + + stash->info_ptr = (char *) bfd_alloc (abfd, total_size); + if (stash->info_ptr == NULL) return false; - if (! bfd_get_section_contents (abfd, msec, stash->info_ptr, 0, size)) + stash->info_ptr_end = stash->info_ptr; + + for (msec = find_debug_info (abfd, NULL); + msec; + msec = find_debug_info (abfd, msec)) { - stash->info_ptr = 0; - return false; + unsigned long size; + unsigned long start; + + size = msec->_raw_size; + if (size == 0) + continue; + + start = stash->info_ptr_end - stash->info_ptr; + + if (! bfd_get_section_contents (abfd, msec, stash->info_ptr + start, 0, size)) + continue; + + stash->info_ptr_end = stash->info_ptr + start + size; } - stash->info_ptr_end = stash->info_ptr + size; - - /* FIXME: There is a problem with the contents of the - .debug_info section. The 'low' and 'high' addresses of the - comp_units are computed by relocs against symbols in the - .text segment. We need these addresses in order to determine - the nearest line number, and so we have to resolve the - relocs. There is a similar problem when the .debug_line - section is processed as well (e.g., there may be relocs - against the operand of the DW_LNE_set_address operator). - - Unfortunately getting hold of the reloc information is hard... - - For now, this means that disassembling object files (as - opposed to fully executables) does not always work as well as - we would like. */ + BFD_ASSERT (stash->info_ptr_end = stash->info_ptr + total_size); } - - /* A null info_ptr indicates that there is no dwarf2 info - (or that an error occured while setting up the stash). */ + /* FIXME: There is a problem with the contents of the + .debug_info section. The 'low' and 'high' addresses of the + comp_units are computed by relocs against symbols in the + .text segment. We need these addresses in order to determine + the nearest line number, and so we have to resolve the + relocs. There is a similar problem when the .debug_line + section is processed as well (e.g., there may be relocs + against the operand of the DW_LNE_set_address operator). + + Unfortunately getting hold of the reloc information is hard... + + For now, this means that disassembling object files (as + opposed to fully executables) does not always work as well as + we would like. */ + + /* 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; - /* Check the previously read comp. units first. */ - + /* Check the previously read comp. units first. */ for (each = stash->all_comp_units; each; each = each->next_unit) if (comp_unit_contains_address (each, addr)) - return comp_unit_find_nearest_line (each, addr, filename_ptr, - functionname_ptr, linenumber_ptr); + return comp_unit_find_nearest_line (each, addr, filename_ptr, + functionname_ptr, linenumber_ptr, + stash); - /* Read each remaining comp. units checking each as they are read. */ + /* Read each remaining comp. units checking each as they are read. */ while (stash->info_ptr < stash->info_ptr_end) { struct comp_unit* each; @@ -1579,9 +1628,7 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset, if (length > 0) { - each = parse_comp_unit (abfd, stash->info_ptr, - stash->info_ptr + length, - addr_size); + each = parse_comp_unit (abfd, stash, length, addr_size); stash->info_ptr += length; if (each) @@ -1593,21 +1640,23 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset, compilation units. If we don't have them (i.e., unit->high == 0), we need to consult the line info table to see if a compilation unit contains the given - address. */ + address. */ if (each->arange.high > 0) { if (comp_unit_contains_address (each, addr)) return comp_unit_find_nearest_line (each, addr, filename_ptr, functionname_ptr, - linenumber_ptr); + linenumber_ptr, + stash); } else { found = comp_unit_find_nearest_line (each, addr, filename_ptr, functionname_ptr, - linenumber_ptr); + linenumber_ptr, + stash); if (found) return true; } @@ -1617,5 +1666,3 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset, return false; } - -/* end of file */ |