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