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 PdbSymUid uid, llvm::pdb::ModuleDebugStreamRef debug_stream, 112 llvm::pdb::DbiModuleDescriptor descriptor) 113 : m_uid(uid), m_debug_stream(std::move(debug_stream)), 114 m_module_descriptor(std::move(descriptor)) {} 115 116 CompilandIndexItem &CompileUnitIndex::GetOrCreateCompiland(uint16_t modi) { 117 PdbSymUid uid = PdbSymUid::makeCompilandId(modi); 118 return GetOrCreateCompiland(uid); 119 } 120 121 CompilandIndexItem & 122 CompileUnitIndex::GetOrCreateCompiland(PdbSymUid compiland_uid) { 123 auto result = m_comp_units.try_emplace(compiland_uid.toOpaqueId(), nullptr); 124 if (!result.second) 125 return *result.first->second; 126 127 // Find the module list and load its debug information stream and cache it 128 // since we need to use it for almost all interesting operations. 129 const DbiModuleList &modules = m_index.dbi().modules(); 130 uint16_t modi = compiland_uid.asCompiland().modi; 131 llvm::pdb::DbiModuleDescriptor descriptor = modules.getModuleDescriptor(modi); 132 uint16_t stream = descriptor.getModuleStreamIndex(); 133 std::unique_ptr<llvm::msf::MappedBlockStream> stream_data = 134 m_index.pdb().createIndexedStream(stream); 135 llvm::pdb::ModuleDebugStreamRef debug_stream(descriptor, 136 std::move(stream_data)); 137 cantFail(debug_stream.reload()); 138 139 std::unique_ptr<CompilandIndexItem> &cci = result.first->second; 140 141 cci = llvm::make_unique<CompilandIndexItem>( 142 compiland_uid, std::move(debug_stream), std::move(descriptor)); 143 ParseExtendedInfo(m_index, *cci); 144 145 cci->m_strings.initialize(debug_stream.getSubsectionsArray()); 146 PDBStringTable &strings = cantFail(m_index.pdb().getStringTable()); 147 cci->m_strings.setStrings(strings.getStringTable()); 148 149 // We want the main source file to always comes first. Note that we can't 150 // just push_back the main file onto the front because `GetMainSourceFile` 151 // computes it in such a way that it doesn't own the resulting memory. So we 152 // have to iterate the module file list comparing each one to the main file 153 // name until we find it, and we can cache that one since the memory is backed 154 // by a contiguous chunk inside the mapped PDB. 155 llvm::SmallString<64> main_file = GetMainSourceFile(*cci); 156 std::string s = main_file.str(); 157 llvm::sys::path::native(main_file); 158 159 uint32_t file_count = modules.getSourceFileCount(modi); 160 cci->m_file_list.reserve(file_count); 161 bool found_main_file = false; 162 for (llvm::StringRef file : modules.source_files(modi)) { 163 if (!found_main_file && IsMainFile(main_file, file)) { 164 cci->m_file_list.insert(cci->m_file_list.begin(), file); 165 found_main_file = true; 166 continue; 167 } 168 cci->m_file_list.push_back(file); 169 } 170 171 return *cci; 172 } 173 174 const CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) const { 175 return GetCompiland(PdbSymUid::makeCompilandId(modi)); 176 } 177 178 const CompilandIndexItem * 179 CompileUnitIndex::GetCompiland(PdbSymUid compiland_uid) const { 180 auto iter = m_comp_units.find(compiland_uid.toOpaqueId()); 181 if (iter == m_comp_units.end()) 182 return nullptr; 183 return iter->second.get(); 184 } 185 186 CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) { 187 return GetCompiland(PdbSymUid::makeCompilandId(modi)); 188 } 189 190 CompilandIndexItem *CompileUnitIndex::GetCompiland(PdbSymUid compiland_uid) { 191 auto iter = m_comp_units.find(compiland_uid.toOpaqueId()); 192 if (iter == m_comp_units.end()) 193 return nullptr; 194 return iter->second.get(); 195 } 196 197 llvm::SmallString<64> 198 CompileUnitIndex::GetMainSourceFile(const CompilandIndexItem &item) const { 199 // LF_BUILDINFO contains a list of arg indices which point to LF_STRING_ID 200 // records in the IPI stream. The order of the arg indices is as follows: 201 // [0] - working directory where compiler was invoked. 202 // [1] - absolute path to compiler binary 203 // [2] - source file name 204 // [3] - path to compiler generated PDB (the /Zi PDB, although this entry gets 205 // added even when using /Z7) 206 // [4] - full command line invocation. 207 // 208 // We need to form the path [0]\[2] to generate the full path to the main 209 // file.source 210 if (item.m_build_info.size() < 3) 211 return {""}; 212 213 LazyRandomTypeCollection &types = m_index.ipi().typeCollection(); 214 215 StringIdRecord working_dir; 216 StringIdRecord file_name; 217 CVType dir_cvt = types.getType(item.m_build_info[0]); 218 CVType file_cvt = types.getType(item.m_build_info[2]); 219 llvm::cantFail( 220 TypeDeserializer::deserializeAs<StringIdRecord>(dir_cvt, working_dir)); 221 llvm::cantFail( 222 TypeDeserializer::deserializeAs<StringIdRecord>(file_cvt, file_name)); 223 224 llvm::SmallString<64> absolute_path = working_dir.String; 225 llvm::sys::path::append(absolute_path, file_name.String); 226 return absolute_path; 227 } 228