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