diff options
author | Cary Coutant <ccoutant@google.com> | 2015-01-30 04:22:19 -0800 |
---|---|---|
committer | Cary Coutant <ccoutant@google.com> | 2015-02-22 23:43:57 -0800 |
commit | f0c3f9ad7bd53affee7fc222efed007f2d02ac8f (patch) | |
tree | 33322d6d3fa9a644ba22d730d1adc6700186e0ad | |
parent | 589778e030658d5aa1a90623f72728b875d1cd3c (diff) | |
download | gdb-f0c3f9ad7bd53affee7fc222efed007f2d02ac8f.zip gdb-f0c3f9ad7bd53affee7fc222efed007f2d02ac8f.tar.gz gdb-f0c3f9ad7bd53affee7fc222efed007f2d02ac8f.tar.bz2 |
Add gold support for two-level line tables.
2015-01-30 Cary Coutant <ccoutant@google.com>
elfcpp/
* dwarf.h (enum DW_LNS): Add experimental two-level line table opcodes.
(enum DW_LNCT): New enum for DWARF-5.
gold/
* debug.h (DEBUG_LOCATION): New constant.
(debug_string_to_enum): Add DEBUG_LOCATION.
* dwarf_reader.cc (struct LineStateMachine): Add context field.
(ResetLineStateMachine): Likewise.
(Sized_dwarf_line_info::Sized_dwarf_line_info): Add support for
two-level line tables.
(Sized_dwarf_line_info::read_header_prolog): Likewise. Also add
support for DWARF-3+ line tables.
(Sized_dwarf_line_info::read_header_tables_v5): New method.
(Sized_dwarf_line_info::process_one_opcode): Add support for two-level
line tables.
(Sized_dwarf_line_info::read_lines): Likewise.
(Sized_dwarf_line_info::read_line_mappings): Likewise.
(Sized_dwarf_line_info::do_addr2line): Add debug output.
* dwarf_reader.h (Sized_dwarf_line_info::~Sized_dwarf_line_info):
Delete str_buffer_start_.
(DWARF5_EXPERIMENTAL_LINE_TABLE): New constant.
(Sized_dwarf_line_info::read_header_tables_v5): New method.
(Sized_dwarf_line_info::read_lines): Update prototype.
(Sized_dwarf_line_info::process_one_opcode): Likewise.
(Sized_dwarf_line_info::max_ops_per_insn): New data member.
(Sized_dwarf_line_info::str_buffer_): New data member.
(Sized_dwarf_line_info::str_buffer_end_): New data member.
(Sized_dwarf_line_info::str_buffer_start_): New data member.
(Sized_dwarf_line_info::end_of_header_length_): New data member.
(Sized_dwarf_line_info::logicals_start_): New data member.
(Sized_dwarf_line_info::actuals_start_): New data member.
(Sized_dwarf_line_info::end_of_unit_): New data member.
-rw-r--r-- | elfcpp/dwarf.h | 22 | ||||
-rw-r--r-- | gold/debug.h | 5 | ||||
-rw-r--r-- | gold/dwarf_reader.cc | 466 | ||||
-rw-r--r-- | gold/dwarf_reader.h | 37 |
4 files changed, 471 insertions, 59 deletions
diff --git a/elfcpp/dwarf.h b/elfcpp/dwarf.h index ccd967e..7534d68 100644 --- a/elfcpp/dwarf.h +++ b/elfcpp/dwarf.h @@ -147,7 +147,13 @@ enum DW_LINE_OPS // DWARF 3. DW_LNS_set_prologue_end = 10, DW_LNS_set_epilogue_begin = 11, - DW_LNS_set_isa = 12 + DW_LNS_set_isa = 12, + /* Experimental DWARF 5 extensions. + See http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables. */ + DW_LNS_set_address_from_logical = 13, /* Actuals table only. */ + DW_LNS_set_subprogram = 13, /* Logicals table only. */ + DW_LNS_inlined_call = 14, /* Logicals table only. */ + DW_LNS_pop_context = 15 /* Logicals table only. */ }; // Line number extended opcodes. @@ -235,6 +241,20 @@ enum DW_SECT DW_SECT_MAX = DW_SECT_MACRO, }; +enum DW_LNCT +{ + DW_LNCT_path = 1, + DW_LNCT_directory_index = 2, + DW_LNCT_timestamp = 3, + DW_LNCT_size = 4, + DW_LNCT_MD5 = 5, + /* Experimental DWARF 5 extensions. + See http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables. */ + DW_LNCT_subprogram_name = 6, + DW_LNCT_decl_file = 7, + DW_LNCT_decl_line = 8 +}; + } // End namespace elfcpp. #endif // !defined(ELFCPP_DWARF_H) diff --git a/gold/debug.h b/gold/debug.h index bca55f3..3fecbd8 100644 --- a/gold/debug.h +++ b/gold/debug.h @@ -38,9 +38,11 @@ const int DEBUG_SCRIPT = 0x2; const int DEBUG_FILES = 0x4; const int DEBUG_RELAXATION = 0x8; const int DEBUG_INCREMENTAL = 0x10; +const int DEBUG_LOCATION = 0x20; const int DEBUG_ALL = (DEBUG_TASK | DEBUG_SCRIPT | DEBUG_FILES - | DEBUG_RELAXATION | DEBUG_INCREMENTAL); + | DEBUG_RELAXATION | DEBUG_INCREMENTAL + | DEBUG_LOCATION); // Convert a debug string to the appropriate enum. inline int @@ -54,6 +56,7 @@ debug_string_to_enum(const char* arg) { "files", DEBUG_FILES }, { "relaxation", DEBUG_RELAXATION }, { "incremental", DEBUG_INCREMENTAL }, + { "location", DEBUG_LOCATION }, { "all", DEBUG_ALL } }; diff --git a/gold/dwarf_reader.cc b/gold/dwarf_reader.cc index bd641d1..6049704 100644 --- a/gold/dwarf_reader.cc +++ b/gold/dwarf_reader.cc @@ -26,6 +26,7 @@ #include <utility> #include <vector> +#include "debug.h" #include "elfcpp_swap.h" #include "dwarf.h" #include "object.h" @@ -1526,6 +1527,7 @@ struct LineStateMachine bool is_stmt; // stmt means statement. bool basic_block; bool end_sequence; + unsigned int context; }; static void @@ -1539,6 +1541,7 @@ ResetLineStateMachine(struct LineStateMachine* lsm, bool default_is_stmt) lsm->is_stmt = default_is_stmt; lsm->basic_block = false; lsm->end_sequence = false; + lsm->context = 0; } template<int size, bool big_endian> @@ -1546,27 +1549,40 @@ Sized_dwarf_line_info<size, big_endian>::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; @@ -1579,7 +1595,7 @@ Sized_dwarf_line_info<size, big_endian>::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; @@ -1612,6 +1628,8 @@ Sized_dwarf_line_info<size, big_endian>::Sized_dwarf_line_info( // Now that we have successfully read all the data, parse the debug // info. this->data_valid_ = true; + gold_debug(DEBUG_LOCATION, "read_line_mappings: %s shndx %u", + object->name().c_str(), read_shndx); this->read_line_mappings(read_shndx); } @@ -1638,16 +1656,17 @@ Sized_dwarf_line_info<size, big_endian>::read_header_prolog( header_.total_length = initial_length; - const unsigned char* end_of_initial_length = lineptr; - 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); lineptr += 2; // We can only read versions 2 and 3 of the DWARF line number table. // For other versions, just skip the entire line number table. - if (header_.version < 2 || header_.version > 3) - return end_of_initial_length + initial_length; + if ((header_.version < 2 || header_.version > 4) + && header_.version != DWARF5_EXPERIMENTAL_LINE_TABLE) + return this->end_of_unit_; if (header_.offset_size == 4) header_.prologue_length = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr); @@ -1655,9 +1674,21 @@ Sized_dwarf_line_info<size, big_endian>::read_header_prolog( header_.prologue_length = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr); lineptr += header_.offset_size; + this->end_of_header_length_ = lineptr; + + // If this is a two-level line table, we'll adjust these below. + this->logicals_start_ = lineptr + header_.prologue_length; + this->actuals_start_ = NULL; + header_.min_insn_length = *lineptr; lineptr += 1; + if (header_.version >= 4) + { + header_.max_ops_per_insn = *lineptr; + lineptr += 1; + } + header_.default_is_stmt = *lineptr; lineptr += 1; @@ -1678,6 +1709,32 @@ Sized_dwarf_line_info<size, big_endian>::read_header_prolog( lineptr += 1; } + if (header_.version == DWARF5_EXPERIMENTAL_LINE_TABLE) + { + // Skip over fake empty directory and filename tables, + // and fake extended opcode that hides the rest of the + // section from old consumers. + lineptr += 7; + + // Offsets to logicals and actuals tables. + off_t logicals_offset; + off_t actuals_offset; + if (header_.offset_size == 4) + logicals_offset = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr); + else + logicals_offset = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr); + lineptr += header_.offset_size; + if (header_.offset_size == 4) + actuals_offset = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr); + else + actuals_offset = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr); + lineptr += header_.offset_size; + + this->logicals_start_ = this->end_of_header_length_ + logicals_offset; + if (actuals_offset > 0) + this->actuals_start_ = this->end_of_header_length_ + actuals_offset; + } + return lineptr; } @@ -1751,12 +1808,180 @@ Sized_dwarf_line_info<size, big_endian>::read_header_tables( return lineptr; } +template<int size, bool big_endian> +const unsigned char* +Sized_dwarf_line_info<size, big_endian>::read_header_tables_v5( + const unsigned char* lineptr) +{ + size_t len; + + ++this->current_header_index_; + + // Create a new directories_ entry and a new files_ entry for our new + // header. We initialize each with a single empty element, because + // dwarf indexes directory and filenames starting at 1. + gold_assert(static_cast<int>(this->directories_.size()) + == this->current_header_index_); + gold_assert(static_cast<int>(this->files_.size()) + == this->current_header_index_); + + // Read the directory list. + uint64_t format_count = read_unsigned_LEB_128(lineptr, &len); + lineptr += len; + + 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<std::string>(1)); + std::vector<std::string>& 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<const char*>(lineptr); + lineptr += dirname.size() + 1; + } + else if (forms[i] == elfcpp::DW_FORM_line_strp) + { + uint64_t offset; + if (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 += header_.offset_size; + dirname = reinterpret_cast<const char*>(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 = read_unsigned_LEB_128(lineptr, &len); + lineptr += len; + + 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<std::pair<int, std::string> >(1)); + std::vector<std::pair<int, std::string> >& 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<const char*>(lineptr); + lineptr += strlen(path) + 1; + } + else if (forms[i] == elfcpp::DW_FORM_line_strp) + { + uint64_t offset; + if (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 += header_.offset_size; + path = reinterpret_cast<const char*>(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<int>(file_list.size()), path); + file_list.push_back(std::make_pair<int, std::string>(dirindex, path)); + } + + delete[] types; + delete[] forms; + + // Ignore the subprograms table; we don't need it for now. + // Because it's the last thing in the header, we don't need + // to figure out how long it is to skip over it. + + return lineptr; +} + // Process a single opcode in the .debug.line structure. template<int size, bool big_endian> bool Sized_dwarf_line_info<size, big_endian>::process_one_opcode( - const unsigned char* start, struct LineStateMachine* lsm, size_t* len) + const unsigned char* start, struct LineStateMachine* lsm, size_t* len, + std::vector<LineStateMachine>* logicals, + bool is_logicals_table, bool is_actuals_table) { size_t oplen = 0; size_t templen; @@ -1800,7 +2025,7 @@ Sized_dwarf_line_info<size, big_endian>::process_one_opcode( 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; } @@ -1848,6 +2073,61 @@ Sized_dwarf_line_info<size, big_endian>::process_one_opcode( } break; + case elfcpp::DW_LNS_set_subprogram: + // aliased with elfcpp::DW_LNS_set_address_from_logical + if (is_actuals_table) + { + // elfcpp::DW_LNS_set_address_from_logical + const int64_t advance_line = read_signed_LEB_128(start, &templen); + oplen += templen; + lsm->line_num += advance_line; + if (lsm->line_num >= 1 + && lsm->line_num <= static_cast<int64_t>(logicals->size())) + { + const LineStateMachine& logical = (*logicals)[lsm->line_num - 1]; + lsm->address = logical.address; + lsm->shndx = logical.shndx; + } + } + else if (is_logicals_table) + { + // elfcpp::DW_LNS_set_subprogram + // Ignore the subprogram number for now. + read_unsigned_LEB_128(start, &templen); + oplen += templen; + lsm->context = 0; + } + break; + + case elfcpp::DW_LNS_inlined_call: + if (is_logicals_table) + { + const int64_t advance_line = read_signed_LEB_128(start, &templen); + oplen += templen; + start += templen; + // Ignore the subprogram number for now. + read_unsigned_LEB_128(start, &templen); + oplen += templen; + lsm->context = logicals->size() + advance_line; + } + break; + + case elfcpp::DW_LNS_pop_context: + if (is_logicals_table) + { + const unsigned int context = lsm->context; + if (context >= 1 && context <= logicals->size()) + { + const LineStateMachine& logical = (*logicals)[context - 1]; + lsm->file_num = logical.file_num; + lsm->line_num = logical.line_num; + lsm->column_num = logical.column_num; + lsm->is_stmt = logical.is_stmt; + lsm->context = logical.context; + } + } + break; + case elfcpp::DW_LNS_extended_op: { const uint64_t extended_op_len @@ -1945,54 +2225,92 @@ Sized_dwarf_line_info<size, big_endian>::process_one_opcode( template<int size, bool big_endian> unsigned const char* -Sized_dwarf_line_info<size, big_endian>::read_lines(unsigned const char* lineptr, - unsigned int shndx) +Sized_dwarf_line_info<size, big_endian>::read_lines( + unsigned const char* lineptr, + unsigned const char* endptr, + std::vector<LineStateMachine>* logicals, + bool is_logicals_table, + bool is_actuals_table, + 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); while (!lsm.end_sequence) { size_t oplength; - bool add_line = this->process_one_opcode(lineptr, &lsm, &oplength); - if (add_line - && (shndx == -1U || lsm.shndx == -1U || shndx == lsm.shndx)) + if (lineptr >= endptr) + break; + + bool add_line = this->process_one_opcode(lineptr, &lsm, &oplength, + logicals, + is_logicals_table, + is_actuals_table); + lineptr += oplength; + + if (add_line) { - Offset_to_lineno_entry entry - = { static_cast<off_t>(lsm.address), - this->current_header_index_, - static_cast<unsigned int>(lsm.file_num), - true, lsm.line_num }; - std::vector<Offset_to_lineno_entry>& - map(this->line_number_map_[lsm.shndx]); - // If we see two consecutive entries with the same - // offset and a real line number, then mark the first - // one as non-canonical. - if (!map.empty() - && (map.back().offset == static_cast<off_t>(lsm.address)) - && lsm.line_num != -1 - && map.back().line_num != -1) - map.back().last_line_for_offset = false; - map.push_back(entry); + if (is_logicals_table) + { + logicals->push_back(lsm); + gold_debug(DEBUG_LOCATION, "Logical %d [%3u:%08x]: " + "file %d line %d context %u", + static_cast<int>(logicals->size()), + lsm.shndx, static_cast<int>(lsm.address), + lsm.file_num, lsm.line_num, lsm.context); + } + else if (shndx == -1U || lsm.shndx == -1U || shndx == lsm.shndx) + { + Offset_to_lineno_entry entry; + + if (is_actuals_table && lsm.line_num != -1) + { + if (lsm.line_num < 1 + || lsm.line_num > static_cast<int64_t>(logicals->size())) + continue; + const LineStateMachine& logical = + (*logicals)[lsm.line_num - 1]; + gold_debug(DEBUG_LOCATION, "Actual [%3u:%08x]: " + "logical %u file %d line %d context %u", + lsm.shndx, static_cast<int>(lsm.address), + lsm.line_num, logical.file_num, + logical.line_num, lsm.context); + entry.offset = static_cast<off_t>(lsm.address); + entry.header_num = this->current_header_index_; + entry.file_num = + static_cast<unsigned int>(logical.file_num); + entry.last_line_for_offset = true; + entry.line_num = logical.line_num; + } + else + { + entry.offset = static_cast<off_t>(lsm.address); + entry.header_num = this->current_header_index_; + entry.file_num = static_cast<unsigned int>(lsm.file_num); + entry.last_line_for_offset = true; + entry.line_num = lsm.line_num; + } + + std::vector<Offset_to_lineno_entry>& + map(this->line_number_map_[lsm.shndx]); + // If we see two consecutive entries with the same + // offset and a real line number, then mark the first + // one as non-canonical. + if (!map.empty() + && (map.back().offset == static_cast<off_t>(lsm.address)) + && lsm.line_num != -1 + && map.back().line_num != -1) + 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. @@ -2032,13 +2350,48 @@ Sized_dwarf_line_info<size, big_endian>::read_line_mappings(unsigned int shndx) while (this->buffer_ < this->buffer_end_) { const unsigned char* lineptr = this->buffer_; + std::vector<LineStateMachine> logicals; + lineptr = this->read_header_prolog(lineptr); - if (header_.version >= 2 && header_.version <= 3) + if (header_.version >= 2 && header_.version <= 4) { lineptr = this->read_header_tables(lineptr); - lineptr = this->read_lines(lineptr, shndx); + lineptr = this->read_lines(this->logicals_start_, + this->end_of_unit_, + NULL, + false, + false, + shndx); + } + else if (header_.version == DWARF5_EXPERIMENTAL_LINE_TABLE) + { + lineptr = this->read_header_tables_v5(lineptr); + if (this->actuals_start_ != NULL) + { + lineptr = this->read_lines(this->logicals_start_, + this->actuals_start_, + &logicals, + true, + false, + shndx); + lineptr = this->read_lines(this->actuals_start_, + this->end_of_unit_, + &logicals, + false, + true, + shndx); + } + else + { + lineptr = this->read_lines(this->logicals_start_, + this->end_of_unit_, + NULL, + false, + false, + shndx); + } } - this->buffer_ = lineptr; + this->buffer_ = this->end_of_unit_; } // Sort the lines numbers, so addr2line can use binary search. @@ -2194,6 +2547,9 @@ Sized_dwarf_line_info<size, big_endian>::do_addr2line( off_t offset, std::vector<std::string>* other_lines) { + gold_debug(DEBUG_LOCATION, "do_addr2line: shndx %u offset %08x", + shndx, static_cast<int>(offset)); + if (this->data_valid_ == false) return ""; diff --git a/gold/dwarf_reader.h b/gold/dwarf_reader.h index 0792c1c..389e77c 100644 --- a/gold/dwarf_reader.h +++ b/gold/dwarf_reader.h @@ -1001,9 +1001,13 @@ 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: + const static int DWARF5_EXPERIMENTAL_LINE_TABLE = 0xf006; + std::string do_addr2line(unsigned int shndx, off_t offset, std::vector<std::string>* other_lines); @@ -1031,11 +1035,17 @@ class Sized_dwarf_line_info : public Dwarf_line_info const unsigned char* read_header_tables(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, // 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, + std::vector<LineStateMachine>* logicals, + bool is_logicals_table, bool is_actuals_table, + 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 @@ -1043,7 +1053,9 @@ class Sized_dwarf_line_info : public Dwarf_line_info // opcode in LEN. bool process_one_opcode(const unsigned char* start, - struct LineStateMachine* lsm, size_t* len); + struct LineStateMachine* lsm, size_t* len, + std::vector<LineStateMachine>* logicals, + bool is_logicals_table, bool is_actuals_table); // Some parts of processing differ depending on whether the input // was a .o file or not. @@ -1064,6 +1076,7 @@ class Sized_dwarf_line_info : public Dwarf_line_info int version; off_t prologue_length; int min_insn_length; // insn stands for instructin + int max_ops_per_insn; bool default_is_stmt; // stmt stands for statement signed char line_base; int line_range; @@ -1081,6 +1094,26 @@ class Sized_dwarf_line_info : public Dwarf_line_info // of the buffer. const unsigned char* buffer_start_; + // buffer is the buffer for our line info, starting at exactly where + // the line info to read is. + 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). + // The offsets to the line number programs are relative to this point. + const unsigned char* end_of_header_length_; + + // Pointers to the start of the line number programs. + const unsigned char* logicals_start_; + const unsigned char* actuals_start_; + + // 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<size, big_endian>* reloc_mapper_; // The type of the reloc section in track_relocs_--SHT_REL or SHT_RELA. |