Zachary Turner | 307f5ae | 2018-10-12 19:47:13 +0000 | [diff] [blame] | 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( |
Zachary Turner | 6284aee | 2018-11-16 02:42:32 +0000 | [diff] [blame] | 111 | PdbCompilandId id, llvm::pdb::ModuleDebugStreamRef debug_stream, |
Zachary Turner | 307f5ae | 2018-10-12 19:47:13 +0000 | [diff] [blame] | 112 | llvm::pdb::DbiModuleDescriptor descriptor) |
Zachary Turner | 6284aee | 2018-11-16 02:42:32 +0000 | [diff] [blame] | 113 | : m_id(id), m_debug_stream(std::move(debug_stream)), |
Zachary Turner | 307f5ae | 2018-10-12 19:47:13 +0000 | [diff] [blame] | 114 | m_module_descriptor(std::move(descriptor)) {} |
| 115 | |
| 116 | CompilandIndexItem &CompileUnitIndex::GetOrCreateCompiland(uint16_t modi) { |
Zachary Turner | 6284aee | 2018-11-16 02:42:32 +0000 | [diff] [blame] | 117 | auto result = m_comp_units.try_emplace(modi, nullptr); |
Zachary Turner | 307f5ae | 2018-10-12 19:47:13 +0000 | [diff] [blame] | 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(); |
Zachary Turner | 307f5ae | 2018-10-12 19:47:13 +0000 | [diff] [blame] | 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>( |
Zachary Turner | 6284aee | 2018-11-16 02:42:32 +0000 | [diff] [blame] | 135 | PdbCompilandId{modi}, std::move(debug_stream), std::move(descriptor)); |
Zachary Turner | 307f5ae | 2018-10-12 19:47:13 +0000 | [diff] [blame] | 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 { |
Zachary Turner | 6284aee | 2018-11-16 02:42:32 +0000 | [diff] [blame] | 168 | auto iter = m_comp_units.find(modi); |
Zachary Turner | 307f5ae | 2018-10-12 19:47:13 +0000 | [diff] [blame] | 169 | if (iter == m_comp_units.end()) |
| 170 | return nullptr; |
| 171 | return iter->second.get(); |
| 172 | } |
| 173 | |
| 174 | CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) { |
Zachary Turner | 6284aee | 2018-11-16 02:42:32 +0000 | [diff] [blame] | 175 | auto iter = m_comp_units.find(modi); |
Zachary Turner | 307f5ae | 2018-10-12 19:47:13 +0000 | [diff] [blame] | 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 | |
Zachary Turner | b3130b4 | 2019-01-02 18:32:50 +0000 | [diff] [blame] | 208 | llvm::sys::path::Style style = working_dir.String.startswith("/") |
| 209 | ? llvm::sys::path::Style::posix |
| 210 | : llvm::sys::path::Style::windows; |
| 211 | if (llvm::sys::path::is_absolute(file_name.String, style)) |
| 212 | return file_name.String; |
| 213 | |
Zachary Turner | 307f5ae | 2018-10-12 19:47:13 +0000 | [diff] [blame] | 214 | llvm::SmallString<64> absolute_path = working_dir.String; |
| 215 | llvm::sys::path::append(absolute_path, file_name.String); |
| 216 | return absolute_path; |
| 217 | } |