aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2007-11-13 01:26:27 +0000
committerIan Lance Taylor <iant@google.com>2007-11-13 01:26:27 +0000
commitaf674d1d6c9874056b9893f3f8c3b60464d6380f (patch)
tree477fd45b410a0ecb150f3756c6142b83aa7e8fc0
parentf4c43811f70f34738c0ee211903fdfc25fac1ef6 (diff)
downloadgdb-af674d1d6c9874056b9893f3f8c3b60464d6380f.zip
gdb-af674d1d6c9874056b9893f3f8c3b60464d6380f.tar.gz
gdb-af674d1d6c9874056b9893f3f8c3b60464d6380f.tar.bz2
From Craig Silverstein: Support debug info for shared libraries.
-rw-r--r--gold/dwarf_reader.cc136
-rw-r--r--gold/dwarf_reader.h24
2 files changed, 110 insertions, 50 deletions
diff --git a/gold/dwarf_reader.cc b/gold/dwarf_reader.cc
index c8bf05c..4e7217b 100644
--- a/gold/dwarf_reader.cc
+++ b/gold/dwarf_reader.cc
@@ -119,7 +119,7 @@ ResetLineStateMachine(struct LineStateMachine* lsm, bool default_is_stmt)
template<int size, bool big_endian>
Dwarf_line_info<size, big_endian>::Dwarf_line_info(Object* object)
: data_valid_(false), buffer_(NULL), symtab_buffer_(NULL),
- directories_(1), files_(1)
+ directories_(), files_(), current_header_index_(-1)
{
unsigned int debug_shndx;
for (debug_shndx = 0; debug_shndx < object->shnum(); ++debug_shndx)
@@ -135,6 +135,7 @@ Dwarf_line_info<size, big_endian>::Dwarf_line_info(Object* object)
return;
// Find the relocation section for ".debug_line".
+ // We expect these for relobjs (.o's) but not dynobjs (.so's).
bool got_relocs = false;
for (unsigned int reloc_shndx = 0;
reloc_shndx < object->shnum();
@@ -150,22 +151,21 @@ Dwarf_line_info<size, big_endian>::Dwarf_line_info(Object* object)
break;
}
}
- if (!got_relocs)
- return;
// Finally, we need the symtab section to interpret the relocs.
- unsigned int symtab_shndx;
- for (symtab_shndx = 0; symtab_shndx < object->shnum(); ++symtab_shndx)
- if (object->section_type(symtab_shndx) == elfcpp::SHT_SYMTAB)
- {
- off_t symtab_size;
- this->symtab_buffer_ = object->section_contents(
- symtab_shndx, &symtab_size, false);
- this->symtab_buffer_end_ = this->symtab_buffer_ + symtab_size;
- break;
- }
- if (this->symtab_buffer_ == NULL)
- return;
+ if (got_relocs)
+ {
+ unsigned int symtab_shndx;
+ for (symtab_shndx = 0; symtab_shndx < object->shnum(); ++symtab_shndx)
+ if (object->section_type(symtab_shndx) == elfcpp::SHT_SYMTAB)
+ {
+ this->symtab_buffer_ = object->section_contents(
+ symtab_shndx, &this->symtab_buffer_size_, false);
+ break;
+ }
+ if (this->symtab_buffer_ == NULL)
+ return;
+ }
// Now that we have successfully read all the data, parse the debug
// info.
@@ -241,16 +241,29 @@ const unsigned char*
Dwarf_line_info<size, big_endian>::read_header_tables(
const unsigned char* lineptr)
{
+ ++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_);
+ this->directories_.push_back(std::vector<std::string>(1));
+ this->files_.push_back(std::vector<std::pair<int, std::string> >(1));
+
// It is legal for the directory entry table to be empty.
if (*lineptr)
{
int dirindex = 1;
while (*lineptr)
{
- const unsigned char* dirname = lineptr;
- gold_assert(dirindex == static_cast<int>(directories_.size()));
- directories_.push_back(reinterpret_cast<const char*>(dirname));
- lineptr += directories_.back().size() + 1;
+ const char* dirname = reinterpret_cast<const char*>(lineptr);
+ gold_assert(dirindex
+ == static_cast<int>(this->directories_.back().size()));
+ this->directories_.back().push_back(dirname);
+ lineptr += this->directories_.back().back().size() + 1;
dirindex++;
}
}
@@ -267,18 +280,21 @@ Dwarf_line_info<size, big_endian>::read_header_tables(
lineptr += strlen(filename) + 1;
uint64_t dirindex = read_unsigned_LEB_128(lineptr, &len);
- if (dirindex >= directories_.size())
- dirindex = 0;
lineptr += len;
+ if (dirindex >= this->directories_.back().size())
+ dirindex = 0;
+ int dirindexi = static_cast<int>(dirindex);
+
read_unsigned_LEB_128(lineptr, &len); // mod_time
lineptr += len;
read_unsigned_LEB_128(lineptr, &len); // filelength
lineptr += len;
- gold_assert(fileindex == static_cast<int>(files_.size()));
- files_.push_back(std::pair<int, std::string>(dirindex, filename));
+ gold_assert(fileindex
+ == static_cast<int>(this->files_.back().size()));
+ this->files_.back().push_back(std::make_pair(dirindexi, filename));
fileindex++;
}
}
@@ -407,21 +423,21 @@ Dwarf_line_info<size, big_endian>::process_one_opcode(
case elfcpp::DW_LNE_set_address:
{
+ lsm->address = elfcpp::Swap<size, big_endian>::readval(start);
typename Reloc_map::const_iterator it
= reloc_map_.find(start - this->buffer_);
if (it != reloc_map_.end())
{
// value + addend.
- lsm->address =
- (elfcpp::Swap<size, big_endian>::readval(start)
- + it->second.second);
+ lsm->address += it->second.second;
lsm->shndx = it->second.first;
}
else
{
- // Every set_address should have an associated
- // relocation.
- this->data_valid_ = false;
+ // If we're a normal .o file, with relocs, every
+ // set_address should have an associated relocation.
+ if (this->input_is_relobj())
+ this->data_valid_ = false;
}
break;
}
@@ -432,17 +448,19 @@ Dwarf_line_info<size, big_endian>::process_one_opcode(
start += templen;
uint64_t dirindex = read_unsigned_LEB_128(start, &templen);
- if (dirindex >= directories_.size())
- dirindex = 0;
oplen += templen;
+ if (dirindex >= this->directories_.back().size())
+ dirindex = 0;
+ int dirindexi = static_cast<int>(dirindex);
+
read_unsigned_LEB_128(start, &templen); // mod_time
oplen += templen;
read_unsigned_LEB_128(start, &templen); // filelength
oplen += templen;
- files_.push_back(std::pair<int, std::string>(dirindex,
+ this->files_.back().push_back(std::make_pair(dirindexi,
filename));
}
break;
@@ -497,7 +515,8 @@ Dwarf_line_info<size, big_endian>::read_lines(unsigned const char* lineptr)
if (add_line)
{
Offset_to_lineno_entry entry
- = { lsm.address, lsm.file_num, lsm.line_num };
+ = { lsm.address, this->current_header_index_,
+ lsm.file_num, lsm.line_num };
line_number_map_[lsm.shndx].push_back(entry);
}
lineptr += oplength;
@@ -516,7 +535,7 @@ Dwarf_line_info<size, big_endian>::symbol_section(
typename elfcpp::Elf_types<size>::Elf_Addr* value)
{
const int symsize = elfcpp::Elf_sizes<size>::sym_size;
- gold_assert(this->symtab_buffer_ + sym * symsize < this->symtab_buffer_end_);
+ gold_assert(sym * symsize < this->symtab_buffer_size_);
elfcpp::Sym<size, big_endian> elfsym(this->symtab_buffer_ + sym * symsize);
*value = elfsym.get_st_value();
return elfsym.get_st_shndx();
@@ -568,6 +587,21 @@ Dwarf_line_info<size, big_endian>::read_line_mappings()
std::sort(it->second.begin(), it->second.end());
}
+// Some processing depends on whether the input is a .o file or not.
+// For instance, .o files have relocs, and have .debug_lines
+// information on a per section basis. .so files, on the other hand,
+// lack relocs, and offsets are unique, so we can ignore the section
+// information.
+
+template<int size, bool big_endian>
+bool
+Dwarf_line_info<size, big_endian>::input_is_relobj()
+{
+ // Only .o files have relocs and the symtab buffer that goes with them.
+ return this->symtab_buffer_ != NULL;
+}
+
+
// Return a string for a file name and line number.
template<int size, bool big_endian>
@@ -577,19 +611,26 @@ Dwarf_line_info<size, big_endian>::addr2line(unsigned int shndx, off_t offset)
if (this->data_valid_ == false)
return "";
- const Offset_to_lineno_entry lookup_key = { offset, 0, 0 };
- std::vector<Offset_to_lineno_entry>& offsets = this->line_number_map_[shndx];
- if (offsets.empty())
+ const Offset_to_lineno_entry lookup_key = { offset, 0, 0, 0 };
+ const std::vector<Offset_to_lineno_entry>* offsets;
+ // If we do not have reloc information, then our input is a .so or
+ // some similar data structure where all the information is held in
+ // the offset. In that case, we ignore the input shndx.
+ if (this->input_is_relobj())
+ offsets = &this->line_number_map_[shndx];
+ else
+ offsets = &this->line_number_map_[-1U];
+ if (offsets->empty())
return "";
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
// before the passed-in offset.
if (it->offset > offset)
{
- if (it == offsets.begin())
+ if (it == offsets->begin())
return "";
--it;
gold_assert(it->offset < offset);
@@ -597,11 +638,20 @@ Dwarf_line_info<size, big_endian>::addr2line(unsigned int shndx, off_t offset)
// Convert the file_num + line_num into a string.
std::string ret;
- gold_assert(it->file_num < static_cast<int>(files_.size()));
- const std::pair<int, std::string>& filename_pair = files_[it->file_num];
- gold_assert(filename_pair.first < static_cast<int>(directories_.size()));
- const std::string& dirname = directories_[filename_pair.first];
+
+ gold_assert(it->header_num < static_cast<int>(this->files_.size()));
+ gold_assert(it->file_num
+ < static_cast<int>(this->files_[it->header_num].size()));
+ const std::pair<int, std::string>& filename_pair
+ = this->files_[it->header_num][it->file_num];
const std::string& filename = filename_pair.second;
+
+ gold_assert(it->header_num < static_cast<int>(this->directories_.size()));
+ gold_assert(filename_pair.first
+ < static_cast<int>(this->directories_[it->header_num].size()));
+ const std::string& dirname
+ = this->directories_[it->header_num][filename_pair.first];
+
if (!dirname.empty())
{
ret += dirname;
diff --git a/gold/dwarf_reader.h b/gold/dwarf_reader.h
index c5347e4..d35cbf1 100644
--- a/gold/dwarf_reader.h
+++ b/gold/dwarf_reader.h
@@ -90,6 +90,10 @@ class Dwarf_line_info
process_one_opcode(const unsigned char* start,
struct LineStateMachine* lsm, size_t* len);
+ // Some parts of processing differ depending on whether the input
+ // was a .o file or not.
+ bool input_is_relobj();
+
// If we saw anything amiss while parsing, we set this to false.
// Then addr2line will always fail (rather than return possibly-
// corrupt data).
@@ -123,15 +127,20 @@ class Dwarf_line_info
// This is used to figure out what section to apply a relocation to.
const unsigned char* symtab_buffer_;
- const unsigned char* symtab_buffer_end_;
+ off_t symtab_buffer_size_;
- // Holds the directories and files as we see them.
- std::vector<std::string> directories_;
+ // Holds the directories and files as we see them. We have an array
+ // of directory-lists, one for each .o file we're reading (usually
+ // there will just be one, but there may be more if input is a .so).
+ std::vector<std::vector<std::string> > directories_;
// The first part is an index into directories_, the second the filename.
- std::vector< std::pair<int, std::string> > files_;
+ std::vector<std::vector< std::pair<int, std::string> > > files_;
+
+ // An index into the current directories_ and files_ vectors.
+ int current_header_index_;
- // A map from offset of the relocation target to the shndx and
- // addend for the relocation.
+ // A sorted map from offset of the relocation target to the shndx
+ // and addend for the relocation.
typedef std::map<typename elfcpp::Elf_types<size>::Elf_Addr,
std::pair<unsigned int,
typename elfcpp::Elf_types<size>::Elf_Swxword> >
@@ -143,8 +152,9 @@ class Dwarf_line_info
struct Offset_to_lineno_entry
{
off_t offset;
+ int header_num; // which file-list to use (i.e. which .o file are we in)
int file_num; // a pointer into files_
- int line_num;
+ int line_num; // the line number in the source file
// Offsets are unique within a section, so that's a sufficient sort key.
bool operator<(const Offset_to_lineno_entry& that) const
{ return this->offset < that.offset; }