From d07d4d739ae17787017f771dd2068fda0e836722 Mon Sep 17 00:00:00 2001 From: Martin Jansa Date: Wed, 12 May 2021 18:45:03 +0200 Subject: binutils: backport DWARF-5 support for gold * DWARF-5 is now used by default with gcc-11, causing 11.1.0/ld: internal error in format_file_lineno, at ../../gold/dwarf_reader.cc:2278 collect2: error: ld returned 1 exit status in various projects (runc-opencontainers, libhybris, collada-dom) * https://gcc.gnu.org/gcc-11/changes.html For targets that produce DWARF debugging information GCC now defaults to DWARF version 5 (with the exception of VxWorks and Darwin/Mac OS X which default to version 2 and AIX which defaults to version 4). This can produce up to 25% more compact debug information compared to earlier versions. To take full advantage of DWARF version 5 GCC needs to be build against binutils version 2.35.2 or higher. When GCC is build against earlier versions of binutils GCC will still emit DWARF version 5 for most debuginfo data, but will generate version 4 debug line tables (even when explicitly given -gdwarf-5). The following debug information consumers can process DWARF version 5: GDB 8.0, or higher valgrind 3.17.0 elfutils 0.172, or higher (for use with systemtap, dwarves/pahole, perf and libabigail) dwz 0.14 Programs embedding libbacktrace are urged to upgrade to the version shipping with GCC 11. To make GCC 11 generate an older DWARF version use -g together with -gdwarf-2, -gdwarf-3 or -gdwarf-4. Signed-off-by: Martin Jansa Signed-off-by: Richard Purdie --- meta/recipes-devtools/binutils/binutils-2.36.inc | 1 + .../0018-Add-DWARF-5-support-in-gold.patch | 1374 ++++++++++++++++++++ 2 files changed, 1375 insertions(+) create mode 100644 meta/recipes-devtools/binutils/binutils/0018-Add-DWARF-5-support-in-gold.patch diff --git a/meta/recipes-devtools/binutils/binutils-2.36.inc b/meta/recipes-devtools/binutils/binutils-2.36.inc index 66080dfcee..d54e2a3457 100644 --- a/meta/recipes-devtools/binutils/binutils-2.36.inc +++ b/meta/recipes-devtools/binutils/binutils-2.36.inc @@ -36,6 +36,7 @@ SRC_URI = "\ file://0015-sync-with-OE-libtool-changes.patch \ file://0016-Check-for-clang-before-checking-gcc-version.patch \ file://0017-Add-support-for-the-DW_FORM_strx-forms-to-the-BFD-li.patch \ + file://0018-Add-DWARF-5-support-in-gold.patch \ file://CVE-2021-20197.patch \ " S = "${WORKDIR}/git" diff --git a/meta/recipes-devtools/binutils/binutils/0018-Add-DWARF-5-support-in-gold.patch b/meta/recipes-devtools/binutils/binutils/0018-Add-DWARF-5-support-in-gold.patch new file mode 100644 index 0000000000..353b680857 --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/0018-Add-DWARF-5-support-in-gold.patch @@ -0,0 +1,1374 @@ +From 29dab7648672342418a9d32767e3b3182d9e6a30 Mon Sep 17 00:00:00 2001 +From: Cary Coutant +Date: Wed, 17 Mar 2021 21:31:15 -0700 +Subject: [PATCH] Add DWARF 5 support in gold. + +elfcpp/ + PR gold/27246 + * dwarf.h (enum DW_LNCT): Add line number table content type codes. + (enum DW_LINE_OPS): Reformat. + (enum DW_LINE_EXTENDED_OPS): Reformat. + (enum DW_CHILDREN): Reformat. + (enum DW_RLE): Add range list entry types. + (enum DW_SECT): Update values for DWARF 5. + +gold/ + PR gold/27246 + * dwarf_reader.cc (Dwarf_abbrev_table::do_get_abbrev): Handle + DW_FORM_implicit_const. + (Dwarf_ranges_table::read_ranges_table): Add version parameter; + Adjust all callers. Look for .debug_rnglists section if DWARF 5. + (Dwarf_ranges_table::read_range_list_v5): New method. + (Dwarf_die::read_attributes): Handle new DWARF 5 DW_FORM codes. + (Dwarf_die::skip_attributes): Likewise. + (Dwarf_info_reader::do_parse): Support DWARF 5 unit header format. + (Dwarf_info_reader::read_3bytes_from_pointer): New method. + (Sized_dwarf_line_info::Sized_dwarf_line_info): Initialize + str_buffer_, str_buffer_start, reloc_map_, line_number_map_. + Look for .debug_line_str section. + (Sized_dwarf_line_info::read_header_prolog): Support DWARF 5 prolog. + (Sized_dwarf_line_info::read_header_tables): Rename to... + (Sized_dwarf_line_info::read_header_tables_v2): ... this. + (Sized_dwarf_line_info::read_header_tables_v5): New method. + (Sized_dwarf_line_info::process_one_opcode): Insert missing "this->". + Change advance_line to signed int64_t. + (Sized_dwarf_line_info::read_lines): Add endptr parameter; adjust + callers. Insert missing "this->". + (Sized_dwarf_line_info::read_line_mappings): Support DWARF 5. + (Sized_dwarf_line_info::do_addr2line): Add debug code. + * dwarf_reader.h (Dwarf_abbrev_table::Attribute): Add implicit_const + field. Adjust constructor. + (Dwarf_abbrev_table::add_sttribute): Add implicit_const parameter. + (Dwarf_ranges_table::read_ranges_table): Add version parameter. + (Dwarf_ranges_table::read_range_list_v5): New method. + (Dwarf_die): Remove unused attr_off field. + (Dwarf_info_reader::Dwarf_info_reader): Initialize unit_type_ field. + (Dwarf_info_reader::is_type_unit): New method. + (Dwarf_info_reader::read_3bytes_from_pointer): New method. + (Dwarf_info_reader::read_range_list): Call read_range_list_v5 for + DWARF 5 range lists. + (Dwarf_info_reader::is_type_unit_): Remove. + (Dwarf_info_reader::unit_type_): New field. + (Sized_dwarf_line_info::~Sized_dwarf_line_info): Delete + str_buffer_start_. + (Sized_dwarf_line_info::read_header_tables): Rename to... + (Sized_dwarf_line_info::read_header_tables_v2): ... this. + (Sized_dwarf_line_info::read_header_tables_v5): New method. + (Sized_dwarf_line_info::read_lines): Add endptr parameter. + (Sized_dwarf_line_info::Dwarf_line_infoHeader): Add address_size field. + (Sized_dwarf_line_info::str_buffer_): New field. + (Sized_dwarf_line_info::str_buffer_end_): New field. + (Sized_dwarf_line_info::str_buffer_start_): New field. + (Sized_dwarf_line_info::end_of_header_length_): New field. + (Sized_dwarf_line_info::end_of_unit_): New field. + +Upstream-Status: Backport [5cde809b7b9 Add DWARF 5 support in gold.] + +Signed-off-by: Martin Jansa +--- + elfcpp/dwarf.h | 89 +++++-- + gold/dwarf_reader.cc | 591 +++++++++++++++++++++++++++++++++++++------ + gold/dwarf_reader.h | 103 ++++++-- + 3 files changed, 654 insertions(+), 129 deletions(-) + +diff --git a/elfcpp/dwarf.h b/elfcpp/dwarf.h +index e24347f8481..c9a9e02369c 100644 +--- a/elfcpp/dwarf.h ++++ b/elfcpp/dwarf.h +@@ -152,35 +152,48 @@ enum DW_EH_PE + DW_EH_PE_indirect = 0x80 + }; + ++// Line number table content type codes. ++ ++enum DW_LNCT ++{ ++ DW_LNCT_path = 0x1, ++ DW_LNCT_directory_index = 0x2, ++ DW_LNCT_timestamp = 0x3, ++ DW_LNCT_size = 0x4, ++ DW_LNCT_MD5 = 0x5, ++ DW_LNCT_lo_user = 0x2000, ++ DW_LNCT_hi_user = 0x3fff ++}; ++ + // Line number opcodes. + + enum DW_LINE_OPS + { +- DW_LNS_extended_op = 0, +- DW_LNS_copy = 1, +- DW_LNS_advance_pc = 2, +- DW_LNS_advance_line = 3, +- DW_LNS_set_file = 4, +- DW_LNS_set_column = 5, +- DW_LNS_negate_stmt = 6, +- DW_LNS_set_basic_block = 7, +- DW_LNS_const_add_pc = 8, +- DW_LNS_fixed_advance_pc = 9, ++ DW_LNS_extended_op = 0x00, ++ DW_LNS_copy = 0x01, ++ DW_LNS_advance_pc = 0x02, ++ DW_LNS_advance_line = 0x03, ++ DW_LNS_set_file = 0x04, ++ DW_LNS_set_column = 0x05, ++ DW_LNS_negate_stmt = 0x06, ++ DW_LNS_set_basic_block = 0x07, ++ DW_LNS_const_add_pc = 0x08, ++ DW_LNS_fixed_advance_pc = 0x09, + // DWARF 3. +- DW_LNS_set_prologue_end = 10, +- DW_LNS_set_epilogue_begin = 11, +- DW_LNS_set_isa = 12 ++ DW_LNS_set_prologue_end = 0x0a, ++ DW_LNS_set_epilogue_begin = 0x0b, ++ DW_LNS_set_isa = 0x0c + }; + + // Line number extended opcodes. + + enum DW_LINE_EXTENDED_OPS + { +- DW_LNE_end_sequence = 1, +- DW_LNE_set_address = 2, +- DW_LNE_define_file = 3, ++ DW_LNE_end_sequence = 0x01, ++ DW_LNE_set_address = 0x02, ++ DW_LNE_define_file = 0x03, + // DWARF4. +- DW_LNE_set_discriminator = 4, ++ DW_LNE_set_discriminator = 0x04, + // HP extensions. + DW_LNE_HP_negate_is_UV_update = 0x11, + DW_LNE_HP_push_context = 0x12, +@@ -191,13 +204,15 @@ enum DW_LINE_EXTENDED_OPS + DW_LNE_HP_negate_post_semantics = 0x17, + DW_LNE_HP_negate_function_exit = 0x18, + DW_LNE_HP_negate_front_end_logical = 0x19, +- DW_LNE_HP_define_proc = 0x20 ++ DW_LNE_HP_define_proc = 0x20, ++ DW_LNE_lo_user = 0x80, ++ DW_LNE_hi_user = 0xff + }; + + enum DW_CHILDREN + { +- DW_CHILDREN_no =0x00, +- DW_CHILDREN_yes =0x01 ++ DW_CHILDREN_no = 0, ++ DW_CHILDREN_yes = 1 + }; + + // Source language names and codes. +@@ -247,20 +262,38 @@ enum DW_LANG + DW_LANG_HP_Assembler = 0x8007 + }; + ++// Range list entry kinds in .debug_rnglists* section. ++ ++enum DW_RLE ++{ ++ DW_RLE_end_of_list = 0x00, ++ DW_RLE_base_addressx = 0x01, ++ DW_RLE_startx_endx = 0x02, ++ DW_RLE_startx_length = 0x03, ++ DW_RLE_offset_pair = 0x04, ++ DW_RLE_base_address = 0x05, ++ DW_RLE_start_end = 0x06, ++ DW_RLE_start_length = 0x07 ++}; ++ + // DWARF section identifiers used in the package format. + // Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFissionDWP. ++// Added (with changes) in DWARF 5. + + enum DW_SECT + { +- DW_SECT_INFO = 1, +- DW_SECT_TYPES = 2, +- DW_SECT_ABBREV = 3, +- DW_SECT_LINE = 4, +- DW_SECT_LOC = 5, ++ DW_SECT_INFO = 1, ++ DW_SECT_ABBREV = 3, ++ DW_SECT_LINE = 4, ++ DW_SECT_LOCLISTS = 5, + DW_SECT_STR_OFFSETS = 6, +- DW_SECT_MACINFO = 7, +- DW_SECT_MACRO = 8, +- DW_SECT_MAX = DW_SECT_MACRO, ++ DW_SECT_MACINFO = 7, ++ DW_SECT_RNGLISTS = 8, ++ DW_SECT_MAX = DW_SECT_RNGLISTS, ++ // These were used only for the experimental Fission support in DWARF 4. ++ DW_SECT_TYPES = 2, ++ DW_SECT_LOC = 5, ++ DW_SECT_MACRO = 8 + }; + + } // End namespace elfcpp. +diff --git a/gold/dwarf_reader.cc b/gold/dwarf_reader.cc +index f0e6b89bde2..83a0114ed39 100644 +--- a/gold/dwarf_reader.cc ++++ b/gold/dwarf_reader.cc +@@ -26,6 +26,7 @@ + #include + #include + ++#include "debug.h" + #include "elfcpp_swap.h" + #include "dwarf.h" + #include "object.h" +@@ -275,6 +276,14 @@ Dwarf_abbrev_table::do_get_abbrev(unsigned int code) + uint64_t form = read_unsigned_LEB_128(this->buffer_pos_, &len); + this->buffer_pos_ += len; + ++ // For DW_FORM_implicit_const, read the constant. ++ int64_t implicit_const = 0; ++ if (form == elfcpp::DW_FORM_implicit_const) ++ { ++ implicit_const = read_signed_LEB_128(this->buffer_pos_, &len); ++ this->buffer_pos_ += len; ++ } ++ + // A (0,0) pair terminates the list. + if (attr == 0 && form == 0) + break; +@@ -282,7 +291,7 @@ Dwarf_abbrev_table::do_get_abbrev(unsigned int code) + if (attr == elfcpp::DW_AT_sibling) + entry->has_sibling_attribute = true; + +- entry->add_attribute(attr, form); ++ entry->add_attribute(attr, form, implicit_const); + } + + this->store_abbrev(nextcode, entry); +@@ -302,8 +311,16 @@ Dwarf_ranges_table::read_ranges_table( + Relobj* object, + const unsigned char* symtab, + off_t symtab_size, +- unsigned int ranges_shndx) ++ unsigned int ranges_shndx, ++ unsigned int version) + { ++ const std::string section_name(version < 5 ++ ? ".debug_ranges" ++ : ".debug_rnglists"); ++ const std::string compressed_section_name(version < 5 ++ ? ".zdebug_ranges" ++ : ".zdebug_rnglists"); ++ + // If we've already read this abbrev table, return immediately. + if (this->ranges_shndx_ > 0 + && this->ranges_shndx_ == ranges_shndx) +@@ -318,7 +335,7 @@ Dwarf_ranges_table::read_ranges_table( + for (unsigned int i = 1; i < object->shnum(); ++i) + { + std::string name = object->section_name(i); +- if (name == ".debug_ranges" || name == ".zdebug_ranges") ++ if (name == section_name || name == compressed_section_name) + { + ranges_shndx = i; + this->output_section_offset_ = object->output_section_offset(i); +@@ -393,7 +410,7 @@ Dwarf_ranges_table::read_range_list( + { + Dwarf_range_list* ranges; + +- if (!this->read_ranges_table(object, symtab, symtab_size, ranges_shndx)) ++ if (!this->read_ranges_table(object, symtab, symtab_size, ranges_shndx, 4)) + return NULL; + + // Correct the offset. For incremental update links, we have a +@@ -459,6 +476,125 @@ Dwarf_ranges_table::read_range_list( + return ranges; + } + ++// Read a DWARF 5 range list from section RANGES_SHNDX at offset RANGES_OFFSET. ++ ++Dwarf_range_list* ++Dwarf_ranges_table::read_range_list_v5( ++ Relobj* object, ++ const unsigned char* symtab, ++ off_t symtab_size, ++ unsigned int addr_size, ++ unsigned int ranges_shndx, ++ off_t offset) ++{ ++ Dwarf_range_list* ranges; ++ ++ if (!this->read_ranges_table(object, symtab, symtab_size, ranges_shndx, 5)) ++ return NULL; ++ ++ ranges = new Dwarf_range_list(); ++ off_t base = 0; ++ unsigned int shndx0 = 0; ++ ++ // Correct the offset. For incremental update links, we have a ++ // relocated offset that is relative to the output section, but ++ // here we need an offset relative to the input section. ++ offset -= this->output_section_offset_; ++ ++ // Read the range list at OFFSET. ++ const unsigned char* prle = this->ranges_buffer_ + offset; ++ while (prle < this->ranges_buffer_end_) ++ { ++ off_t start; ++ off_t end; ++ unsigned int shndx1 = 0; ++ unsigned int shndx2 = 0; ++ size_t len; ++ ++ // Read the entry type. ++ unsigned int rle_type = *prle++; ++ offset += 1; ++ ++ if (rle_type == elfcpp::DW_RLE_end_of_list) ++ break; ++ ++ switch (rle_type) ++ { ++ case elfcpp::DW_RLE_base_address: ++ if (addr_size == 4) ++ base = this->dwinfo_->read_from_pointer<32>(prle); ++ else ++ base = this->dwinfo_->read_from_pointer<64>(prle); ++ if (this->ranges_reloc_mapper_ != NULL) ++ shndx0 = this->lookup_reloc(offset, &base); ++ prle += addr_size; ++ offset += addr_size; ++ break; ++ ++ case elfcpp::DW_RLE_offset_pair: ++ start = read_unsigned_LEB_128(prle, &len); ++ prle += len; ++ offset += len; ++ end = read_unsigned_LEB_128(prle, &len); ++ prle += len; ++ offset += len; ++ if (shndx0 == 0 || object->is_section_included(shndx0)) ++ ranges->add(shndx0, base + start, base + end); ++ break; ++ ++ case elfcpp::DW_RLE_start_end: ++ if (addr_size == 4) ++ { ++ start = this->dwinfo_->read_from_pointer<32>(prle); ++ end = this->dwinfo_->read_from_pointer<32>(prle + 4); ++ } ++ else ++ { ++ start = this->dwinfo_->read_from_pointer<64>(prle); ++ end = this->dwinfo_->read_from_pointer<64>(prle + 8); ++ } ++ if (this->ranges_reloc_mapper_ != NULL) ++ { ++ shndx1 = this->lookup_reloc(offset, &start); ++ shndx2 = this->lookup_reloc(offset + addr_size, &end); ++ if (shndx1 != shndx2) ++ gold_warning(_("%s: DWARF info may be corrupt; offsets in a " ++ "range list entry are in different sections"), ++ object->name().c_str()); ++ } ++ prle += addr_size * 2; ++ offset += addr_size * 2; ++ if (shndx1 == 0 || object->is_section_included(shndx1)) ++ ranges->add(shndx1, start, end); ++ break; ++ ++ case elfcpp::DW_RLE_start_length: ++ if (addr_size == 4) ++ start = this->dwinfo_->read_from_pointer<32>(prle); ++ else ++ start = this->dwinfo_->read_from_pointer<64>(prle); ++ if (this->ranges_reloc_mapper_ != NULL) ++ shndx1 = this->lookup_reloc(offset, &start); ++ prle += addr_size; ++ offset += addr_size; ++ end = start + read_unsigned_LEB_128(prle, &len); ++ prle += len; ++ offset += len; ++ if (shndx1 == 0 || object->is_section_included(shndx1)) ++ ranges->add(shndx1, start, end); ++ break; ++ ++ default: ++ gold_warning(_("%s: DWARF range list contains " ++ "unsupported entry type (%d)"), ++ object->name().c_str(), rle_type); ++ break; ++ } ++ } ++ ++ return ranges; ++} ++ + // Look for a relocation at offset OFF in the range table, + // and return the section index and offset of the target. + +@@ -709,7 +845,13 @@ Dwarf_die::read_attributes() + case elfcpp::DW_FORM_flag_present: + attr_value.val.intval = 1; + break; ++ case elfcpp::DW_FORM_implicit_const: ++ attr_value.val.intval = ++ this->abbrev_code_->attributes[i].implicit_const; ++ break; + case elfcpp::DW_FORM_strp: ++ case elfcpp::DW_FORM_strp_sup: ++ case elfcpp::DW_FORM_line_strp: + { + off_t str_off; + if (this->dwinfo_->offset_size() == 4) +@@ -722,6 +864,26 @@ Dwarf_die::read_attributes() + attr_value.val.refval = str_off; + break; + } ++ case elfcpp::DW_FORM_strx: ++ case elfcpp::DW_FORM_GNU_str_index: ++ attr_value.val.uintval = read_unsigned_LEB_128(pattr, &len); ++ pattr += len; ++ break; ++ case elfcpp::DW_FORM_strx1: ++ attr_value.val.uintval = *pattr++; ++ break; ++ case elfcpp::DW_FORM_strx2: ++ attr_value.val.uintval = ++ this->dwinfo_->read_from_pointer<16>(&pattr); ++ break; ++ case elfcpp::DW_FORM_strx3: ++ attr_value.val.uintval = ++ this->dwinfo_->read_3bytes_from_pointer(&pattr); ++ break; ++ case elfcpp::DW_FORM_strx4: ++ attr_value.val.uintval = ++ this->dwinfo_->read_from_pointer<32>(&pattr); ++ break; + case elfcpp::DW_FORM_sec_offset: + { + off_t sec_off; +@@ -747,7 +909,6 @@ Dwarf_die::read_attributes() + this->dwinfo_->lookup_reloc(attr_off, &sec_off); + attr_value.aux.shndx = shndx; + attr_value.val.refval = sec_off; +- ref_form = true; + break; + } + case elfcpp::DW_FORM_ref_addr: +@@ -815,6 +976,7 @@ Dwarf_die::read_attributes() + break; + } + case elfcpp::DW_FORM_ref4: ++ case elfcpp::DW_FORM_ref_sup4: + { + off_t sec_off; + sec_off = this->dwinfo_->read_from_pointer<32>(&pattr); +@@ -835,11 +997,20 @@ Dwarf_die::read_attributes() + attr_value.val.intval = sec_off; + break; + } ++ case elfcpp::DW_FORM_data16: ++ { ++ // For now, treat this as a 16-byte block. ++ attr_value.val.blockval = pattr; ++ attr_value.aux.blocklen = 16; ++ pattr += 16; ++ break; ++ } + case elfcpp::DW_FORM_ref_sig8: + attr_value.val.uintval = + this->dwinfo_->read_from_pointer<64>(&pattr); + break; + case elfcpp::DW_FORM_ref8: ++ case elfcpp::DW_FORM_ref_sup8: + { + off_t sec_off; + sec_off = this->dwinfo_->read_from_pointer<64>(&pattr); +@@ -856,11 +1027,29 @@ Dwarf_die::read_attributes() + pattr += len; + break; + case elfcpp::DW_FORM_udata: ++ attr_value.val.uintval = read_unsigned_LEB_128(pattr, &len); ++ pattr += len; ++ break; ++ case elfcpp::DW_FORM_addrx: + case elfcpp::DW_FORM_GNU_addr_index: +- case elfcpp::DW_FORM_GNU_str_index: + attr_value.val.uintval = read_unsigned_LEB_128(pattr, &len); + pattr += len; + break; ++ case elfcpp::DW_FORM_addrx1: ++ attr_value.val.uintval = *pattr++; ++ break; ++ case elfcpp::DW_FORM_addrx2: ++ attr_value.val.uintval = ++ this->dwinfo_->read_from_pointer<16>(&pattr); ++ break; ++ case elfcpp::DW_FORM_addrx3: ++ attr_value.val.uintval = ++ this->dwinfo_->read_3bytes_from_pointer(&pattr); ++ break; ++ case elfcpp::DW_FORM_addrx4: ++ attr_value.val.uintval = ++ this->dwinfo_->read_from_pointer<32>(&pattr); ++ break; + case elfcpp::DW_FORM_sdata: + attr_value.val.intval = read_signed_LEB_128(pattr, &len); + pattr += len; +@@ -870,6 +1059,11 @@ Dwarf_die::read_attributes() + len = strlen(attr_value.val.stringval); + pattr += len + 1; + break; ++ case elfcpp::DW_FORM_loclistx: ++ case elfcpp::DW_FORM_rnglistx: ++ attr_value.val.uintval = read_unsigned_LEB_128(pattr, &len); ++ pattr += len; ++ break; + default: + return false; + } +@@ -954,9 +1148,12 @@ Dwarf_die::skip_attributes() + switch(form) + { + case elfcpp::DW_FORM_flag_present: ++ case elfcpp::DW_FORM_implicit_const: + break; + case elfcpp::DW_FORM_strp: + case elfcpp::DW_FORM_sec_offset: ++ case elfcpp::DW_FORM_strp_sup: ++ case elfcpp::DW_FORM_line_strp: + pattr += this->dwinfo_->offset_size(); + break; + case elfcpp::DW_FORM_addr: +@@ -993,23 +1190,42 @@ Dwarf_die::skip_attributes() + case elfcpp::DW_FORM_data1: + case elfcpp::DW_FORM_ref1: + case elfcpp::DW_FORM_flag: ++ case elfcpp::DW_FORM_strx1: ++ case elfcpp::DW_FORM_addrx1: + pattr += 1; + break; + case elfcpp::DW_FORM_data2: + case elfcpp::DW_FORM_ref2: ++ case elfcpp::DW_FORM_strx2: ++ case elfcpp::DW_FORM_addrx2: + pattr += 2; + break; ++ case elfcpp::DW_FORM_strx3: ++ case elfcpp::DW_FORM_addrx3: ++ pattr += 3; ++ break; + case elfcpp::DW_FORM_data4: + case elfcpp::DW_FORM_ref4: ++ case elfcpp::DW_FORM_ref_sup4: ++ case elfcpp::DW_FORM_strx4: ++ case elfcpp::DW_FORM_addrx4: + pattr += 4; + break; + case elfcpp::DW_FORM_data8: + case elfcpp::DW_FORM_ref8: + case elfcpp::DW_FORM_ref_sig8: ++ case elfcpp::DW_FORM_ref_sup8: + pattr += 8; + break; ++ case elfcpp::DW_FORM_data16: ++ pattr += 16; ++ break; + case elfcpp::DW_FORM_ref_udata: + case elfcpp::DW_FORM_udata: ++ case elfcpp::DW_FORM_addrx: ++ case elfcpp::DW_FORM_strx: ++ case elfcpp::DW_FORM_loclistx: ++ case elfcpp::DW_FORM_rnglistx: + case elfcpp::DW_FORM_GNU_addr_index: + case elfcpp::DW_FORM_GNU_str_index: + read_unsigned_LEB_128(pattr, &len); +@@ -1313,6 +1529,13 @@ Dwarf_info_reader::do_parse() + elfcpp::Swap_unaligned<16, big_endian>::readval(pinfo); + pinfo += 2; + ++ // DWARF 5: Read the unit type (1 byte) and address size (1 byte). ++ if (this->cu_version_ >= 5) ++ { ++ this->unit_type_ = *pinfo++; ++ this->address_size_ = *pinfo++; ++ } ++ + // Read debug_abbrev_offset (4 or 8 bytes). + if (this->offset_size_ == 4) + abbrev_offset = elfcpp::Swap_unaligned<32, big_endian>::readval(pinfo); +@@ -1333,13 +1556,14 @@ Dwarf_info_reader::do_parse() + } + pinfo += this->offset_size_; + +- // Read address_size (1 byte). +- this->address_size_ = *pinfo++; ++ // DWARF 2-4: Read address_size (1 byte). ++ if (this->cu_version_ < 5) ++ this->address_size_ = *pinfo++; + + // For type units, read the two extra fields. + uint64_t signature = 0; + off_t type_offset = 0; +- if (this->is_type_unit_) ++ if (this->is_type_unit()) + { + if (!this->check_buffer(pinfo + 8 + this->offset_size_)) + break; +@@ -1369,7 +1593,7 @@ Dwarf_info_reader::do_parse() + if (root_die.tag() != 0) + { + // Visit the CU or TU. +- if (this->is_type_unit_) ++ if (this->is_type_unit()) + this->visit_type_unit(section_offset + this->cu_offset_, + cu_end - cu_start, type_offset, signature, + &root_die); +@@ -1460,6 +1684,19 @@ Dwarf_info_reader::read_from_pointer(const unsigned char** source) + return return_value; + } + ++// Read a 3-byte integer. Update SOURCE after read. ++inline typename elfcpp::Valtype_base<32>::Valtype ++Dwarf_info_reader::read_3bytes_from_pointer(const unsigned char** source) ++{ ++ typename elfcpp::Valtype_base<32>::Valtype return_value; ++ if (this->object_->is_big_endian()) ++ return_value = ((*source)[0] << 16) | ((*source)[1] << 8) | (*source)[2]; ++ else ++ return_value = ((*source)[2] << 16) | ((*source)[1] << 8) | (*source)[0]; ++ *source += 3; ++ return return_value; ++} ++ + // Look for a relocation at offset ATTR_OFF in the dwarf info, + // and return the section index and offset of the target. + +@@ -1561,27 +1798,40 @@ Sized_dwarf_line_info::Sized_dwarf_line_info( + Object* object, + unsigned int read_shndx) + : data_valid_(false), buffer_(NULL), buffer_start_(NULL), ++ str_buffer_(NULL), str_buffer_start_(NULL), + reloc_mapper_(NULL), symtab_buffer_(NULL), directories_(), files_(), +- current_header_index_(-1) ++ current_header_index_(-1), reloc_map_(), line_number_map_() + { +- unsigned int debug_shndx; ++ unsigned int debug_line_shndx = 0; ++ unsigned int debug_line_str_shndx = 0; + +- for (debug_shndx = 1; debug_shndx < object->shnum(); ++debug_shndx) ++ for (unsigned int i = 1; i < object->shnum(); ++i) + { ++ section_size_type buffer_size; ++ bool is_new = false; ++ + // FIXME: do this more efficiently: section_name() isn't super-fast +- std::string name = object->section_name(debug_shndx); ++ std::string name = object->section_name(i); + if (name == ".debug_line" || name == ".zdebug_line") + { +- section_size_type buffer_size; +- bool is_new = false; +- this->buffer_ = object->decompressed_section_contents(debug_shndx, +- &buffer_size, +- &is_new); ++ this->buffer_ = ++ object->decompressed_section_contents(i, &buffer_size, &is_new); + if (is_new) + this->buffer_start_ = this->buffer_; + this->buffer_end_ = this->buffer_ + buffer_size; +- break; ++ debug_line_shndx = i; ++ } ++ else if (name == ".debug_line_str" || name == ".zdebug_line_str") ++ { ++ this->str_buffer_ = ++ object->decompressed_section_contents(i, &buffer_size, &is_new); ++ if (is_new) ++ this->str_buffer_start_ = this->str_buffer_; ++ this->str_buffer_end_ = this->str_buffer_ + buffer_size; ++ debug_line_str_shndx = i; + } ++ if (debug_line_shndx > 0 && debug_line_str_shndx > 0) ++ break; + } + if (this->buffer_ == NULL) + return; +@@ -1594,7 +1844,7 @@ Sized_dwarf_line_info::Sized_dwarf_line_info( + unsigned int reloc_sh_type = object->section_type(i); + if ((reloc_sh_type == elfcpp::SHT_REL + || reloc_sh_type == elfcpp::SHT_RELA) +- && object->section_info(i) == debug_shndx) ++ && object->section_info(i) == debug_line_shndx) + { + reloc_shndx = i; + this->track_relocs_type_ = reloc_sh_type; +@@ -1640,65 +1890,80 @@ Sized_dwarf_line_info::read_header_prolog( + uint32_t initial_length = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr); + lineptr += 4; + +- // In DWARF2/3, if the initial length is all 1 bits, then the offset ++ // In DWARF, if the initial length is all 1 bits, then the offset + // size is 8 and we need to read the next 8 bytes for the real length. + if (initial_length == 0xffffffff) + { +- header_.offset_size = 8; ++ this->header_.offset_size = 8; + initial_length = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr); + lineptr += 8; + } + else +- header_.offset_size = 4; ++ this->header_.offset_size = 4; + +- header_.total_length = initial_length; ++ this->header_.total_length = initial_length; + +- gold_assert(lineptr + header_.total_length <= buffer_end_); ++ this->end_of_unit_ = lineptr + initial_length; ++ gold_assert(this->end_of_unit_ <= buffer_end_); + +- header_.version = elfcpp::Swap_unaligned<16, big_endian>::readval(lineptr); ++ this->header_.version = ++ elfcpp::Swap_unaligned<16, big_endian>::readval(lineptr); + lineptr += 2; + +- // Skip address size and segment selector for DWARF5. +- if (header_.version >= 5) +- lineptr += 2; ++ // We can only read versions 2-5 of the DWARF line number table. ++ // For other versions, just skip the entire line number table. ++ if (this->header_.version < 2 || this->header_.version > 5) ++ return this->end_of_unit_; + +- if (header_.offset_size == 4) +- header_.prologue_length = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr); ++ // DWARF 5 only: address size and segment selector. ++ if (this->header_.version >= 5) ++ { ++ this->header_.address_size = *lineptr; ++ // We ignore the segment selector. ++ lineptr += 2; ++ } ++ ++ if (this->header_.offset_size == 4) ++ this->header_.prologue_length = ++ elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr); + else +- header_.prologue_length = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr); +- lineptr += header_.offset_size; ++ this->header_.prologue_length = ++ elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr); ++ lineptr += this->header_.offset_size; + +- header_.min_insn_length = *lineptr; ++ this->end_of_header_length_ = lineptr; ++ ++ this->header_.min_insn_length = *lineptr; + lineptr += 1; + +- if (header_.version < 4) +- header_.max_ops_per_insn = 1; ++ if (this->header_.version < 4) ++ this->header_.max_ops_per_insn = 1; + else + { + // DWARF 4 added the maximum_operations_per_instruction field. +- header_.max_ops_per_insn = *lineptr; ++ this->header_.max_ops_per_insn = *lineptr; + lineptr += 1; + // TODO: Add support for values other than 1. +- gold_assert(header_.max_ops_per_insn == 1); ++ gold_assert(this->header_.max_ops_per_insn == 1); + } + +- header_.default_is_stmt = *lineptr; ++ this->header_.default_is_stmt = *lineptr; + lineptr += 1; + +- header_.line_base = *reinterpret_cast(lineptr); ++ this->header_.line_base = *reinterpret_cast(lineptr); + lineptr += 1; + +- header_.line_range = *lineptr; ++ this->header_.line_range = *lineptr; + lineptr += 1; + +- header_.opcode_base = *lineptr; ++ this->header_.opcode_base = *lineptr; + lineptr += 1; + +- header_.std_opcode_lengths.resize(header_.opcode_base + 1); +- header_.std_opcode_lengths[0] = 0; +- for (int i = 1; i < header_.opcode_base; i++) ++ this->header_.std_opcode_lengths.resize(this->header_.opcode_base + 1); ++ this->header_.std_opcode_lengths[0] = 0; ++ for (int i = 1; i < this->header_.opcode_base; i++) + { +- header_.std_opcode_lengths[i] = *lineptr; ++ this->header_.std_opcode_lengths[i] = *lineptr; + lineptr += 1; + } + +@@ -1707,10 +1972,11 @@ Sized_dwarf_line_info::read_header_prolog( + + // The header for a debug_line section is mildly complicated, because + // the line info is very tightly encoded. ++// This routine is for DWARF versions 2, 3, and 4. + + template + const unsigned char* +-Sized_dwarf_line_info::read_header_tables( ++Sized_dwarf_line_info::read_header_tables_v2( + const unsigned char* lineptr) + { + ++this->current_header_index_; +@@ -1775,6 +2041,169 @@ Sized_dwarf_line_info::read_header_tables( + return lineptr; + } + ++// This routine is for DWARF version 5. ++ ++template ++const unsigned char* ++Sized_dwarf_line_info::read_header_tables_v5( ++ const unsigned char* lineptr) ++{ ++ size_t len; ++ ++ ++this->current_header_index_; ++ ++ gold_assert(static_cast(this->directories_.size()) ++ == this->current_header_index_); ++ gold_assert(static_cast(this->files_.size()) ++ == this->current_header_index_); ++ ++ // Read the directory list. ++ unsigned int format_count = *lineptr; ++ lineptr += 1; ++ ++ unsigned int *types = new unsigned int[format_count]; ++ unsigned int *forms = new unsigned int[format_count]; ++ ++ for (unsigned int i = 0; i < format_count; i++) ++ { ++ types[i] = read_unsigned_LEB_128(lineptr, &len); ++ lineptr += len; ++ forms[i] = read_unsigned_LEB_128(lineptr, &len); ++ lineptr += len; ++ } ++ ++ uint64_t entry_count = read_unsigned_LEB_128(lineptr, &len); ++ lineptr += len; ++ this->directories_.push_back(std::vector(0)); ++ std::vector& dir_list = this->directories_.back(); ++ ++ for (unsigned int j = 0; j < entry_count; j++) ++ { ++ std::string dirname; ++ ++ for (unsigned int i = 0; i < format_count; i++) ++ { ++ if (types[i] == elfcpp::DW_LNCT_path) ++ { ++ if (forms[i] == elfcpp::DW_FORM_string) ++ { ++ dirname = reinterpret_cast(lineptr); ++ lineptr += dirname.size() + 1; ++ } ++ else if (forms[i] == elfcpp::DW_FORM_line_strp) ++ { ++ uint64_t offset; ++ if (this->header_.offset_size == 4) ++ offset = ++ elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr); ++ else ++ offset = ++ elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr); ++ typename Reloc_map::const_iterator it ++ = this->reloc_map_.find(lineptr - this->buffer_); ++ if (it != reloc_map_.end()) ++ { ++ if (this->track_relocs_type_ == elfcpp::SHT_RELA) ++ offset = 0; ++ offset += it->second.second; ++ } ++ lineptr += this->header_.offset_size; ++ dirname = reinterpret_cast(this->str_buffer_ ++ + offset); ++ } ++ else ++ return lineptr; ++ } ++ else ++ return lineptr; ++ } ++ dir_list.push_back(dirname); ++ } ++ ++ delete[] types; ++ delete[] forms; ++ ++ // Read the filenames list. ++ format_count = *lineptr; ++ lineptr += 1; ++ ++ types = new unsigned int[format_count]; ++ forms = new unsigned int[format_count]; ++ ++ for (unsigned int i = 0; i < format_count; i++) ++ { ++ types[i] = read_unsigned_LEB_128(lineptr, &len); ++ lineptr += len; ++ forms[i] = read_unsigned_LEB_128(lineptr, &len); ++ lineptr += len; ++ } ++ ++ entry_count = read_unsigned_LEB_128(lineptr, &len); ++ lineptr += len; ++ this->files_.push_back( ++ std::vector >(0)); ++ std::vector >& file_list = this->files_.back(); ++ ++ for (unsigned int j = 0; j < entry_count; j++) ++ { ++ const char* path = NULL; ++ int dirindex = 0; ++ ++ for (unsigned int i = 0; i < format_count; i++) ++ { ++ if (types[i] == elfcpp::DW_LNCT_path) ++ { ++ if (forms[i] == elfcpp::DW_FORM_string) ++ { ++ path = reinterpret_cast(lineptr); ++ lineptr += strlen(path) + 1; ++ } ++ else if (forms[i] == elfcpp::DW_FORM_line_strp) ++ { ++ uint64_t offset; ++ if (this->header_.offset_size == 4) ++ offset = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr); ++ else ++ offset = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr); ++ typename Reloc_map::const_iterator it ++ = this->reloc_map_.find(lineptr - this->buffer_); ++ if (it != reloc_map_.end()) ++ { ++ if (this->track_relocs_type_ == elfcpp::SHT_RELA) ++ offset = 0; ++ offset += it->second.second; ++ } ++ lineptr += this->header_.offset_size; ++ path = reinterpret_cast(this->str_buffer_ ++ + offset); ++ } ++ else ++ return lineptr; ++ } ++ else if (types[i] == elfcpp::DW_LNCT_directory_index) ++ { ++ if (forms[i] == elfcpp::DW_FORM_udata) ++ { ++ dirindex = read_unsigned_LEB_128(lineptr, &len); ++ lineptr += len; ++ } ++ else ++ return lineptr; ++ } ++ else ++ return lineptr; ++ } ++ gold_debug(DEBUG_LOCATION, "File %3d: %s", ++ static_cast(file_list.size()), path); ++ file_list.push_back(std::make_pair(dirindex, path)); ++ } ++ ++ delete[] types; ++ delete[] forms; ++ ++ return lineptr; ++} ++ + // Process a single opcode in the .debug.line structure. + + template +@@ -1790,15 +2219,15 @@ Sized_dwarf_line_info::process_one_opcode( + + // If the opcode is great than the opcode_base, it is a special + // opcode. Most line programs consist mainly of special opcodes. +- if (opcode >= header_.opcode_base) ++ if (opcode >= this->header_.opcode_base) + { +- opcode -= header_.opcode_base; +- const int advance_address = ((opcode / header_.line_range) +- * header_.min_insn_length); ++ opcode -= this->header_.opcode_base; ++ const int advance_address = ((opcode / this->header_.line_range) ++ * this->header_.min_insn_length); + lsm->address += advance_address; + +- const int advance_line = ((opcode % header_.line_range) +- + header_.line_base); ++ const int advance_line = ((opcode % this->header_.line_range) ++ + this->header_.line_base); + lsm->line_num += advance_line; + lsm->basic_block = true; + *len = oplen; +@@ -1818,13 +2247,13 @@ Sized_dwarf_line_info::process_one_opcode( + const uint64_t advance_address + = read_unsigned_LEB_128(start, &templen); + oplen += templen; +- lsm->address += header_.min_insn_length * advance_address; ++ lsm->address += this->header_.min_insn_length * advance_address; + } + break; + + case elfcpp::DW_LNS_advance_line: + { +- const uint64_t advance_line = read_signed_LEB_128(start, &templen); ++ const int64_t advance_line = read_signed_LEB_128(start, &templen); + oplen += templen; + lsm->line_num += advance_line; + } +@@ -1865,9 +2294,9 @@ Sized_dwarf_line_info::process_one_opcode( + + case elfcpp::DW_LNS_const_add_pc: + { +- const int advance_address = (header_.min_insn_length +- * ((255 - header_.opcode_base) +- / header_.line_range)); ++ const int advance_address = (this->header_.min_insn_length ++ * ((255 - this->header_.opcode_base) ++ / this->header_.line_range)); + lsm->address += advance_address; + } + break; +@@ -1950,7 +2379,7 @@ Sized_dwarf_line_info::process_one_opcode( + default: + { + // Ignore unknown opcode silently +- for (int i = 0; i < header_.std_opcode_lengths[opcode]; i++) ++ for (int i = 0; i < this->header_.std_opcode_lengths[opcode]; i++) + { + size_t templen; + read_unsigned_LEB_128(start, &templen); +@@ -1970,28 +2399,24 @@ Sized_dwarf_line_info::process_one_opcode( + template + unsigned const char* + Sized_dwarf_line_info::read_lines(unsigned const char* lineptr, ++ unsigned const char* endptr, + unsigned int shndx) + { + struct LineStateMachine lsm; + +- // LENGTHSTART is the place the length field is based on. It is the +- // point in the header after the initial length field. +- const unsigned char* lengthstart = buffer_; +- +- // In 64 bit dwarf, the initial length is 12 bytes, because of the +- // 0xffffffff at the start. +- if (header_.offset_size == 8) +- lengthstart += 12; +- else +- lengthstart += 4; +- +- while (lineptr < lengthstart + header_.total_length) ++ while (lineptr < endptr) + { +- ResetLineStateMachine(&lsm, header_.default_is_stmt); ++ ResetLineStateMachine(&lsm, this->header_.default_is_stmt); + while (!lsm.end_sequence) + { + size_t oplength; ++ ++ if (lineptr >= endptr) ++ break; ++ + bool add_line = this->process_one_opcode(lineptr, &lsm, &oplength); ++ lineptr += oplength; ++ + if (add_line + && (shndx == -1U || lsm.shndx == -1U || shndx == lsm.shndx)) + { +@@ -2012,11 +2437,10 @@ Sized_dwarf_line_info::read_lines(unsigned const char* lineptr + map.back().last_line_for_offset = false; + map.push_back(entry); + } +- lineptr += oplength; + } + } + +- return lengthstart + header_.total_length; ++ return endptr; + } + + // Read the relocations into a Reloc_map. +@@ -2057,9 +2481,17 @@ Sized_dwarf_line_info::read_line_mappings(unsigned int shndx) + { + const unsigned char* lineptr = this->buffer_; + lineptr = this->read_header_prolog(lineptr); +- lineptr = this->read_header_tables(lineptr); +- lineptr = this->read_lines(lineptr, shndx); +- this->buffer_ = lineptr; ++ if (this->header_.version >= 2 && this->header_.version <= 4) ++ { ++ lineptr = this->read_header_tables_v2(lineptr); ++ lineptr = this->read_lines(lineptr, this->end_of_unit_, shndx); ++ } ++ else if (this->header_.version == 5) ++ { ++ lineptr = this->read_header_tables_v5(lineptr); ++ lineptr = this->read_lines(lineptr, this->end_of_unit_, shndx); ++ } ++ this->buffer_ = this->end_of_unit_; + } + + // Sort the lines numbers, so addr2line can use binary search. +@@ -2215,6 +2647,9 @@ Sized_dwarf_line_info::do_addr2line( + off_t offset, + std::vector* other_lines) + { ++ gold_debug(DEBUG_LOCATION, "do_addr2line: shndx %u offset %08x", ++ shndx, static_cast(offset)); ++ + if (this->data_valid_ == false) + return ""; + +diff --git a/gold/dwarf_reader.h b/gold/dwarf_reader.h +index 80b2231327c..921a1f7c876 100644 +--- a/gold/dwarf_reader.h ++++ b/gold/dwarf_reader.h +@@ -173,11 +173,12 @@ class Dwarf_abbrev_table + // An attribute list entry. + struct Attribute + { +- Attribute(unsigned int a, unsigned int f) +- : attr(a), form(f) ++ Attribute(unsigned int a, unsigned int f, int c) ++ : attr(a), form(f), implicit_const(c) + { } + unsigned int attr; + unsigned int form; ++ int implicit_const; + }; + + // An abbrev code entry. +@@ -190,9 +191,9 @@ class Dwarf_abbrev_table + } + + void +- add_attribute(unsigned int attr, unsigned int form) ++ add_attribute(unsigned int attr, unsigned int form, int implicit_const) + { +- this->attributes.push_back(Attribute(attr, form)); ++ this->attributes.push_back(Attribute(attr, form, implicit_const)); + } + + // The DWARF tag. +@@ -349,14 +350,15 @@ class Dwarf_ranges_table + delete this->ranges_reloc_mapper_; + } + +- // Read the ranges table from an object file. ++ // Fetch the contents of the ranges table from an object file. + bool + read_ranges_table(Relobj* object, + const unsigned char* symtab, + off_t symtab_size, +- unsigned int ranges_shndx); ++ unsigned int ranges_shndx, ++ unsigned int version); + +- // Read the range table from an object file. ++ // Read the DWARF 2/3/4 range table. + Dwarf_range_list* + read_range_list(Relobj* object, + const unsigned char* symtab, +@@ -365,6 +367,15 @@ class Dwarf_ranges_table + unsigned int ranges_shndx, + off_t ranges_offset); + ++ // Read the DWARF 5 rnglists table. ++ Dwarf_range_list* ++ read_range_list_v5(Relobj* object, ++ const unsigned char* symtab, ++ off_t symtab_size, ++ unsigned int address_size, ++ unsigned int ranges_shndx, ++ off_t ranges_offset); ++ + // Look for a relocation at offset OFF in the range table, + // and return the section index and offset of the target. + unsigned int +@@ -490,8 +501,6 @@ class Dwarf_die + unsigned int shndx; + // Block length for block forms. + unsigned int blocklen; +- // Attribute offset for DW_FORM_strp. +- unsigned int attr_off; + } aux; + }; + +@@ -684,6 +693,10 @@ class Dwarf_die + // calls the various visit_xxx() methods for each header. Clients + // should derive a new class from this one and implement the + // visit_compilation_unit() and visit_type_unit() functions. ++// IS_TYPE_UNIT is true if we are reading from a .debug_types section, ++// which is used only in DWARF 4. For DWARF 5, it will be false, ++// and we will determine whether it's a type init when we parse the ++// header. + + class Dwarf_info_reader + { +@@ -695,7 +708,7 @@ class Dwarf_info_reader + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type) +- : is_type_unit_(is_type_unit), object_(object), symtab_(symtab), ++ : object_(object), symtab_(symtab), + symtab_size_(symtab_size), shndx_(shndx), reloc_shndx_(reloc_shndx), + reloc_type_(reloc_type), abbrev_shndx_(0), string_shndx_(0), + buffer_(NULL), buffer_end_(NULL), cu_offset_(0), cu_length_(0), +@@ -703,7 +716,12 @@ class Dwarf_info_reader + abbrev_table_(), ranges_table_(this), + reloc_mapper_(NULL), string_buffer_(NULL), string_buffer_end_(NULL), + owns_string_buffer_(false), string_output_section_offset_(0) +- { } ++ { ++ // For DWARF 4, we infer the unit type from the section name. ++ // For DWARF 5, we will read this from the unit header. ++ this->unit_type_ = ++ (is_type_unit ? elfcpp::DW_UT_type : elfcpp::DW_UT_compile); ++ } + + virtual + ~Dwarf_info_reader() +@@ -714,6 +732,13 @@ class Dwarf_info_reader + delete[] this->string_buffer_; + } + ++ bool ++ is_type_unit() const ++ { ++ return (this->unit_type_ == elfcpp::DW_UT_type ++ || this->unit_type_ == elfcpp::DW_UT_split_type); ++ } ++ + // Begin parsing the debug info. This calls visit_compilation_unit() + // or visit_type_unit() for each compilation or type unit found in the + // section, and visit_die() for each top-level DIE. +@@ -745,6 +770,9 @@ class Dwarf_info_reader + inline typename elfcpp::Valtype_base::Valtype + read_from_pointer(const unsigned char** source); + ++ inline typename elfcpp::Valtype_base<32>::Valtype ++ read_3bytes_from_pointer(const unsigned char** source); ++ + // Look for a relocation at offset ATTR_OFF in the dwarf info, + // and return the section index and offset of the target. + unsigned int +@@ -818,12 +846,20 @@ class Dwarf_info_reader + Dwarf_range_list* + read_range_list(unsigned int ranges_shndx, off_t ranges_offset) + { +- return this->ranges_table_.read_range_list(this->object_, +- this->symtab_, +- this->symtab_size_, +- this->address_size_, +- ranges_shndx, +- ranges_offset); ++ if (this->cu_version_ < 5) ++ return this->ranges_table_.read_range_list(this->object_, ++ this->symtab_, ++ this->symtab_size_, ++ this->address_size_, ++ ranges_shndx, ++ ranges_offset); ++ else ++ return this->ranges_table_.read_range_list_v5(this->object_, ++ this->symtab_, ++ this->symtab_size_, ++ this->address_size_, ++ ranges_shndx, ++ ranges_offset); + } + + // Return the object. +@@ -873,8 +909,8 @@ class Dwarf_info_reader + bool + do_read_string_table(unsigned int string_shndx); + +- // True if this is a type unit; false for a compilation unit. +- bool is_type_unit_; ++ // The unit type (DW_UT_xxx). ++ unsigned int unit_type_; + // The object containing the .debug_info or .debug_types input section. + Relobj* object_; + // The ELF symbol table. +@@ -1008,6 +1044,8 @@ class Sized_dwarf_line_info : public Dwarf_line_info + { + if (this->buffer_start_ != NULL) + delete[] this->buffer_start_; ++ if (this->str_buffer_start_ != NULL) ++ delete[] this->str_buffer_start_; + } + + private: +@@ -1030,19 +1068,23 @@ class Sized_dwarf_line_info : public Dwarf_line_info + void + read_relocs(); + +- // Reads the DWARF2/3 header for this line info. Each takes as input ++ // Reads the DWARF header for this line info. Each takes as input + // a starting buffer position, and returns the ending position. + const unsigned char* + read_header_prolog(const unsigned char* lineptr); + + const unsigned char* +- read_header_tables(const unsigned char* lineptr); ++ read_header_tables_v2(const unsigned char* lineptr); ++ ++ const unsigned char* ++ read_header_tables_v5(const unsigned char* lineptr); + +- // Reads the DWARF2/3 line information. If shndx is non-negative, ++ // Reads the DWARF line information. If shndx is non-negative, + // discard all line information that doesn't pertain to the given + // section. + const unsigned char* +- read_lines(const unsigned char* lineptr, unsigned int shndx); ++ read_lines(const unsigned char* lineptr, const unsigned char* endptr, ++ unsigned int shndx); + + // Process a single line info opcode at START using the state + // machine at LSM. Return true if we should define a line using the +@@ -1069,6 +1111,7 @@ class Sized_dwarf_line_info : public Dwarf_line_info + { + off_t total_length; + int version; ++ int address_size; + off_t prologue_length; + int min_insn_length; // insn stands for instruction + int max_ops_per_insn; // Added in DWARF-4. +@@ -1089,6 +1132,20 @@ class Sized_dwarf_line_info : public Dwarf_line_info + // of the buffer. + const unsigned char* buffer_start_; + ++ // str_buffer is the buffer for the line table strings. ++ const unsigned char* str_buffer_; ++ const unsigned char* str_buffer_end_; ++ // If the buffer was allocated temporarily, and therefore must be ++ // deallocated in the dtor, this contains a pointer to the start ++ // of the buffer. ++ const unsigned char* str_buffer_start_; ++ ++ // Pointer to the end of the header_length field (aka prologue_length). ++ const unsigned char* end_of_header_length_; ++ ++ // Pointer to the end of the current compilation unit. ++ const unsigned char* end_of_unit_; ++ + // This has relocations that point into buffer. + Sized_elf_reloc_mapper* reloc_mapper_; + // The type of the reloc section in track_relocs_--SHT_REL or SHT_RELA. -- cgit 1.2.3-korg