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( |
| 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 | } |