LLDB  mainline
CompileUnitIndex.cpp
Go to the documentation of this file.
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 
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  llvm::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);
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 
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 
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);
164 
165  cci->m_strings.initialize(cci->m_debug_stream.getSubsectionsArray());
166  PDBStringTable &strings = cantFail(m_index.pdb().getStringTable());
167  cci->m_strings.setStrings(strings.getStringTable());
168 
169  // We want the main source file to always comes first. Note that we can't
170  // just push_back the main file onto the front because `GetMainSourceFile`
171  // computes it in such a way that it doesn't own the resulting memory. So we
172  // have to iterate the module file list comparing each one to the main file
173  // name until we find it, and we can cache that one since the memory is backed
174  // by a contiguous chunk inside the mapped PDB.
175  llvm::SmallString<64> main_file = GetMainSourceFile(*cci);
176  std::string s = std::string(main_file.str());
177  llvm::sys::path::native(main_file);
178 
179  uint32_t file_count = modules.getSourceFileCount(modi);
180  cci->m_file_list.reserve(file_count);
181  bool found_main_file = false;
182  for (llvm::StringRef file : modules.source_files(modi)) {
183  if (!found_main_file && IsMainFile(main_file, file)) {
184  cci->m_file_list.insert(cci->m_file_list.begin(), file);
185  found_main_file = true;
186  continue;
187  }
188  cci->m_file_list.push_back(file);
189  }
190 
191  return *cci;
192 }
193 
195  auto iter = m_comp_units.find(modi);
196  if (iter == m_comp_units.end())
197  return nullptr;
198  return iter->second.get();
199 }
200 
202  auto iter = m_comp_units.find(modi);
203  if (iter == m_comp_units.end())
204  return nullptr;
205  return iter->second.get();
206 }
207 
208 llvm::SmallString<64>
210  // LF_BUILDINFO contains a list of arg indices which point to LF_STRING_ID
211  // records in the IPI stream. The order of the arg indices is as follows:
212  // [0] - working directory where compiler was invoked.
213  // [1] - absolute path to compiler binary
214  // [2] - source file name
215  // [3] - path to compiler generated PDB (the /Zi PDB, although this entry gets
216  // added even when using /Z7)
217  // [4] - full command line invocation.
218  //
219  // We need to form the path [0]\[2] to generate the full path to the main
220  // file.source
221  if (item.m_build_info.size() < 3)
222  return {""};
223 
224  LazyRandomTypeCollection &types = m_index.ipi().typeCollection();
225 
226  StringIdRecord working_dir;
227  StringIdRecord file_name;
228  CVType dir_cvt = types.getType(item.m_build_info[0]);
229  CVType file_cvt = types.getType(item.m_build_info[2]);
230  llvm::cantFail(
231  TypeDeserializer::deserializeAs<StringIdRecord>(dir_cvt, working_dir));
232  llvm::cantFail(
233  TypeDeserializer::deserializeAs<StringIdRecord>(file_cvt, file_name));
234 
235  llvm::sys::path::Style style = working_dir.String.startswith("/")
236  ? llvm::sys::path::Style::posix
237  : llvm::sys::path::Style::windows;
238  if (llvm::sys::path::is_absolute(file_name.String, style))
239  return file_name.String;
240 
241  llvm::SmallString<64> absolute_path = working_dir.String;
242  llvm::sys::path::append(absolute_path, file_name.String);
243  return absolute_path;
244 }
lldb_private::npdb::CompilandIndexItem::m_debug_stream
llvm::pdb::ModuleDebugStreamRef m_debug_stream
Definition: CompileUnitIndex.h:48
ParseBuildInfo
static void ParseBuildInfo(PdbIndex &index, const CVSymbol &sym, CompilandIndexItem &cci)
Definition: CompileUnitIndex.cpp:61
lldb_private::npdb::CompileUnitIndex::GetCompiland
const CompilandIndexItem * GetCompiland(uint16_t modi) const
Definition: CompileUnitIndex.cpp:194
lldb_private::npdb::CompilandIndexItem::m_obj_name
llvm::Optional< llvm::codeview::ObjNameSym > m_obj_name
Definition: CompileUnitIndex.h:68
lldb_private::npdb::PdbIndex
PdbIndex - Lazy access to the important parts of a PDB file.
Definition: PdbIndex.h:47
lldb_private::npdb
Definition: CodeViewRegisterMapping.h:16
CompileUnitIndex.h
lldb_private::npdb::CompileUnitIndex::m_index
PdbIndex & m_index
Definition: CompileUnitIndex.h:90
ParseObjname
static void ParseObjname(const CVSymbol &sym, CompilandIndexItem &cci)
Definition: CompileUnitIndex.cpp:55
PdbIndex.h
lldb_private::npdb::CompilandIndexItem::m_compile_opts
llvm::Optional< llvm::codeview::Compile3Sym > m_compile_opts
Definition: CompileUnitIndex.h:65
lldb_private::npdb::CompileUnitIndex::GetOrCreateCompiland
CompilandIndexItem & GetOrCreateCompiland(uint16_t modi)
Definition: CompileUnitIndex.cpp:133
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
LLDBAssert.h
ParseInlineeLineTableForCompileUnit
static void ParseInlineeLineTableForCompileUnit(CompilandIndexItem &item)
Definition: CompileUnitIndex.cpp:109
IsMainFile
static bool IsMainFile(llvm::StringRef main, llvm::StringRef other)
Definition: CompileUnitIndex.cpp:34
ParseCompile3
static void ParseCompile3(const CVSymbol &sym, CompilandIndexItem &cci)
Definition: CompileUnitIndex.cpp:49
llvm::pdb
Definition: DWARFLocationExpression.h:23
lldb_private::npdb::PdbIndex::dbi
llvm::pdb::DbiStream & dbi()
Definition: PdbIndex.h:121
lldb_private::npdb::CompileUnitIndex::GetMainSourceFile
llvm::SmallString< 64 > GetMainSourceFile(const CompilandIndexItem &item) const
Definition: CompileUnitIndex.cpp:209
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:40
lldb_private::npdb::PdbCompilandId
Definition: PdbSymUid.h:39
PdbUtil.h
lldbassert
#define lldbassert(x)
Definition: LLDBAssert.h:15
lldb_private::npdb::CompilandIndexItem
Represents a single compile unit.
Definition: CompileUnitIndex.h:39
uint32_t
id
void * id
Definition: PlatformiOSSimulatorCoreSimulatorSupport.h:20
uint16_t
lldb_private::npdb::CompilandIndexItem::m_build_info
llvm::SmallVector< llvm::codeview::TypeIndex, 5 > m_build_info
Definition: CompileUnitIndex.h:73
lldb_private::npdb::PdbIndex::ipi
llvm::pdb::TpiStream & ipi()
Definition: PdbIndex.h:127
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
llvm::codeview
Definition: DWARFLocationExpression.h:20
Error
llvm::Error Error
Definition: UdtRecordCompleter.cpp:30
lldb_private::npdb::PdbIndex::pdb
llvm::pdb::PDBFile & pdb()
Definition: PdbIndex.h:118
ParseExtendedInfo
static void ParseExtendedInfo(PdbIndex &index, CompilandIndexItem &item)
Definition: CompileUnitIndex.cpp:79
lldb_private::npdb::CompileUnitIndex::m_comp_units
llvm::DenseMap< uint16_t, std::unique_ptr< CompilandIndexItem > > m_comp_units
Definition: CompileUnitIndex.h:91
lldb
Definition: SBAddress.h:15
lldb_private::npdb::CompilandIndexItem::m_inline_map
std::map< llvm::codeview::TypeIndex, llvm::codeview::InlineeSourceLine > m_inline_map
Definition: CompileUnitIndex.h:77