From: Jan Kratochvil Date: Tue, 4 Jul 2017 08:09:27 +0000 (+0200) Subject: [binutils patch] DWARF-5: Extend bfd/dwarf2.c parse_comp_unit() X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0041f7df741692954ebc112c69e5326afb0115ba;p=binutils-gdb.git [binutils patch] DWARF-5: Extend bfd/dwarf2.c parse_comp_unit() bfd/ 2017-07-04 Jan Kratochvil * dwarf2.c (struct dwarf2_debug): Add fields dwarf_line_str_buffer and dwarf_line_str_size. (struct attr_abbrev): Add field implicit_const. (dwarf_debug_sections): Add .debug_line_str. (enum dwarf_debug_section_enum): Add debug_line_str and debug_max. (dwarf_debug_section_assert): Add static assertion. (read_indirect_line_string): New. (read_abbrevs): Support DW_FORM_implicit_const. (is_str_attr): Support DW_FORM_line_strp. (read_attribute_value): Support DW_FORM_line_strp and DW_FORM_implicit_const. (read_attribute): Support DW_FORM_implicit_const. (line_info_add_include_dir, line_info_add_include_dir_stub): (line_info_add_file_name, read_formatted_entries): New. (decode_line_info, parse_comp_unit): Support DWARF 5. (_bfd_dwarf2_cleanup_debug_info): Free dwarf_line_str_buffer. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index a2b79d916e4..b2b028fe59b 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,22 @@ +2017-07-04 Jan Kratochvil + + * dwarf2.c (struct dwarf2_debug): Add fields dwarf_line_str_buffer and + dwarf_line_str_size. + (struct attr_abbrev): Add field implicit_const. + (dwarf_debug_sections): Add .debug_line_str. + (enum dwarf_debug_section_enum): Add debug_line_str and debug_max. + (dwarf_debug_section_assert): Add static assertion. + (read_indirect_line_string): New. + (read_abbrevs): Support DW_FORM_implicit_const. + (is_str_attr): Support DW_FORM_line_strp. + (read_attribute_value): Support DW_FORM_line_strp and + DW_FORM_implicit_const. + (read_attribute): Support DW_FORM_implicit_const. + (line_info_add_include_dir, line_info_add_include_dir_stub): + (line_info_add_file_name, read_formatted_entries): New. + (decode_line_info, parse_comp_unit): Support DWARF 5. + (_bfd_dwarf2_cleanup_debug_info): Free dwarf_line_str_buffer. + 2017-07-03 Egeyar Bagcioglu * elfxx-sparc.c (_bfd_sparc_elf_finish_dynamic_symbol): Remove the diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c index 0ef3e1fc534..5e674d4859e 100644 --- a/bfd/dwarf2.c +++ b/bfd/dwarf2.c @@ -150,6 +150,12 @@ struct dwarf2_debug /* Length of the loaded .debug_str section. */ bfd_size_type dwarf_str_size; + /* Pointer to the .debug_line_str section loaded into memory. */ + bfd_byte *dwarf_line_str_buffer; + + /* Length of the loaded .debug_line_str section. */ + bfd_size_type dwarf_line_str_size; + /* Pointer to the .debug_ranges section loaded into memory. */ bfd_byte *dwarf_ranges_buffer; @@ -306,6 +312,7 @@ struct attr_abbrev { enum dwarf_attribute name; enum dwarf_form form; + bfd_vma implicit_const; }; /* Map of uncompressed DWARF debug section name to compressed one. It @@ -329,6 +336,7 @@ const struct dwarf_debug_section dwarf_debug_sections[] = { ".debug_static_vars", ".zdebug_static_vars" }, { ".debug_str", ".zdebug_str", }, { ".debug_str", ".zdebug_str", }, + { ".debug_line_str", ".zdebug_line_str", }, { ".debug_types", ".zdebug_types" }, /* GNU DWARF 1 extensions */ { ".debug_sfnames", ".zdebug_sfnames" }, @@ -361,15 +369,21 @@ enum dwarf_debug_section_enum debug_static_vars, debug_str, debug_str_alt, + debug_line_str, debug_types, debug_sfnames, debug_srcinfo, debug_funcnames, debug_typenames, debug_varnames, - debug_weaknames + debug_weaknames, + debug_max }; +/* A static assertion. */ +extern int dwarf_debug_section_assert[ARRAY_SIZE (dwarf_debug_sections) + == debug_max + 1 ? 1 : -1]; + #ifndef ABBREV_HASH_SIZE #define ABBREV_HASH_SIZE 121 #endif @@ -703,6 +717,45 @@ read_indirect_string (struct comp_unit * unit, return str; } +/* Like read_indirect_string but from .debug_line_str section. */ + +static char * +read_indirect_line_string (struct comp_unit * unit, + bfd_byte * buf, + bfd_byte * buf_end, + unsigned int * bytes_read_ptr) +{ + bfd_uint64_t offset; + struct dwarf2_debug *stash = unit->stash; + char *str; + + if (buf + unit->offset_size > buf_end) + { + * bytes_read_ptr = 0; + return NULL; + } + + if (unit->offset_size == 4) + offset = read_4_bytes (unit->abfd, buf, buf_end); + else + offset = read_8_bytes (unit->abfd, buf, buf_end); + + *bytes_read_ptr = unit->offset_size; + + if (! read_section (unit->abfd, &stash->debug_sections[debug_line_str], + stash->syms, offset, + &stash->dwarf_line_str_buffer, + &stash->dwarf_line_str_size)) + return NULL; + + if (offset >= stash->dwarf_line_str_size) + return NULL; + str = (char *) stash->dwarf_line_str_buffer + offset; + if (*str == '\0') + return NULL; + return str; +} + /* Like read_indirect_string but uses a .debug_str located in an alternate file pointed to by the .gnu_debugaltlink section. Used to impement DW_FORM_GNU_strp_alt. */ @@ -928,15 +981,28 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash) abbrev_ptr += 1; /* Now read in declarations. */ - abbrev_name = _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, - FALSE, abbrev_end); - abbrev_ptr += bytes_read; - abbrev_form = _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, - FALSE, abbrev_end); - abbrev_ptr += bytes_read; - - while (abbrev_name) + for (;;) { + /* Initialize it just to avoid a GCC false warning. */ + bfd_vma implicit_const = -1; + + abbrev_name = _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, + FALSE, abbrev_end); + abbrev_ptr += bytes_read; + abbrev_form = _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, + FALSE, abbrev_end); + abbrev_ptr += bytes_read; + if (abbrev_form == DW_FORM_implicit_const) + { + implicit_const = _bfd_safe_read_leb128 (abfd, abbrev_ptr, + &bytes_read, TRUE, + abbrev_end); + abbrev_ptr += bytes_read; + } + + if (abbrev_name == 0) + break; + if ((cur_abbrev->num_attrs % ATTR_ALLOC_CHUNK) == 0) { struct attr_abbrev *tmp; @@ -965,14 +1031,11 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash) cur_abbrev->attrs[cur_abbrev->num_attrs].name = (enum dwarf_attribute) abbrev_name; - cur_abbrev->attrs[cur_abbrev->num_attrs++].form + cur_abbrev->attrs[cur_abbrev->num_attrs].form = (enum dwarf_form) abbrev_form; - abbrev_name = _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, - FALSE, abbrev_end); - abbrev_ptr += bytes_read; - abbrev_form = _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, - FALSE, abbrev_end); - abbrev_ptr += bytes_read; + cur_abbrev->attrs[cur_abbrev->num_attrs].implicit_const + = implicit_const; + ++cur_abbrev->num_attrs; } hash_number = abbrev_number % ABBREV_HASH_SIZE; @@ -1004,7 +1067,8 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash) static inline bfd_boolean is_str_attr (enum dwarf_form form) { - return form == DW_FORM_string || form == DW_FORM_strp || form == DW_FORM_GNU_strp_alt; + return (form == DW_FORM_string || form == DW_FORM_strp + || form == DW_FORM_line_strp || form == DW_FORM_GNU_strp_alt); } /* Read and fill in the value of attribute ATTR as described by FORM. @@ -1014,6 +1078,7 @@ is_str_attr (enum dwarf_form form) static bfd_byte * read_attribute_value (struct attribute * attr, unsigned form, + bfd_vma implicit_const, struct comp_unit * unit, bfd_byte * info_ptr, bfd_byte * info_ptr_end) @@ -1101,6 +1166,10 @@ read_attribute_value (struct attribute * attr, attr->u.str = read_indirect_string (unit, info_ptr, info_ptr_end, &bytes_read); info_ptr += bytes_read; break; + case DW_FORM_line_strp: + attr->u.str = read_indirect_line_string (unit, info_ptr, info_ptr_end, &bytes_read); + info_ptr += bytes_read; + break; case DW_FORM_GNU_strp_alt: attr->u.str = read_alt_indirect_string (unit, info_ptr, info_ptr_end, &bytes_read); info_ptr += bytes_read; @@ -1179,7 +1248,18 @@ read_attribute_value (struct attribute * attr, form = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end); info_ptr += bytes_read; - info_ptr = read_attribute_value (attr, form, unit, info_ptr, info_ptr_end); + if (form == DW_FORM_implicit_const) + { + implicit_const = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read, + TRUE, info_ptr_end); + info_ptr += bytes_read; + } + info_ptr = read_attribute_value (attr, form, implicit_const, unit, + info_ptr, info_ptr_end); + break; + case DW_FORM_implicit_const: + attr->form = DW_FORM_sdata; + attr->u.sval = implicit_const; break; default: _bfd_error_handler (_("Dwarf Error: Invalid or unhandled FORM value: %#x."), @@ -1200,7 +1280,8 @@ read_attribute (struct attribute * attr, bfd_byte * info_ptr_end) { attr->name = abbrev->name; - info_ptr = read_attribute_value (attr, abbrev->form, unit, info_ptr, info_ptr_end); + info_ptr = read_attribute_value (attr, abbrev->form, abbrev->implicit_const, + unit, info_ptr, info_ptr_end); return info_ptr; } @@ -1734,6 +1815,195 @@ sort_line_sequences (struct line_info_table* table) return TRUE; } +/* Add directory to TABLE. CUR_DIR memory ownership is taken by TABLE. */ + +static bfd_boolean +line_info_add_include_dir (struct line_info_table *table, char *cur_dir) +{ + if ((table->num_dirs % DIR_ALLOC_CHUNK) == 0) + { + char **tmp; + bfd_size_type amt; + + amt = table->num_dirs + DIR_ALLOC_CHUNK; + amt *= sizeof (char *); + + tmp = (char **) bfd_realloc (table->dirs, amt); + if (tmp == NULL) + return FALSE; + table->dirs = tmp; + } + + table->dirs[table->num_dirs++] = cur_dir; + return TRUE; +} + +static bfd_boolean +line_info_add_include_dir_stub (struct line_info_table *table, char *cur_dir, + unsigned int dir ATTRIBUTE_UNUSED, + unsigned int time ATTRIBUTE_UNUSED, + unsigned int size ATTRIBUTE_UNUSED) +{ + return line_info_add_include_dir (table, cur_dir); +} + +/* Add file to TABLE. CUR_FILE memory ownership is taken by TABLE. */ + +static bfd_boolean +line_info_add_file_name (struct line_info_table *table, char *cur_file, + unsigned int dir, unsigned int time, unsigned int size) +{ + if ((table->num_files % FILE_ALLOC_CHUNK) == 0) + { + struct fileinfo *tmp; + bfd_size_type amt; + + amt = table->num_files + FILE_ALLOC_CHUNK; + amt *= sizeof (struct fileinfo); + + tmp = (struct fileinfo *) bfd_realloc (table->files, amt); + if (tmp == NULL) + return FALSE; + table->files = tmp; + } + + table->files[table->num_files].name = cur_file; + table->files[table->num_files].dir = dir; + table->files[table->num_files].time = time; + table->files[table->num_files].size = size; + table->num_files++; + return TRUE; +} + +/* Read directory or file name entry format, starting with byte of + format count entries, ULEB128 pairs of entry formats, ULEB128 of + entries count and the entries themselves in the described entry + format. */ + +static bfd_boolean +read_formatted_entries (struct comp_unit *unit, bfd_byte **bufp, + bfd_byte *buf_end, struct line_info_table *table, + bfd_boolean (*callback) (struct line_info_table *table, + char *cur_file, + unsigned int dir, + unsigned int time, + unsigned int size)) +{ + bfd *abfd = unit->abfd; + bfd_byte format_count, formati; + bfd_vma data_count, datai; + bfd_byte *buf = *bufp; + bfd_byte *format_header_data; + unsigned int bytes_read; + + format_count = read_1_byte (abfd, buf, buf_end); + buf += 1; + format_header_data = buf; + for (formati = 0; formati < format_count; formati++) + { + _bfd_safe_read_leb128 (abfd, buf, &bytes_read, FALSE, buf_end); + buf += bytes_read; + _bfd_safe_read_leb128 (abfd, buf, &bytes_read, FALSE, buf_end); + buf += bytes_read; + } + + data_count = _bfd_safe_read_leb128 (abfd, buf, &bytes_read, FALSE, buf_end); + buf += bytes_read; + for (datai = 0; datai < data_count; datai++) + { + bfd_byte *format = format_header_data; + struct fileinfo fe; + + for (formati = 0; formati < format_count; formati++) + { + bfd_vma content_type, form; + char *string_trash; + char **stringp = &string_trash; + unsigned int uint_trash, *uintp = &uint_trash; + + content_type = _bfd_safe_read_leb128 (abfd, format, &bytes_read, + FALSE, buf_end); + format += bytes_read; + switch (content_type) + { + case DW_LNCT_path: + stringp = &fe.name; + break; + case DW_LNCT_directory_index: + uintp = &fe.dir; + break; + case DW_LNCT_timestamp: + uintp = &fe.time; + break; + case DW_LNCT_size: + uintp = &fe.size; + break; + case DW_LNCT_MD5: + break; + default: + _bfd_error_handler + (_("Dwarf Error: Unknown format content type %lu."), + (unsigned long) content_type); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + form = _bfd_safe_read_leb128 (abfd, format, &bytes_read, FALSE, + buf_end); + format += bytes_read; + switch (form) + { + case DW_FORM_string: + *stringp = read_string (abfd, buf, buf_end, &bytes_read); + buf += bytes_read; + break; + + case DW_FORM_line_strp: + *stringp = read_indirect_line_string (unit, buf, buf_end, &bytes_read); + buf += bytes_read; + break; + + case DW_FORM_data1: + *uintp = read_1_byte (abfd, buf, buf_end); + buf += 1; + break; + + case DW_FORM_data2: + *uintp = read_2_bytes (abfd, buf, buf_end); + buf += 2; + break; + + case DW_FORM_data4: + *uintp = read_4_bytes (abfd, buf, buf_end); + buf += 4; + break; + + case DW_FORM_data8: + *uintp = read_8_bytes (abfd, buf, buf_end); + buf += 8; + break; + + case DW_FORM_udata: + *uintp = _bfd_safe_read_leb128 (abfd, buf, &bytes_read, FALSE, + buf_end); + buf += bytes_read; + break; + + case DW_FORM_block: + /* It is valid only for DW_LNCT_timestamp which is ignored by + current GDB. */ + break; + } + } + + if (!callback (table, fe.name, fe.dir, fe.time, fe.size)) + return FALSE; + } + + *bufp = buf; + return TRUE; +} + /* Decode the line number information for UNIT. */ static struct line_info_table* @@ -1815,7 +2085,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) line_end = line_ptr + lh.total_length; lh.version = read_2_bytes (abfd, line_ptr, line_end); - if (lh.version < 2 || lh.version > 4) + if (lh.version < 2 || lh.version > 5) { _bfd_error_handler (_("Dwarf Error: Unhandled .debug_line version %d."), lh.version); @@ -1824,7 +2094,8 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) } line_ptr += 2; - if (line_ptr + offset_size + (lh.version >=4 ? 6 : 5) >= line_end) + if (line_ptr + offset_size + (lh.version >= 5 ? 8 : (lh.version >= 4 ? 6 : 5)) + >= line_end) { _bfd_error_handler (_("Dwarf Error: Ran out of room reading prologue")); @@ -1832,6 +2103,26 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) return NULL; } + if (lh.version >= 5) + { + unsigned int segment_selector_size; + + /* Skip address size. */ + read_1_byte (abfd, line_ptr, line_end); + line_ptr += 1; + + segment_selector_size = read_1_byte (abfd, line_ptr, line_end); + line_ptr += 1; + if (segment_selector_size != 0) + { + _bfd_error_handler + (_("Dwarf Error: Line info unsupported segment selector size %u."), + segment_selector_size); + bfd_set_error (bfd_error_bad_value); + return NULL; + } + } + if (offset_size == 4) lh.prologue_length = read_4_bytes (abfd, line_ptr, line_end); else @@ -1887,62 +2178,52 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) line_ptr += 1; } - /* Read directory table. */ - while ((cur_dir = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL) + if (lh.version >= 5) { - line_ptr += bytes_read; + /* Read directory table. */ + if (!read_formatted_entries (unit, &line_ptr, line_end, table, + line_info_add_include_dir_stub)) + goto fail; - if ((table->num_dirs % DIR_ALLOC_CHUNK) == 0) + /* Read file name table. */ + if (!read_formatted_entries (unit, &line_ptr, line_end, table, + line_info_add_file_name)) + goto fail; + } + else + { + /* Read directory table. */ + while ((cur_dir = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL) { - char **tmp; - - amt = table->num_dirs + DIR_ALLOC_CHUNK; - amt *= sizeof (char *); + line_ptr += bytes_read; - tmp = (char **) bfd_realloc (table->dirs, amt); - if (tmp == NULL) + if (!line_info_add_include_dir (table, cur_dir)) goto fail; - table->dirs = tmp; } - table->dirs[table->num_dirs++] = cur_dir; - } - - line_ptr += bytes_read; - - /* Read file name table. */ - while ((cur_file = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL) - { line_ptr += bytes_read; - if ((table->num_files % FILE_ALLOC_CHUNK) == 0) + /* Read file name table. */ + while ((cur_file = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL) { - struct fileinfo *tmp; + unsigned int dir, time, size; + + line_ptr += bytes_read; - amt = table->num_files + FILE_ALLOC_CHUNK; - amt *= sizeof (struct fileinfo); + dir = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); + line_ptr += bytes_read; + time = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); + line_ptr += bytes_read; + size = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); + line_ptr += bytes_read; - tmp = (struct fileinfo *) bfd_realloc (table->files, amt); - if (tmp == NULL) + if (!line_info_add_file_name (table, cur_file, dir, time, size)) goto fail; - table->files = tmp; } - table->files[table->num_files].name = cur_file; - table->files[table->num_files].dir = - _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); - line_ptr += bytes_read; - table->files[table->num_files].time - = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); line_ptr += bytes_read; - table->files[table->num_files].size - = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); - 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) { @@ -2987,7 +3268,8 @@ parse_comp_unit (struct dwarf2_debug *stash, struct comp_unit* unit; unsigned int version; bfd_uint64_t abbrev_offset = 0; - unsigned int addr_size; + /* Initialize it just to avoid a GCC false warning. */ + unsigned int addr_size = -1; struct abbrev_info** abbrevs; unsigned int abbrev_number, bytes_read, i; struct abbrev_info *abbrev; @@ -2999,19 +3281,11 @@ parse_comp_unit (struct dwarf2_debug *stash, bfd_vma high_pc = 0; bfd *abfd = stash->bfd_ptr; bfd_boolean high_pc_relative = FALSE; + enum dwarf_unit_type unit_type; version = read_2_bytes (abfd, info_ptr, end_ptr); info_ptr += 2; - BFD_ASSERT (offset_size == 4 || offset_size == 8); - if (offset_size == 4) - abbrev_offset = read_4_bytes (abfd, info_ptr, end_ptr); - else - abbrev_offset = read_8_bytes (abfd, info_ptr, end_ptr); - info_ptr += offset_size; - addr_size = read_1_byte (abfd, info_ptr, end_ptr); - info_ptr += 1; - - if (version != 2 && version != 3 && version != 4) + if (version < 2 || version > 5) { /* PR 19872: A version number of 0 probably means that there is padding at the end of the .debug_info section. Gold puts it there when @@ -3021,12 +3295,45 @@ parse_comp_unit (struct dwarf2_debug *stash, { _bfd_error_handler (_("Dwarf Error: found dwarf version '%u', this reader" - " only handles version 2, 3 and 4 information."), version); + " only handles version 2, 3, 4 and 5 information."), version); bfd_set_error (bfd_error_bad_value); } return NULL; } + if (version < 5) + unit_type = DW_UT_compile; + else + { + unit_type = read_1_byte (abfd, info_ptr, end_ptr); + info_ptr += 1; + + addr_size = read_1_byte (abfd, info_ptr, end_ptr); + info_ptr += 1; + } + + BFD_ASSERT (offset_size == 4 || offset_size == 8); + if (offset_size == 4) + abbrev_offset = read_4_bytes (abfd, info_ptr, end_ptr); + else + abbrev_offset = read_8_bytes (abfd, info_ptr, end_ptr); + info_ptr += offset_size; + + if (version < 5) + { + addr_size = read_1_byte (abfd, info_ptr, end_ptr); + info_ptr += 1; + } + + if (unit_type == DW_UT_type) + { + /* Skip type signature. */ + info_ptr += 8; + + /* Skip type offset. */ + info_ptr += offset_size; + } + if (addr_size > sizeof (bfd_vma)) { _bfd_error_handler @@ -4576,6 +4883,8 @@ _bfd_dwarf2_cleanup_debug_info (bfd *abfd, void **pinfo) free (stash->dwarf_line_buffer); if (stash->dwarf_str_buffer) free (stash->dwarf_str_buffer); + if (stash->dwarf_line_str_buffer) + free (stash->dwarf_line_str_buffer); if (stash->dwarf_ranges_buffer) free (stash->dwarf_ranges_buffer); if (stash->info_ptr_memory)