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