diff --git a/src/common/windows/pdb_source_line_writer.cc b/src/common/windows/pdb_source_line_writer.cc index 9525efe2..9cd0d2e3 100644 --- a/src/common/windows/pdb_source_line_writer.cc +++ b/src/common/windows/pdb_source_line_writer.cc @@ -118,11 +118,13 @@ bool PDBSourceLineWriter::PrintLines(IDiaEnumLineNumbers *lines) { return false; } - DWORD source_id; - if (FAILED(line->get_sourceFileId(&source_id))) { + DWORD dia_source_id; + if (FAILED(line->get_sourceFileId(&dia_source_id))) { fprintf(stderr, "failed to get line source file id\n"); return false; } + // duplicate file names are coalesced to share one ID + DWORD source_id = GetRealFileID(dia_source_id); DWORD line_num; if (FAILED(line->get_lineNumber(&line_num))) { @@ -216,7 +218,16 @@ bool PDBSourceLineWriter::PrintSourceFiles() { return false; } - fwprintf(output_, L"FILE %d %s\n", file_id, file_name); + wstring file_name_string(file_name); + if (!FileIDIsCached(file_name_string)) { + // this is a new file name, cache it and output a FILE line. + CacheFileID(file_name_string, file_id); + fwprintf(output_, L"FILE %d %s\n", file_id, file_name); + } else { + // this file name has already been seen, just save this + // ID for later lookup. + StoreDuplicateFileID(file_name_string, file_id); + } file.Release(); } compiland.Release(); diff --git a/src/common/windows/pdb_source_line_writer.h b/src/common/windows/pdb_source_line_writer.h index 346d4549..8524d8b0 100644 --- a/src/common/windows/pdb_source_line_writer.h +++ b/src/common/windows/pdb_source_line_writer.h @@ -35,6 +35,7 @@ #include +#include #include struct IDiaEnumLineNumbers; @@ -44,6 +45,7 @@ struct IDiaSymbol; namespace google_breakpad { using std::wstring; +using stdext::hash_map; // A structure that carries information that identifies a pdb file. struct PDBModuleInfo { @@ -137,6 +139,37 @@ class PDBSourceLineWriter { // its uuid and age. bool PrintPDBInfo(); + // Returns true if this filename has already been seen, + // and an ID is stored for it, or false if it has not. + bool FileIDIsCached(const wstring &file) { + return unique_files_.find(file) != unique_files_.end(); + }; + + // Cache this filename and ID for later reuse. + void CacheFileID(const wstring &file, DWORD id) { + unique_files_[file] = id; + }; + + // Store this ID in the cache as a duplicate for this filename. + void StoreDuplicateFileID(const wstring &file, DWORD id) { + hash_map::iterator iter = unique_files_.find(file); + if (iter != unique_files_.end()) { + // map this id to the previously seen one + file_ids_[id] = iter->second; + } + }; + + // Given a file's unique ID, return the ID that should be used to + // reference it. There may be multiple files with identical filenames + // but different unique IDs. The cache attempts to coalesce these into + // one ID per unique filename. + DWORD GetRealFileID(DWORD id) { + hash_map::iterator iter = file_ids_.find(id); + if (iter == file_ids_.end()) + return id; + return iter->second; + }; + // Returns the function name for a symbol. If possible, the name is // undecorated. If the symbol's decorated form indicates the size of // parameters on the stack, this information is returned in stack_param_size. @@ -156,6 +189,13 @@ class PDBSourceLineWriter { // The current output file for this WriteMap invocation. FILE *output_; + // There may be many duplicate filenames with different IDs. + // This maps from the DIA "unique ID" to a single ID per unique + // filename. + hash_map file_ids_; + // This maps unique filenames to file IDs. + hash_map unique_files_; + // Disallow copy ctor and operator= PDBSourceLineWriter(const PDBSourceLineWriter&); void operator=(const PDBSourceLineWriter&);