From Craig Silverstein: Templatize the Dwarf reader.

This commit is contained in:
Ian Lance Taylor
2007-11-07 00:49:56 +00:00
parent a7a81c1d9d
commit e43872e995
3 changed files with 40 additions and 62 deletions

View File

@ -118,7 +118,8 @@ ResetLineStateMachine(struct LineStateMachine* lsm, bool default_is_stmt)
template<int size, bool big_endian> template<int size, bool big_endian>
const unsigned char* const unsigned char*
Dwarf_line_info::read_header_prolog(const unsigned char* lineptr) Dwarf_line_info<size, big_endian>::read_header_prolog(
const unsigned char* lineptr)
{ {
uint32_t initial_length = elfcpp::Swap<32, big_endian>::readval(lineptr); uint32_t initial_length = elfcpp::Swap<32, big_endian>::readval(lineptr);
lineptr += 4; lineptr += 4;
@ -176,8 +177,10 @@ Dwarf_line_info::read_header_prolog(const unsigned char* lineptr)
// The header for a debug_line section is mildly complicated, because // The header for a debug_line section is mildly complicated, because
// the line info is very tightly encoded. // the line info is very tightly encoded.
template<int size, bool big_endian>
const unsigned char* const unsigned char*
Dwarf_line_info::read_header_tables(const unsigned char* lineptr) Dwarf_line_info<size, big_endian>::read_header_tables(
const unsigned char* lineptr)
{ {
// It is legal for the directory entry table to be empty. // It is legal for the directory entry table to be empty.
if (*lineptr) if (*lineptr)
@ -231,11 +234,10 @@ Dwarf_line_info::read_header_tables(const unsigned char* lineptr)
// simpler) code, but would bloat the binary. Speed isn't important // simpler) code, but would bloat the binary. Speed isn't important
// here. // here.
template<int size, bool big_endian>
bool bool
Dwarf_line_info::process_one_opcode(int size, bool big_endian, Dwarf_line_info<size, big_endian>::process_one_opcode(
const unsigned char* start, const unsigned char* start, struct LineStateMachine* lsm, size_t* len)
struct LineStateMachine* lsm,
size_t* len)
{ {
size_t oplen = 0; size_t oplen = 0;
size_t templen; size_t templen;
@ -312,10 +314,7 @@ Dwarf_line_info::process_one_opcode(int size, bool big_endian,
case elfcpp::DW_LNS_fixed_advance_pc: case elfcpp::DW_LNS_fixed_advance_pc:
{ {
int advance_address; int advance_address;
if (big_endian) advance_address = elfcpp::Swap<16, big_endian>::readval(start);
advance_address = elfcpp::Swap<16, true>::readval(start);
else
advance_address = elfcpp::Swap<16, false>::readval(start);
oplen += 2; oplen += 2;
lsm->address += advance_address; lsm->address += advance_address;
} }
@ -349,16 +348,7 @@ Dwarf_line_info::process_one_opcode(int size, bool big_endian,
case elfcpp::DW_LNE_set_address: case elfcpp::DW_LNE_set_address:
// FIXME: modify the address based on the reloc // FIXME: modify the address based on the reloc
if (size == 32 && big_endian == false) lsm->address = elfcpp::Swap<size, big_endian>::readval(start);
lsm->address = elfcpp::Swap<32, false>::readval(start);
else if (size == 32 && big_endian == true)
lsm->address = elfcpp::Swap<32, true>::readval(start);
else if (size == 64 && big_endian == false)
lsm->address = elfcpp::Swap<64, false>::readval(start);
else if (size == 64 && big_endian == true)
lsm->address = elfcpp::Swap<64, true>::readval(start);
else
gold_assert(false); // We need to implement more cases, then.
// FIXME: set lsm->shndx from the reloc // FIXME: set lsm->shndx from the reloc
lsm->shndx = 1; lsm->shndx = 1;
break; break;
@ -408,9 +398,9 @@ Dwarf_line_info::process_one_opcode(int size, bool big_endian,
// Read the debug information at LINEPTR and store it in the line // Read the debug information at LINEPTR and store it in the line
// number map. // number map.
template<int size, bool big_endian>
unsigned const char* unsigned const char*
Dwarf_line_info::read_lines(int size, bool big_endian, Dwarf_line_info<size, big_endian>::read_lines(unsigned const char* lineptr)
unsigned const char* lineptr)
{ {
struct LineStateMachine lsm; struct LineStateMachine lsm;
@ -431,8 +421,7 @@ Dwarf_line_info::read_lines(int size, bool big_endian,
while (!lsm.end_sequence) while (!lsm.end_sequence)
{ {
size_t oplength; size_t oplength;
bool add_line = this->process_one_opcode(size, big_endian, bool add_line = this->process_one_opcode(lineptr, &lsm, &oplength);
lineptr, &lsm, &oplength);
if (add_line) if (add_line)
{ {
Offset_to_lineno_entry entry Offset_to_lineno_entry entry
@ -446,12 +435,21 @@ Dwarf_line_info::read_lines(int size, bool big_endian,
return lengthstart + header_.total_length; return lengthstart + header_.total_length;
} }
// Called after all line numbers have been read. template<int size, bool big_endian>
void void
Dwarf_line_info::finalize_line_number_map() Dwarf_line_info<size, big_endian>::read_line_mappings()
{ {
for (Lineno_map::iterator it = line_number_map_.begin(); while (buffer_ < buffer_end_)
{
const unsigned char* lineptr = buffer_;
lineptr = this->read_header_prolog(lineptr);
lineptr = this->read_header_tables(lineptr);
lineptr = this->read_lines(lineptr);
buffer_ = lineptr;
}
// Sort the lines numbers, so addr2line can use binary search.
for (typename Lineno_map::iterator it = line_number_map_.begin();
it != line_number_map_.end(); it != line_number_map_.end();
++it) ++it)
// Each vector needs to be sorted by offset. // Each vector needs to be sorted by offset.
@ -460,12 +458,13 @@ Dwarf_line_info::finalize_line_number_map()
// Return a string for a file name and line number. // Return a string for a file name and line number.
template<int size, bool big_endian>
std::string std::string
Dwarf_line_info::addr2line(unsigned int shndx, off_t offset) Dwarf_line_info<size, big_endian>::addr2line(unsigned int shndx, off_t offset)
{ {
const Offset_to_lineno_entry lookup_key = { offset, 0, 0 }; const Offset_to_lineno_entry lookup_key = { offset, 0, 0 };
std::vector<Offset_to_lineno_entry>& offsets = line_number_map_[shndx]; std::vector<Offset_to_lineno_entry>& offsets = line_number_map_[shndx];
std::vector<Offset_to_lineno_entry>::const_iterator it typename std::vector<Offset_to_lineno_entry>::const_iterator it
= std::lower_bound(offsets.begin(), offsets.end(), lookup_key); = std::lower_bound(offsets.begin(), offsets.end(), lookup_key);
// If we found an exact match, great, otherwise find the last entry // If we found an exact match, great, otherwise find the last entry
@ -504,26 +503,22 @@ Dwarf_line_info::addr2line(unsigned int shndx, off_t offset)
#ifdef HAVE_TARGET_32_LITTLE #ifdef HAVE_TARGET_32_LITTLE
template template
const unsigned char* class Dwarf_line_info<32, false>;
Dwarf_line_info::read_header_prolog<32, false>(const unsigned char* lineptr);
#endif #endif
#ifdef HAVE_TARGET_32_BIG #ifdef HAVE_TARGET_32_BIG
template template
const unsigned char* class Dwarf_line_info<32, true>;
Dwarf_line_info::read_header_prolog<32, true>(const unsigned char* lineptr);
#endif #endif
#ifdef HAVE_TARGET_64_LITTLE #ifdef HAVE_TARGET_64_LITTLE
template template
const unsigned char* class Dwarf_line_info<64, false>;
Dwarf_line_info::read_header_prolog<64, false>(const unsigned char* lineptr);
#endif #endif
#ifdef HAVE_TARGET_64_BIG #ifdef HAVE_TARGET_64_BIG
template template
const unsigned char* class Dwarf_line_info<64, true>;
Dwarf_line_info::read_header_prolog<64, true>(const unsigned char* lineptr);
#endif #endif
} // End namespace gold. } // End namespace gold.

View File

@ -36,6 +36,7 @@ struct LineStateMachine;
// This class is used to read the line information from the debugging // This class is used to read the line information from the debugging
// section of an object file. // section of an object file.
template<int size, bool big_endian>
class Dwarf_line_info class Dwarf_line_info
{ {
public: public:
@ -49,20 +50,8 @@ class Dwarf_line_info
{ } { }
// Start processing line info, and populates the offset_map_. // Start processing line info, and populates the offset_map_.
template<int size, bool big_endian>
void void
read_line_mappings() read_line_mappings();
{
while (buffer_ < buffer_end_)
{
const unsigned char* lineptr = buffer_;
lineptr = this->read_header_prolog<size, big_endian>(lineptr);
lineptr = this->read_header_tables(lineptr);
lineptr = this->read_lines(size, big_endian, lineptr);
buffer_ = lineptr;
}
finalize_line_number_map();
}
// Given a section number and an offset, returns the associated // Given a section number and an offset, returns the associated
// file and line-number, as a string: "file:lineno". If unable // file and line-number, as a string: "file:lineno". If unable
@ -74,7 +63,6 @@ class Dwarf_line_info
private: private:
// Reads the DWARF2/3 header for this line info. Each takes as input // Reads the DWARF2/3 header for this line info. Each takes as input
// a starting buffer position, and returns the ending position. // a starting buffer position, and returns the ending position.
template<int size, bool big_endian>
const unsigned char* const unsigned char*
read_header_prolog(const unsigned char* lineptr); read_header_prolog(const unsigned char* lineptr);
@ -83,22 +71,16 @@ class Dwarf_line_info
// Reads the DWARF2/3 line information. // Reads the DWARF2/3 line information.
const unsigned char* const unsigned char*
read_lines(int size, bool big_endian, const unsigned char* lineptr); read_lines(const unsigned char* lineptr);
// 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
// current state of the line state machine. Place the length of the // current state of the line state machine. Place the length of the
// opcode in LEN. // opcode in LEN.
bool bool
process_one_opcode(int size, bool big_endian, process_one_opcode(const unsigned char* start,
const unsigned char* start,
struct LineStateMachine* lsm, size_t* len); struct LineStateMachine* lsm, size_t* len);
// Called after all line number have been read, to ready
// line_number_map_ for calls to addr2line().
void
finalize_line_number_map();
// A DWARF2/3 line info header. This is not the same size as in the // A DWARF2/3 line info header. This is not the same size as in the
// actual file, as the one in the file may have a 32 bit or 64 bit // actual file, as the one in the file may have a 32 bit or 64 bit
// lengths. // lengths.

View File

@ -919,8 +919,9 @@ Relocate_info<size, big_endian>::location(size_t, off_t offset) const
shndx, &debuglines_size, false); shndx, &debuglines_size, false);
if (debuglines) if (debuglines)
{ {
Dwarf_line_info line_info(debuglines, debuglines_size); Dwarf_line_info<size, big_endian> line_info(debuglines,
line_info.read_line_mappings<size, big_endian>(); debuglines_size);
line_info.read_line_mappings();
file_and_lineno = line_info.addr2line(this->data_shndx, offset); file_and_lineno = line_info.addr2line(this->data_shndx, offset);
} }
break; break;