diff options
author | Ian Lance Taylor <iant@google.com> | 2007-11-13 01:26:27 +0000 |
---|---|---|
committer | Ian Lance Taylor <iant@google.com> | 2007-11-13 01:26:27 +0000 |
commit | af674d1d6c9874056b9893f3f8c3b60464d6380f (patch) | |
tree | 477fd45b410a0ecb150f3756c6142b83aa7e8fc0 | |
parent | f4c43811f70f34738c0ee211903fdfc25fac1ef6 (diff) | |
download | gdb-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.cc | 136 | ||||
-rw-r--r-- | gold/dwarf_reader.h | 24 |
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; } |