Index: gold/dwarf_reader.cc =================================================================== RCS file: /cvs/src/src/gold/dwarf_reader.cc,v retrieving revision 1.31 diff -u -r1.31 dwarf_reader.cc --- gold/dwarf_reader.cc 20 Dec 2010 18:37:36 -0000 1.31 +++ gold/dwarf_reader.cc 3 Feb 2011 06:15:20 -0000 @@ -61,6 +61,29 @@ lsm->end_sequence = false; } +std::string +Source_location::str() const +{ + std::string ret; + if (this->filename == NULL) + return ret; // "", but in a way that the NRVO still works. + if (this->dirname != NULL && !this->dirname->empty()) + { + ret += *this->dirname; + ret += '/'; + } + ret += *this->filename; + if (ret.empty()) + ret = "(unknown)"; + + char buffer[64]; // enough to hold a line number + snprintf(buffer, sizeof(buffer), "%d", this->line_num); + ret += ':'; + ret += buffer; + + return ret; +} + template Sized_dwarf_line_info::Sized_dwarf_line_info(Object* object, unsigned int read_shndx) @@ -717,15 +740,15 @@ return offsets->end(); } -// Return a string for a file name and line number. +// Return a Source_location for an offset. template -std::string +Source_location Sized_dwarf_line_info::do_addr2line(unsigned int shndx, off_t offset) { if (this->data_valid_ == false) - return ""; + return Source_location(); const std::vector* offsets; // If we do not have reloc information, then our input is a .so or @@ -736,16 +759,14 @@ else offsets = &this->line_number_map_[-1U]; if (offsets->empty()) - return ""; + return Source_location(); typename std::vector::const_iterator it = offset_to_iterator(offsets, offset); if (it == offsets->end()) - return ""; - - // Convert the file_num + line_num into a string. - std::string ret; + return Source_location(); + // Convert the file_num into a directory and file name. gold_assert(it->header_num < static_cast(this->files_.size())); gold_assert(it->file_num < static_cast(this->files_[it->header_num].size())); @@ -759,21 +780,7 @@ const std::string& dirname = this->directories_[it->header_num][filename_pair.first]; - if (!dirname.empty()) - { - ret += dirname; - ret += "/"; - } - ret += filename; - if (ret.empty()) - ret = "(unknown)"; - - char buffer[64]; // enough to hold a line number - snprintf(buffer, sizeof(buffer), "%d", it->line_num); - ret += ":"; - ret += buffer; - - return ret; + return Source_location(&dirname, &filename, it->line_num); } // Dwarf_line_info routines. @@ -800,7 +807,7 @@ // or priority queue or anything: just use a simple vector. static std::vector addr2line_cache; -std::string +Source_location Dwarf_line_info::one_addr2line(Object* object, unsigned int shndx, off_t offset, size_t cache_size) @@ -854,7 +861,7 @@ } // Now that we have our object, figure out the answer - std::string retval = lineinfo->addr2line(shndx, offset); + Source_location retval = lineinfo->addr2line(shndx, offset); // Finally, if our cache has grown too big, delete old objects. We // assume the common (probably only) case is deleting only one object. Index: gold/dwarf_reader.h =================================================================== RCS file: /cvs/src/src/gold/dwarf_reader.h,v retrieving revision 1.19 diff -u -r1.19 dwarf_reader.h --- gold/dwarf_reader.h 20 Dec 2010 18:37:36 -0000 1.19 +++ gold/dwarf_reader.h 3 Feb 2011 06:15:20 -0000 @@ -54,6 +54,32 @@ { return this->offset < that.offset; } }; +// Stores a triple of directory, file, and line number and can format +// these to a string. +struct Source_location +{ + const std::string* dirname; + const std::string* filename; + int line_num; + + Source_location() + : dirname(NULL), filename(NULL), line_num(0) + {} + + Source_location(const std::string* dirname, + const std::string* filename, + int line_num) + : dirname(dirname), filename(filename), line_num(line_num) + {} + + bool + empty() const + { return this->filename == NULL; } + + std::string + str() const; +}; + // This class is used to read the line information from the debugging // section of an object file. @@ -71,7 +97,7 @@ // file and line-number, as a string: "file:lineno". If unable // to do the mapping, returns the empty string. You must call // read_line_mappings() before calling this function. - std::string + Source_location addr2line(unsigned int shndx, off_t offset) { return do_addr2line(shndx, offset); } @@ -81,7 +107,7 @@ // chance this routine won't have to re-create a Dwarf_line_info // object for its addr2line computation; such creations are slow. // NOTE: Not thread-safe, so only call from one thread at a time. - static std::string + static Source_location one_addr2line(Object* object, unsigned int shndx, off_t offset, size_t cache_size); @@ -91,7 +117,7 @@ clear_addr2line_cache(); private: - virtual std::string + virtual Source_location do_addr2line(unsigned int shndx, off_t offset) = 0; }; @@ -105,7 +131,7 @@ Sized_dwarf_line_info(Object* object, unsigned int read_shndx = -1U); private: - std::string + virtual Source_location do_addr2line(unsigned int shndx, off_t offset); // Start processing line info, and populates the offset_map_. @@ -191,8 +217,10 @@ // 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). + // This never changes after construction. std::vector > directories_; // The first part is an index into directories_, the second the filename. + // This never changes after construction. std::vector > > files_; // An index into the current directories_ and files_ vectors. Index: gold/object.cc =================================================================== RCS file: /cvs/src/src/gold/object.cc,v retrieving revision 1.134 diff -u -r1.134 object.cc --- gold/object.cc 14 Dec 2010 19:03:30 -0000 1.134 +++ gold/object.cc 3 Feb 2011 06:15:20 -0000 @@ -2582,7 +2582,7 @@ Sized_dwarf_line_info line_info(this->object); // This will be "" if we failed to parse the debug info for any reason. - file_and_lineno = line_info.addr2line(this->data_shndx, offset); + file_and_lineno = line_info.addr2line(this->data_shndx, offset).str(); std::string ret(this->object->name()); ret += ':'; Index: gold/symtab.cc =================================================================== RCS file: /cvs/src/src/gold/symtab.cc,v retrieving revision 1.146 diff -u -r1.146 symtab.cc --- gold/symtab.cc 24 Jan 2011 21:48:40 -0000 1.146 +++ gold/symtab.cc 3 Feb 2011 06:15:20 -0000 @@ -3012,11 +3012,12 @@ // We check for ODR violations by looking for symbols with the same // name for which the debugging information reports that they were // defined in different source locations. When comparing the source -// location, we consider instances with the same base filename and -// line number to be the same. This is because different object -// files/shared libraries can include the same header file using -// different paths, and we don't want to report an ODR violation in -// that case. +// location, we consider instances with the same base filename to be +// the same. This is because different object files/shared libraries +// can include the same header file using different paths, and +// different optimization settings can make the line number appear to +// be a couple lines off, and we don't want to report an ODR violation +// in those cases. // This struct is used to compare line information, as returned by // Dwarf_line_info::one_addr2line. It implements a < comparison @@ -3025,15 +3026,11 @@ struct Odr_violation_compare { bool - operator()(const std::string& s1, const std::string& s2) const + operator()(const Source_location& s1, const Source_location& s2) const { - std::string::size_type pos1 = s1.rfind('/'); - std::string::size_type pos2 = s2.rfind('/'); - if (pos1 == std::string::npos - || pos2 == std::string::npos) - return s1 < s2; - return s1.compare(pos1, std::string::npos, - s2, pos2, std::string::npos) < 0; + if (s1.filename == NULL || s2.filename == NULL) + return s1.filename == NULL && s2.filename != NULL; + return *s1.filename < *s2.filename; } }; @@ -3053,7 +3050,7 @@ // that location in. We use a sorted map so the location order // is deterministic, but we only store an arbitrary object file // to avoid copying lots of names. - std::map line_nums; + std::map line_nums; for (Unordered_set::const_iterator locs = it->second.begin(); @@ -3069,7 +3066,7 @@ // currently thread-safe. Task_lock_obj tl(task, locs->object); // 16 is the size of the object-cache that one_addr2line should use. - std::string lineno = Dwarf_line_info::one_addr2line( + Source_location lineno = Dwarf_line_info::one_addr2line( locs->object, locs->shndx, locs->offset, 16); if (!lineno.empty()) { @@ -3084,12 +3081,12 @@ gold_warning(_("while linking %s: symbol '%s' defined in multiple " "places (possible ODR violation):"), output_file_name, demangle(symbol_name).c_str()); - for (std::map::const_iterator it2 = + for (std::map::const_iterator it2 = line_nums.begin(); it2 != line_nums.end(); ++it2) fprintf(stderr, _(" %s from %s\n"), - it2->first.c_str(), it2->second.c_str()); + it2->first.str().c_str(), it2->second.c_str()); } } // We only call one_addr2line() in this function, so we can clear its cache.