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