blob: 67ea05767fdeeb24a1a1fb7efd91ad3caa22fc2e [file] [log] [blame]
Zachary Turner307f5ae2018-10-12 19:47:13 +00001//===-- 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
29using namespace lldb;
30using namespace lldb_private;
31using namespace lldb_private::npdb;
32using namespace llvm::codeview;
33using namespace llvm::pdb;
34
35static 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
50static 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
56static 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
62static 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
80static 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
110CompilandIndexItem::CompilandIndexItem(
Zachary Turner6284aee2018-11-16 02:42:32 +0000111 PdbCompilandId id, llvm::pdb::ModuleDebugStreamRef debug_stream,
Zachary Turner307f5ae2018-10-12 19:47:13 +0000112 llvm::pdb::DbiModuleDescriptor descriptor)
Zachary Turner6284aee2018-11-16 02:42:32 +0000113 : m_id(id), m_debug_stream(std::move(debug_stream)),
Zachary Turner307f5ae2018-10-12 19:47:13 +0000114 m_module_descriptor(std::move(descriptor)) {}
115
116CompilandIndexItem &CompileUnitIndex::GetOrCreateCompiland(uint16_t modi) {
Zachary Turner6284aee2018-11-16 02:42:32 +0000117 auto result = m_comp_units.try_emplace(modi, nullptr);
Zachary Turner307f5ae2018-10-12 19:47:13 +0000118 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 Turner307f5ae2018-10-12 19:47:13 +0000124 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 Turner6284aee2018-11-16 02:42:32 +0000135 PdbCompilandId{modi}, std::move(debug_stream), std::move(descriptor));
Zachary Turner307f5ae2018-10-12 19:47:13 +0000136 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
167const CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) const {
Zachary Turner6284aee2018-11-16 02:42:32 +0000168 auto iter = m_comp_units.find(modi);
Zachary Turner307f5ae2018-10-12 19:47:13 +0000169 if (iter == m_comp_units.end())
170 return nullptr;
171 return iter->second.get();
172}
173
174CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) {
Zachary Turner6284aee2018-11-16 02:42:32 +0000175 auto iter = m_comp_units.find(modi);
Zachary Turner307f5ae2018-10-12 19:47:13 +0000176 if (iter == m_comp_units.end())
177 return nullptr;
178 return iter->second.get();
179}
180
181llvm::SmallString<64>
182CompileUnitIndex::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 Turnerb3130b42019-01-02 18:32:50 +0000208 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 Turner307f5ae2018-10-12 19:47:13 +0000214 llvm::SmallString<64> absolute_path = working_dir.String;
215 llvm::sys::path::append(absolute_path, file_name.String);
216 return absolute_path;
217}