forked from Imagelibrary/binutils-gdb
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.
This commit is contained in:
@@ -147,7 +147,13 @@ enum DW_LINE_OPS
|
|||||||
// DWARF 3.
|
// DWARF 3.
|
||||||
DW_LNS_set_prologue_end = 10,
|
DW_LNS_set_prologue_end = 10,
|
||||||
DW_LNS_set_epilogue_begin = 11,
|
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.
|
// Line number extended opcodes.
|
||||||
@@ -235,6 +241,20 @@ enum DW_SECT
|
|||||||
DW_SECT_MAX = DW_SECT_MACRO,
|
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.
|
} // End namespace elfcpp.
|
||||||
|
|
||||||
#endif // !defined(ELFCPP_DWARF_H)
|
#endif // !defined(ELFCPP_DWARF_H)
|
||||||
|
|||||||
@@ -38,9 +38,11 @@ const int DEBUG_SCRIPT = 0x2;
|
|||||||
const int DEBUG_FILES = 0x4;
|
const int DEBUG_FILES = 0x4;
|
||||||
const int DEBUG_RELAXATION = 0x8;
|
const int DEBUG_RELAXATION = 0x8;
|
||||||
const int DEBUG_INCREMENTAL = 0x10;
|
const int DEBUG_INCREMENTAL = 0x10;
|
||||||
|
const int DEBUG_LOCATION = 0x20;
|
||||||
|
|
||||||
const int DEBUG_ALL = (DEBUG_TASK | DEBUG_SCRIPT | DEBUG_FILES
|
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.
|
// Convert a debug string to the appropriate enum.
|
||||||
inline int
|
inline int
|
||||||
@@ -54,6 +56,7 @@ debug_string_to_enum(const char* arg)
|
|||||||
{ "files", DEBUG_FILES },
|
{ "files", DEBUG_FILES },
|
||||||
{ "relaxation", DEBUG_RELAXATION },
|
{ "relaxation", DEBUG_RELAXATION },
|
||||||
{ "incremental", DEBUG_INCREMENTAL },
|
{ "incremental", DEBUG_INCREMENTAL },
|
||||||
|
{ "location", DEBUG_LOCATION },
|
||||||
{ "all", DEBUG_ALL }
|
{ "all", DEBUG_ALL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
#include "elfcpp_swap.h"
|
#include "elfcpp_swap.h"
|
||||||
#include "dwarf.h"
|
#include "dwarf.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
@@ -1526,6 +1527,7 @@ struct LineStateMachine
|
|||||||
bool is_stmt; // stmt means statement.
|
bool is_stmt; // stmt means statement.
|
||||||
bool basic_block;
|
bool basic_block;
|
||||||
bool end_sequence;
|
bool end_sequence;
|
||||||
|
unsigned int context;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1539,6 +1541,7 @@ ResetLineStateMachine(struct LineStateMachine* lsm, bool default_is_stmt)
|
|||||||
lsm->is_stmt = default_is_stmt;
|
lsm->is_stmt = default_is_stmt;
|
||||||
lsm->basic_block = false;
|
lsm->basic_block = false;
|
||||||
lsm->end_sequence = false;
|
lsm->end_sequence = false;
|
||||||
|
lsm->context = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
@@ -1546,27 +1549,40 @@ Sized_dwarf_line_info<size, big_endian>::Sized_dwarf_line_info(
|
|||||||
Object* object,
|
Object* object,
|
||||||
unsigned int read_shndx)
|
unsigned int read_shndx)
|
||||||
: data_valid_(false), buffer_(NULL), buffer_start_(NULL),
|
: data_valid_(false), buffer_(NULL), buffer_start_(NULL),
|
||||||
|
str_buffer_(NULL), str_buffer_start_(NULL),
|
||||||
reloc_mapper_(NULL), symtab_buffer_(NULL), directories_(), files_(),
|
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)
|
||||||
{
|
|
||||||
// FIXME: do this more efficiently: section_name() isn't super-fast
|
|
||||||
std::string name = object->section_name(debug_shndx);
|
|
||||||
if (name == ".debug_line" || name == ".zdebug_line")
|
|
||||||
{
|
{
|
||||||
section_size_type buffer_size;
|
section_size_type buffer_size;
|
||||||
bool is_new = false;
|
bool is_new = false;
|
||||||
this->buffer_ = object->decompressed_section_contents(debug_shndx,
|
|
||||||
&buffer_size,
|
// FIXME: do this more efficiently: section_name() isn't super-fast
|
||||||
&is_new);
|
std::string name = object->section_name(i);
|
||||||
|
if (name == ".debug_line" || name == ".zdebug_line")
|
||||||
|
{
|
||||||
|
this->buffer_ =
|
||||||
|
object->decompressed_section_contents(i, &buffer_size, &is_new);
|
||||||
if (is_new)
|
if (is_new)
|
||||||
this->buffer_start_ = this->buffer_;
|
this->buffer_start_ = this->buffer_;
|
||||||
this->buffer_end_ = this->buffer_ + buffer_size;
|
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)
|
if (this->buffer_ == NULL)
|
||||||
return;
|
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);
|
unsigned int reloc_sh_type = object->section_type(i);
|
||||||
if ((reloc_sh_type == elfcpp::SHT_REL
|
if ((reloc_sh_type == elfcpp::SHT_REL
|
||||||
|| reloc_sh_type == elfcpp::SHT_RELA)
|
|| reloc_sh_type == elfcpp::SHT_RELA)
|
||||||
&& object->section_info(i) == debug_shndx)
|
&& object->section_info(i) == debug_line_shndx)
|
||||||
{
|
{
|
||||||
reloc_shndx = i;
|
reloc_shndx = i;
|
||||||
this->track_relocs_type_ = reloc_sh_type;
|
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
|
// Now that we have successfully read all the data, parse the debug
|
||||||
// info.
|
// info.
|
||||||
this->data_valid_ = true;
|
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);
|
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;
|
header_.total_length = initial_length;
|
||||||
|
|
||||||
const unsigned char* end_of_initial_length = lineptr;
|
this->end_of_unit_ = lineptr + initial_length;
|
||||||
gold_assert(lineptr + header_.total_length <= buffer_end_);
|
gold_assert(this->end_of_unit_ <= buffer_end_);
|
||||||
|
|
||||||
header_.version = elfcpp::Swap_unaligned<16, big_endian>::readval(lineptr);
|
header_.version = elfcpp::Swap_unaligned<16, big_endian>::readval(lineptr);
|
||||||
lineptr += 2;
|
lineptr += 2;
|
||||||
|
|
||||||
// We can only read versions 2 and 3 of the DWARF line number table.
|
// We can only read versions 2 and 3 of the DWARF line number table.
|
||||||
// For other versions, just skip the entire line number table.
|
// For other versions, just skip the entire line number table.
|
||||||
if (header_.version < 2 || header_.version > 3)
|
if ((header_.version < 2 || header_.version > 4)
|
||||||
return end_of_initial_length + initial_length;
|
&& header_.version != DWARF5_EXPERIMENTAL_LINE_TABLE)
|
||||||
|
return this->end_of_unit_;
|
||||||
|
|
||||||
if (header_.offset_size == 4)
|
if (header_.offset_size == 4)
|
||||||
header_.prologue_length = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr);
|
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);
|
header_.prologue_length = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr);
|
||||||
lineptr += header_.offset_size;
|
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;
|
header_.min_insn_length = *lineptr;
|
||||||
lineptr += 1;
|
lineptr += 1;
|
||||||
|
|
||||||
|
if (header_.version >= 4)
|
||||||
|
{
|
||||||
|
header_.max_ops_per_insn = *lineptr;
|
||||||
|
lineptr += 1;
|
||||||
|
}
|
||||||
|
|
||||||
header_.default_is_stmt = *lineptr;
|
header_.default_is_stmt = *lineptr;
|
||||||
lineptr += 1;
|
lineptr += 1;
|
||||||
|
|
||||||
@@ -1678,6 +1709,32 @@ Sized_dwarf_line_info<size, big_endian>::read_header_prolog(
|
|||||||
lineptr += 1;
|
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;
|
return lineptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1751,12 +1808,180 @@ Sized_dwarf_line_info<size, big_endian>::read_header_tables(
|
|||||||
return lineptr;
|
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.
|
// Process a single opcode in the .debug.line structure.
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
bool
|
bool
|
||||||
Sized_dwarf_line_info<size, big_endian>::process_one_opcode(
|
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 oplen = 0;
|
||||||
size_t templen;
|
size_t templen;
|
||||||
@@ -1800,7 +2025,7 @@ Sized_dwarf_line_info<size, big_endian>::process_one_opcode(
|
|||||||
|
|
||||||
case elfcpp::DW_LNS_advance_line:
|
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;
|
oplen += templen;
|
||||||
lsm->line_num += advance_line;
|
lsm->line_num += advance_line;
|
||||||
}
|
}
|
||||||
@@ -1848,6 +2073,61 @@ Sized_dwarf_line_info<size, big_endian>::process_one_opcode(
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
case elfcpp::DW_LNS_extended_op:
|
||||||
{
|
{
|
||||||
const uint64_t extended_op_len
|
const uint64_t extended_op_len
|
||||||
@@ -1945,37 +2225,74 @@ Sized_dwarf_line_info<size, big_endian>::process_one_opcode(
|
|||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
unsigned const char*
|
unsigned const char*
|
||||||
Sized_dwarf_line_info<size, big_endian>::read_lines(unsigned const char* lineptr,
|
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)
|
unsigned int shndx)
|
||||||
{
|
{
|
||||||
struct LineStateMachine lsm;
|
struct LineStateMachine lsm;
|
||||||
|
|
||||||
// LENGTHSTART is the place the length field is based on. It is the
|
while (lineptr < endptr)
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
ResetLineStateMachine(&lsm, header_.default_is_stmt);
|
ResetLineStateMachine(&lsm, header_.default_is_stmt);
|
||||||
while (!lsm.end_sequence)
|
while (!lsm.end_sequence)
|
||||||
{
|
{
|
||||||
size_t oplength;
|
size_t oplength;
|
||||||
bool add_line = this->process_one_opcode(lineptr, &lsm, &oplength);
|
if (lineptr >= endptr)
|
||||||
if (add_line
|
break;
|
||||||
&& (shndx == -1U || lsm.shndx == -1U || shndx == lsm.shndx))
|
|
||||||
|
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
|
if (is_logicals_table)
|
||||||
= { static_cast<off_t>(lsm.address),
|
{
|
||||||
this->current_header_index_,
|
logicals->push_back(lsm);
|
||||||
static_cast<unsigned int>(lsm.file_num),
|
gold_debug(DEBUG_LOCATION, "Logical %d [%3u:%08x]: "
|
||||||
true, lsm.line_num };
|
"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>&
|
std::vector<Offset_to_lineno_entry>&
|
||||||
map(this->line_number_map_[lsm.shndx]);
|
map(this->line_number_map_[lsm.shndx]);
|
||||||
// If we see two consecutive entries with the same
|
// If we see two consecutive entries with the same
|
||||||
@@ -1988,11 +2305,12 @@ Sized_dwarf_line_info<size, big_endian>::read_lines(unsigned const char* lineptr
|
|||||||
map.back().last_line_for_offset = false;
|
map.back().last_line_for_offset = false;
|
||||||
map.push_back(entry);
|
map.push_back(entry);
|
||||||
}
|
}
|
||||||
lineptr += oplength;
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lengthstart + header_.total_length;
|
return endptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the relocations into a Reloc_map.
|
// 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_)
|
while (this->buffer_ < this->buffer_end_)
|
||||||
{
|
{
|
||||||
const unsigned char* lineptr = this->buffer_;
|
const unsigned char* lineptr = this->buffer_;
|
||||||
|
std::vector<LineStateMachine> logicals;
|
||||||
|
|
||||||
lineptr = this->read_header_prolog(lineptr);
|
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_header_tables(lineptr);
|
||||||
lineptr = this->read_lines(lineptr, shndx);
|
lineptr = this->read_lines(this->logicals_start_,
|
||||||
|
this->end_of_unit_,
|
||||||
|
NULL,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
shndx);
|
||||||
}
|
}
|
||||||
this->buffer_ = lineptr;
|
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_ = this->end_of_unit_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort the lines numbers, so addr2line can use binary search.
|
// 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,
|
off_t offset,
|
||||||
std::vector<std::string>* other_lines)
|
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)
|
if (this->data_valid_ == false)
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
|
|||||||
@@ -1001,9 +1001,13 @@ class Sized_dwarf_line_info : public Dwarf_line_info
|
|||||||
{
|
{
|
||||||
if (this->buffer_start_ != NULL)
|
if (this->buffer_start_ != NULL)
|
||||||
delete[] this->buffer_start_;
|
delete[] this->buffer_start_;
|
||||||
|
if (this->str_buffer_start_ != NULL)
|
||||||
|
delete[] this->str_buffer_start_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const static int DWARF5_EXPERIMENTAL_LINE_TABLE = 0xf006;
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
do_addr2line(unsigned int shndx, off_t offset,
|
do_addr2line(unsigned int shndx, off_t offset,
|
||||||
std::vector<std::string>* other_lines);
|
std::vector<std::string>* other_lines);
|
||||||
@@ -1031,11 +1035,17 @@ class Sized_dwarf_line_info : public Dwarf_line_info
|
|||||||
const unsigned char*
|
const unsigned char*
|
||||||
read_header_tables(const unsigned char* lineptr);
|
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,
|
// Reads the DWARF2/3 line information. If shndx is non-negative,
|
||||||
// discard all line information that doesn't pertain to the given
|
// discard all line information that doesn't pertain to the given
|
||||||
// section.
|
// section.
|
||||||
const unsigned char*
|
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
|
// Process a single line info opcode at START using the state
|
||||||
// machine at LSM. Return true if we should define a line using the
|
// 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.
|
// opcode in LEN.
|
||||||
bool
|
bool
|
||||||
process_one_opcode(const unsigned char* start,
|
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
|
// Some parts of processing differ depending on whether the input
|
||||||
// was a .o file or not.
|
// was a .o file or not.
|
||||||
@@ -1064,6 +1076,7 @@ class Sized_dwarf_line_info : public Dwarf_line_info
|
|||||||
int version;
|
int version;
|
||||||
off_t prologue_length;
|
off_t prologue_length;
|
||||||
int min_insn_length; // insn stands for instructin
|
int min_insn_length; // insn stands for instructin
|
||||||
|
int max_ops_per_insn;
|
||||||
bool default_is_stmt; // stmt stands for statement
|
bool default_is_stmt; // stmt stands for statement
|
||||||
signed char line_base;
|
signed char line_base;
|
||||||
int line_range;
|
int line_range;
|
||||||
@@ -1081,6 +1094,26 @@ class Sized_dwarf_line_info : public Dwarf_line_info
|
|||||||
// of the buffer.
|
// of the buffer.
|
||||||
const unsigned char* buffer_start_;
|
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.
|
// This has relocations that point into buffer.
|
||||||
Sized_elf_reloc_mapper<size, big_endian>* reloc_mapper_;
|
Sized_elf_reloc_mapper<size, big_endian>* reloc_mapper_;
|
||||||
// The type of the reloc section in track_relocs_--SHT_REL or SHT_RELA.
|
// The type of the reloc section in track_relocs_--SHT_REL or SHT_RELA.
|
||||||
|
|||||||
Reference in New Issue
Block a user