180814287SRaphael Isemann //===-- CompileUnitIndex.cpp ----------------------------------------------===// 2307f5ae8SZachary Turner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6307f5ae8SZachary Turner // 7307f5ae8SZachary Turner //===----------------------------------------------------------------------===// 8307f5ae8SZachary Turner 9307f5ae8SZachary Turner #include "CompileUnitIndex.h" 10307f5ae8SZachary Turner 11307f5ae8SZachary Turner #include "PdbIndex.h" 12307f5ae8SZachary Turner #include "PdbUtil.h" 13307f5ae8SZachary Turner 14307f5ae8SZachary Turner #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" 15307f5ae8SZachary Turner #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" 16307f5ae8SZachary Turner #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" 17307f5ae8SZachary Turner #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 18307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" 19307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/DbiStream.h" 20307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/InfoStream.h" 21307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" 22307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h" 23307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/TpiStream.h" 24307f5ae8SZachary Turner #include "llvm/Support/Path.h" 25307f5ae8SZachary Turner 26307f5ae8SZachary Turner #include "lldb/Utility/LLDBAssert.h" 27307f5ae8SZachary Turner 28307f5ae8SZachary Turner using namespace lldb; 29307f5ae8SZachary Turner using namespace lldb_private; 30307f5ae8SZachary Turner using namespace lldb_private::npdb; 31307f5ae8SZachary Turner using namespace llvm::codeview; 32307f5ae8SZachary Turner using namespace llvm::pdb; 33307f5ae8SZachary Turner 34307f5ae8SZachary Turner static bool IsMainFile(llvm::StringRef main, llvm::StringRef other) { 35307f5ae8SZachary Turner if (main == other) 36307f5ae8SZachary Turner return true; 37307f5ae8SZachary Turner 38307f5ae8SZachary Turner // If the files refer to the local file system, we can just ask the file 39307f5ae8SZachary Turner // system if they're equivalent. But if the source isn't present on disk 40307f5ae8SZachary Turner // then we still want to try. 41307f5ae8SZachary Turner if (llvm::sys::fs::equivalent(main, other)) 42307f5ae8SZachary Turner return true; 43307f5ae8SZachary Turner 44307f5ae8SZachary Turner llvm::SmallString<64> normalized(other); 45307f5ae8SZachary Turner llvm::sys::path::native(normalized); 46e50f9c41SMartin Storsjö return main.equals_insensitive(normalized); 47307f5ae8SZachary Turner } 48307f5ae8SZachary Turner 49307f5ae8SZachary Turner static void ParseCompile3(const CVSymbol &sym, CompilandIndexItem &cci) { 50307f5ae8SZachary Turner cci.m_compile_opts.emplace(); 51307f5ae8SZachary Turner llvm::cantFail( 52307f5ae8SZachary Turner SymbolDeserializer::deserializeAs<Compile3Sym>(sym, *cci.m_compile_opts)); 53307f5ae8SZachary Turner } 54307f5ae8SZachary Turner 55307f5ae8SZachary Turner static void ParseObjname(const CVSymbol &sym, CompilandIndexItem &cci) { 56307f5ae8SZachary Turner cci.m_obj_name.emplace(); 57307f5ae8SZachary Turner llvm::cantFail( 58307f5ae8SZachary Turner SymbolDeserializer::deserializeAs<ObjNameSym>(sym, *cci.m_obj_name)); 59307f5ae8SZachary Turner } 60307f5ae8SZachary Turner 61307f5ae8SZachary Turner static void ParseBuildInfo(PdbIndex &index, const CVSymbol &sym, 62307f5ae8SZachary Turner CompilandIndexItem &cci) { 63307f5ae8SZachary Turner BuildInfoSym bis(SymbolRecordKind::BuildInfoSym); 64307f5ae8SZachary Turner llvm::cantFail(SymbolDeserializer::deserializeAs<BuildInfoSym>(sym, bis)); 65307f5ae8SZachary Turner 66307f5ae8SZachary Turner // S_BUILDINFO just points to an LF_BUILDINFO in the IPI stream. Let's do 67307f5ae8SZachary Turner // a little extra work to pull out the LF_BUILDINFO. 68307f5ae8SZachary Turner LazyRandomTypeCollection &types = index.ipi().typeCollection(); 69307f5ae8SZachary Turner llvm::Optional<CVType> cvt = types.tryGetType(bis.BuildId); 70307f5ae8SZachary Turner 71307f5ae8SZachary Turner if (!cvt || cvt->kind() != LF_BUILDINFO) 72307f5ae8SZachary Turner return; 73307f5ae8SZachary Turner 74307f5ae8SZachary Turner BuildInfoRecord bir; 75307f5ae8SZachary Turner llvm::cantFail(TypeDeserializer::deserializeAs<BuildInfoRecord>(*cvt, bir)); 76307f5ae8SZachary Turner cci.m_build_info.assign(bir.ArgIndices.begin(), bir.ArgIndices.end()); 77307f5ae8SZachary Turner } 78307f5ae8SZachary Turner 79307f5ae8SZachary Turner static void ParseExtendedInfo(PdbIndex &index, CompilandIndexItem &item) { 80307f5ae8SZachary Turner const CVSymbolArray &syms = item.m_debug_stream.getSymbolArray(); 81307f5ae8SZachary Turner 82307f5ae8SZachary Turner // This is a private function, it shouldn't be called if the information 83307f5ae8SZachary Turner // has already been parsed. 84307f5ae8SZachary Turner lldbassert(!item.m_obj_name); 85307f5ae8SZachary Turner lldbassert(!item.m_compile_opts); 86307f5ae8SZachary Turner lldbassert(item.m_build_info.empty()); 87307f5ae8SZachary Turner 88307f5ae8SZachary Turner // We're looking for 3 things. S_COMPILE3, S_OBJNAME, and S_BUILDINFO. 89307f5ae8SZachary Turner int found = 0; 90307f5ae8SZachary Turner for (const CVSymbol &sym : syms) { 91307f5ae8SZachary Turner switch (sym.kind()) { 92307f5ae8SZachary Turner case S_COMPILE3: 93307f5ae8SZachary Turner ParseCompile3(sym, item); 94307f5ae8SZachary Turner break; 95307f5ae8SZachary Turner case S_OBJNAME: 96307f5ae8SZachary Turner ParseObjname(sym, item); 97307f5ae8SZachary Turner break; 98307f5ae8SZachary Turner case S_BUILDINFO: 99307f5ae8SZachary Turner ParseBuildInfo(index, sym, item); 100307f5ae8SZachary Turner break; 101307f5ae8SZachary Turner default: 102307f5ae8SZachary Turner continue; 103307f5ae8SZachary Turner } 104307f5ae8SZachary Turner if (++found >= 3) 105307f5ae8SZachary Turner break; 106307f5ae8SZachary Turner } 107307f5ae8SZachary Turner } 108307f5ae8SZachary Turner 109*f00cd23cSZequan Wu static void ParseInlineeLineTableForCompileUnit(CompilandIndexItem &item) { 110*f00cd23cSZequan Wu for (const auto &ss : item.m_debug_stream.getSubsectionsArray()) { 111*f00cd23cSZequan Wu if (ss.kind() != DebugSubsectionKind::InlineeLines) 112*f00cd23cSZequan Wu continue; 113*f00cd23cSZequan Wu 114*f00cd23cSZequan Wu DebugInlineeLinesSubsectionRef inlinee_lines; 115*f00cd23cSZequan Wu llvm::BinaryStreamReader reader(ss.getRecordData()); 116*f00cd23cSZequan Wu if (llvm::Error error = inlinee_lines.initialize(reader)) { 117*f00cd23cSZequan Wu consumeError(std::move(error)); 118*f00cd23cSZequan Wu continue; 119*f00cd23cSZequan Wu } 120*f00cd23cSZequan Wu 121*f00cd23cSZequan Wu for (const InlineeSourceLine &Line : inlinee_lines) { 122*f00cd23cSZequan Wu item.m_inline_map[Line.Header->Inlinee] = Line; 123*f00cd23cSZequan Wu } 124*f00cd23cSZequan Wu } 125*f00cd23cSZequan Wu } 126*f00cd23cSZequan Wu 127307f5ae8SZachary Turner CompilandIndexItem::CompilandIndexItem( 1286284aee9SZachary Turner PdbCompilandId id, llvm::pdb::ModuleDebugStreamRef debug_stream, 129307f5ae8SZachary Turner llvm::pdb::DbiModuleDescriptor descriptor) 1306284aee9SZachary Turner : m_id(id), m_debug_stream(std::move(debug_stream)), 131307f5ae8SZachary Turner m_module_descriptor(std::move(descriptor)) {} 132307f5ae8SZachary Turner 133307f5ae8SZachary Turner CompilandIndexItem &CompileUnitIndex::GetOrCreateCompiland(uint16_t modi) { 1346284aee9SZachary Turner auto result = m_comp_units.try_emplace(modi, nullptr); 135307f5ae8SZachary Turner if (!result.second) 136307f5ae8SZachary Turner return *result.first->second; 137307f5ae8SZachary Turner 138307f5ae8SZachary Turner // Find the module list and load its debug information stream and cache it 139307f5ae8SZachary Turner // since we need to use it for almost all interesting operations. 140307f5ae8SZachary Turner const DbiModuleList &modules = m_index.dbi().modules(); 141307f5ae8SZachary Turner llvm::pdb::DbiModuleDescriptor descriptor = modules.getModuleDescriptor(modi); 142307f5ae8SZachary Turner uint16_t stream = descriptor.getModuleStreamIndex(); 143307f5ae8SZachary Turner std::unique_ptr<llvm::msf::MappedBlockStream> stream_data = 144307f5ae8SZachary Turner m_index.pdb().createIndexedStream(stream); 145a31347f1SZachary Turner 146307f5ae8SZachary Turner 147307f5ae8SZachary Turner std::unique_ptr<CompilandIndexItem>& cci = result.first->second; 148307f5ae8SZachary Turner 149a31347f1SZachary Turner if (!stream_data) { 150a31347f1SZachary Turner llvm::pdb::ModuleDebugStreamRef debug_stream(descriptor, nullptr); 151a8f3ae7cSJonas Devlieghere cci = std::make_unique<CompilandIndexItem>(PdbCompilandId{ modi }, debug_stream, std::move(descriptor)); 152a31347f1SZachary Turner return *cci; 153a31347f1SZachary Turner } 154a31347f1SZachary Turner 155a31347f1SZachary Turner llvm::pdb::ModuleDebugStreamRef debug_stream(descriptor, 156a31347f1SZachary Turner std::move(stream_data)); 157a31347f1SZachary Turner 158a31347f1SZachary Turner cantFail(debug_stream.reload()); 159a31347f1SZachary Turner 160a8f3ae7cSJonas Devlieghere cci = std::make_unique<CompilandIndexItem>( 1616284aee9SZachary Turner PdbCompilandId{modi}, std::move(debug_stream), std::move(descriptor)); 162307f5ae8SZachary Turner ParseExtendedInfo(m_index, *cci); 163*f00cd23cSZequan Wu ParseInlineeLineTableForCompileUnit(*cci); 164307f5ae8SZachary Turner 165307f5ae8SZachary Turner cci->m_strings.initialize(debug_stream.getSubsectionsArray()); 166307f5ae8SZachary Turner PDBStringTable &strings = cantFail(m_index.pdb().getStringTable()); 167307f5ae8SZachary Turner cci->m_strings.setStrings(strings.getStringTable()); 168307f5ae8SZachary Turner 169307f5ae8SZachary Turner // We want the main source file to always comes first. Note that we can't 170307f5ae8SZachary Turner // just push_back the main file onto the front because `GetMainSourceFile` 171307f5ae8SZachary Turner // computes it in such a way that it doesn't own the resulting memory. So we 172307f5ae8SZachary Turner // have to iterate the module file list comparing each one to the main file 173307f5ae8SZachary Turner // name until we find it, and we can cache that one since the memory is backed 174307f5ae8SZachary Turner // by a contiguous chunk inside the mapped PDB. 175307f5ae8SZachary Turner llvm::SmallString<64> main_file = GetMainSourceFile(*cci); 176adcd0268SBenjamin Kramer std::string s = std::string(main_file.str()); 177307f5ae8SZachary Turner llvm::sys::path::native(main_file); 178307f5ae8SZachary Turner 179307f5ae8SZachary Turner uint32_t file_count = modules.getSourceFileCount(modi); 180307f5ae8SZachary Turner cci->m_file_list.reserve(file_count); 181307f5ae8SZachary Turner bool found_main_file = false; 182307f5ae8SZachary Turner for (llvm::StringRef file : modules.source_files(modi)) { 183307f5ae8SZachary Turner if (!found_main_file && IsMainFile(main_file, file)) { 184307f5ae8SZachary Turner cci->m_file_list.insert(cci->m_file_list.begin(), file); 185307f5ae8SZachary Turner found_main_file = true; 186307f5ae8SZachary Turner continue; 187307f5ae8SZachary Turner } 188307f5ae8SZachary Turner cci->m_file_list.push_back(file); 189307f5ae8SZachary Turner } 190307f5ae8SZachary Turner 191307f5ae8SZachary Turner return *cci; 192307f5ae8SZachary Turner } 193307f5ae8SZachary Turner 194307f5ae8SZachary Turner const CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) const { 1956284aee9SZachary Turner auto iter = m_comp_units.find(modi); 196307f5ae8SZachary Turner if (iter == m_comp_units.end()) 197307f5ae8SZachary Turner return nullptr; 198307f5ae8SZachary Turner return iter->second.get(); 199307f5ae8SZachary Turner } 200307f5ae8SZachary Turner 201307f5ae8SZachary Turner CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) { 2026284aee9SZachary Turner auto iter = m_comp_units.find(modi); 203307f5ae8SZachary Turner if (iter == m_comp_units.end()) 204307f5ae8SZachary Turner return nullptr; 205307f5ae8SZachary Turner return iter->second.get(); 206307f5ae8SZachary Turner } 207307f5ae8SZachary Turner 208307f5ae8SZachary Turner llvm::SmallString<64> 209307f5ae8SZachary Turner CompileUnitIndex::GetMainSourceFile(const CompilandIndexItem &item) const { 210307f5ae8SZachary Turner // LF_BUILDINFO contains a list of arg indices which point to LF_STRING_ID 211307f5ae8SZachary Turner // records in the IPI stream. The order of the arg indices is as follows: 212307f5ae8SZachary Turner // [0] - working directory where compiler was invoked. 213307f5ae8SZachary Turner // [1] - absolute path to compiler binary 214307f5ae8SZachary Turner // [2] - source file name 215307f5ae8SZachary Turner // [3] - path to compiler generated PDB (the /Zi PDB, although this entry gets 216307f5ae8SZachary Turner // added even when using /Z7) 217307f5ae8SZachary Turner // [4] - full command line invocation. 218307f5ae8SZachary Turner // 219307f5ae8SZachary Turner // We need to form the path [0]\[2] to generate the full path to the main 220307f5ae8SZachary Turner // file.source 221307f5ae8SZachary Turner if (item.m_build_info.size() < 3) 222307f5ae8SZachary Turner return {""}; 223307f5ae8SZachary Turner 224307f5ae8SZachary Turner LazyRandomTypeCollection &types = m_index.ipi().typeCollection(); 225307f5ae8SZachary Turner 226307f5ae8SZachary Turner StringIdRecord working_dir; 227307f5ae8SZachary Turner StringIdRecord file_name; 228307f5ae8SZachary Turner CVType dir_cvt = types.getType(item.m_build_info[0]); 229307f5ae8SZachary Turner CVType file_cvt = types.getType(item.m_build_info[2]); 230307f5ae8SZachary Turner llvm::cantFail( 231307f5ae8SZachary Turner TypeDeserializer::deserializeAs<StringIdRecord>(dir_cvt, working_dir)); 232307f5ae8SZachary Turner llvm::cantFail( 233307f5ae8SZachary Turner TypeDeserializer::deserializeAs<StringIdRecord>(file_cvt, file_name)); 234307f5ae8SZachary Turner 235b3130b4fSZachary Turner llvm::sys::path::Style style = working_dir.String.startswith("/") 236b3130b4fSZachary Turner ? llvm::sys::path::Style::posix 237b3130b4fSZachary Turner : llvm::sys::path::Style::windows; 238b3130b4fSZachary Turner if (llvm::sys::path::is_absolute(file_name.String, style)) 239b3130b4fSZachary Turner return file_name.String; 240b3130b4fSZachary Turner 241307f5ae8SZachary Turner llvm::SmallString<64> absolute_path = working_dir.String; 242307f5ae8SZachary Turner llvm::sys::path::append(absolute_path, file_name.String); 243307f5ae8SZachary Turner return absolute_path; 244307f5ae8SZachary Turner } 245