1 //===-- CompileUnitIndex.cpp ------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "CompileUnitIndex.h" 11 12 #include "PdbIndex.h" 13 #include "PdbUtil.h" 14 15 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" 16 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" 17 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" 18 #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 19 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" 20 #include "llvm/DebugInfo/PDB/Native/DbiStream.h" 21 #include "llvm/DebugInfo/PDB/Native/InfoStream.h" 22 #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" 23 #include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h" 24 #include "llvm/DebugInfo/PDB/Native/TpiStream.h" 25 #include "llvm/Support/Path.h" 26 27 #include "lldb/Utility/LLDBAssert.h" 28 29 using namespace lldb; 30 using namespace lldb_private; 31 using namespace lldb_private::npdb; 32 using namespace llvm::codeview; 33 using namespace llvm::pdb; 34 35 static bool IsMainFile(llvm::StringRef main, llvm::StringRef other) { 36 if (main == other) 37 return true; 38 39 // If the files refer to the local file system, we can just ask the file 40 // system if they're equivalent. But if the source isn't present on disk 41 // then we still want to try. 42 if (llvm::sys::fs::equivalent(main, other)) 43 return true; 44 45 llvm::SmallString<64> normalized(other); 46 llvm::sys::path::native(normalized); 47 return main.equals_lower(normalized); 48 } 49 50 static void ParseCompile3(const CVSymbol &sym, CompilandIndexItem &cci) { 51 cci.m_compile_opts.emplace(); 52 llvm::cantFail( 53 SymbolDeserializer::deserializeAs<Compile3Sym>(sym, *cci.m_compile_opts)); 54 } 55 56 static void ParseObjname(const CVSymbol &sym, CompilandIndexItem &cci) { 57 cci.m_obj_name.emplace(); 58 llvm::cantFail( 59 SymbolDeserializer::deserializeAs<ObjNameSym>(sym, *cci.m_obj_name)); 60 } 61 62 static void ParseBuildInfo(PdbIndex &index, const CVSymbol &sym, 63 CompilandIndexItem &cci) { 64 BuildInfoSym bis(SymbolRecordKind::BuildInfoSym); 65 llvm::cantFail(SymbolDeserializer::deserializeAs<BuildInfoSym>(sym, bis)); 66 67 // S_BUILDINFO just points to an LF_BUILDINFO in the IPI stream. Let's do 68 // a little extra work to pull out the LF_BUILDINFO. 69 LazyRandomTypeCollection &types = index.ipi().typeCollection(); 70 llvm::Optional<CVType> cvt = types.tryGetType(bis.BuildId); 71 72 if (!cvt || cvt->kind() != LF_BUILDINFO) 73 return; 74 75 BuildInfoRecord bir; 76 llvm::cantFail(TypeDeserializer::deserializeAs<BuildInfoRecord>(*cvt, bir)); 77 cci.m_build_info.assign(bir.ArgIndices.begin(), bir.ArgIndices.end()); 78 } 79 80 static void ParseExtendedInfo(PdbIndex &index, CompilandIndexItem &item) { 81 const CVSymbolArray &syms = item.m_debug_stream.getSymbolArray(); 82 83 // This is a private function, it shouldn't be called if the information 84 // has already been parsed. 85 lldbassert(!item.m_obj_name); 86 lldbassert(!item.m_compile_opts); 87 lldbassert(item.m_build_info.empty()); 88 89 // We're looking for 3 things. S_COMPILE3, S_OBJNAME, and S_BUILDINFO. 90 int found = 0; 91 for (const CVSymbol &sym : syms) { 92 switch (sym.kind()) { 93 case S_COMPILE3: 94 ParseCompile3(sym, item); 95 break; 96 case S_OBJNAME: 97 ParseObjname(sym, item); 98 break; 99 case S_BUILDINFO: 100 ParseBuildInfo(index, sym, item); 101 break; 102 default: 103 continue; 104 } 105 if (++found >= 3) 106 break; 107 } 108 } 109 110 CompilandIndexItem::CompilandIndexItem( 111 PdbCompilandId id, llvm::pdb::ModuleDebugStreamRef debug_stream, 112 llvm::pdb::DbiModuleDescriptor descriptor) 113 : m_id(id), m_debug_stream(std::move(debug_stream)), 114 m_module_descriptor(std::move(descriptor)) {} 115 116 CompilandIndexItem &CompileUnitIndex::GetOrCreateCompiland(uint16_t modi) { 117 auto result = m_comp_units.try_emplace(modi, nullptr); 118 if (!result.second) 119 return *result.first->second; 120 121 // Find the module list and load its debug information stream and cache it 122 // since we need to use it for almost all interesting operations. 123 const DbiModuleList &modules = m_index.dbi().modules(); 124 llvm::pdb::DbiModuleDescriptor descriptor = modules.getModuleDescriptor(modi); 125 uint16_t stream = descriptor.getModuleStreamIndex(); 126 std::unique_ptr<llvm::msf::MappedBlockStream> stream_data = 127 m_index.pdb().createIndexedStream(stream); 128 llvm::pdb::ModuleDebugStreamRef debug_stream(descriptor, 129 std::move(stream_data)); 130 cantFail(debug_stream.reload()); 131 132 std::unique_ptr<CompilandIndexItem> &cci = result.first->second; 133 134 cci = llvm::make_unique<CompilandIndexItem>( 135 PdbCompilandId{modi}, std::move(debug_stream), std::move(descriptor)); 136 ParseExtendedInfo(m_index, *cci); 137 138 cci->m_strings.initialize(debug_stream.getSubsectionsArray()); 139 PDBStringTable &strings = cantFail(m_index.pdb().getStringTable()); 140 cci->m_strings.setStrings(strings.getStringTable()); 141 142 // We want the main source file to always comes first. Note that we can't 143 // just push_back the main file onto the front because `GetMainSourceFile` 144 // computes it in such a way that it doesn't own the resulting memory. So we 145 // have to iterate the module file list comparing each one to the main file 146 // name until we find it, and we can cache that one since the memory is backed 147 // by a contiguous chunk inside the mapped PDB. 148 llvm::SmallString<64> main_file = GetMainSourceFile(*cci); 149 std::string s = main_file.str(); 150 llvm::sys::path::native(main_file); 151 152 uint32_t file_count = modules.getSourceFileCount(modi); 153 cci->m_file_list.reserve(file_count); 154 bool found_main_file = false; 155 for (llvm::StringRef file : modules.source_files(modi)) { 156 if (!found_main_file && IsMainFile(main_file, file)) { 157 cci->m_file_list.insert(cci->m_file_list.begin(), file); 158 found_main_file = true; 159 continue; 160 } 161 cci->m_file_list.push_back(file); 162 } 163 164 return *cci; 165 } 166 167 const CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) const { 168 auto iter = m_comp_units.find(modi); 169 if (iter == m_comp_units.end()) 170 return nullptr; 171 return iter->second.get(); 172 } 173 174 CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) { 175 auto iter = m_comp_units.find(modi); 176 if (iter == m_comp_units.end()) 177 return nullptr; 178 return iter->second.get(); 179 } 180 181 llvm::SmallString<64> 182 CompileUnitIndex::GetMainSourceFile(const CompilandIndexItem &item) const { 183 // LF_BUILDINFO contains a list of arg indices which point to LF_STRING_ID 184 // records in the IPI stream. The order of the arg indices is as follows: 185 // [0] - working directory where compiler was invoked. 186 // [1] - absolute path to compiler binary 187 // [2] - source file name 188 // [3] - path to compiler generated PDB (the /Zi PDB, although this entry gets 189 // added even when using /Z7) 190 // [4] - full command line invocation. 191 // 192 // We need to form the path [0]\[2] to generate the full path to the main 193 // file.source 194 if (item.m_build_info.size() < 3) 195 return {""}; 196 197 LazyRandomTypeCollection &types = m_index.ipi().typeCollection(); 198 199 StringIdRecord working_dir; 200 StringIdRecord file_name; 201 CVType dir_cvt = types.getType(item.m_build_info[0]); 202 CVType file_cvt = types.getType(item.m_build_info[2]); 203 llvm::cantFail( 204 TypeDeserializer::deserializeAs<StringIdRecord>(dir_cvt, working_dir)); 205 llvm::cantFail( 206 TypeDeserializer::deserializeAs<StringIdRecord>(file_cvt, file_name)); 207 208 llvm::SmallString<64> absolute_path = working_dir.String; 209 llvm::sys::path::append(absolute_path, file_name.String); 210 return absolute_path; 211 } 212