1 //===-- 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 
29 using namespace lldb;
30 using namespace lldb_private;
31 using namespace lldb_private::npdb;
32 using namespace llvm::codeview;
33 using namespace llvm::pdb;
34 
35 static 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 
50 static 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 
56 static 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 
62 static 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 
80 static 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 
110 CompilandIndexItem::CompilandIndexItem(
111     PdbSymUid uid, llvm::pdb::ModuleDebugStreamRef debug_stream,
112     llvm::pdb::DbiModuleDescriptor descriptor)
113     : m_uid(uid), m_debug_stream(std::move(debug_stream)),
114       m_module_descriptor(std::move(descriptor)) {}
115 
116 CompilandIndexItem &CompileUnitIndex::GetOrCreateCompiland(uint16_t modi) {
117   PdbSymUid uid = PdbSymUid::makeCompilandId(modi);
118   return GetOrCreateCompiland(uid);
119 }
120 
121 CompilandIndexItem &
122 CompileUnitIndex::GetOrCreateCompiland(PdbSymUid compiland_uid) {
123   auto result = m_comp_units.try_emplace(compiland_uid.toOpaqueId(), nullptr);
124   if (!result.second)
125     return *result.first->second;
126 
127   // Find the module list and load its debug information stream and cache it
128   // since we need to use it for almost all interesting operations.
129   const DbiModuleList &modules = m_index.dbi().modules();
130   uint16_t modi = compiland_uid.asCompiland().modi;
131   llvm::pdb::DbiModuleDescriptor descriptor = modules.getModuleDescriptor(modi);
132   uint16_t stream = descriptor.getModuleStreamIndex();
133   std::unique_ptr<llvm::msf::MappedBlockStream> stream_data =
134       m_index.pdb().createIndexedStream(stream);
135   llvm::pdb::ModuleDebugStreamRef debug_stream(descriptor,
136                                                std::move(stream_data));
137   cantFail(debug_stream.reload());
138 
139   std::unique_ptr<CompilandIndexItem> &cci = result.first->second;
140 
141   cci = llvm::make_unique<CompilandIndexItem>(
142       compiland_uid, std::move(debug_stream), std::move(descriptor));
143   ParseExtendedInfo(m_index, *cci);
144 
145   cci->m_strings.initialize(debug_stream.getSubsectionsArray());
146   PDBStringTable &strings = cantFail(m_index.pdb().getStringTable());
147   cci->m_strings.setStrings(strings.getStringTable());
148 
149   // We want the main source file to always comes first.  Note that we can't
150   // just push_back the main file onto the front because `GetMainSourceFile`
151   // computes it in such a way that it doesn't own the resulting memory.  So we
152   // have to iterate the module file list comparing each one to the main file
153   // name until we find it, and we can cache that one since the memory is backed
154   // by a contiguous chunk inside the mapped PDB.
155   llvm::SmallString<64> main_file = GetMainSourceFile(*cci);
156   std::string s = main_file.str();
157   llvm::sys::path::native(main_file);
158 
159   uint32_t file_count = modules.getSourceFileCount(modi);
160   cci->m_file_list.reserve(file_count);
161   bool found_main_file = false;
162   for (llvm::StringRef file : modules.source_files(modi)) {
163     if (!found_main_file && IsMainFile(main_file, file)) {
164       cci->m_file_list.insert(cci->m_file_list.begin(), file);
165       found_main_file = true;
166       continue;
167     }
168     cci->m_file_list.push_back(file);
169   }
170 
171   return *cci;
172 }
173 
174 const CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) const {
175   return GetCompiland(PdbSymUid::makeCompilandId(modi));
176 }
177 
178 const CompilandIndexItem *
179 CompileUnitIndex::GetCompiland(PdbSymUid compiland_uid) const {
180   auto iter = m_comp_units.find(compiland_uid.toOpaqueId());
181   if (iter == m_comp_units.end())
182     return nullptr;
183   return iter->second.get();
184 }
185 
186 CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) {
187   return GetCompiland(PdbSymUid::makeCompilandId(modi));
188 }
189 
190 CompilandIndexItem *CompileUnitIndex::GetCompiland(PdbSymUid compiland_uid) {
191   auto iter = m_comp_units.find(compiland_uid.toOpaqueId());
192   if (iter == m_comp_units.end())
193     return nullptr;
194   return iter->second.get();
195 }
196 
197 llvm::SmallString<64>
198 CompileUnitIndex::GetMainSourceFile(const CompilandIndexItem &item) const {
199   // LF_BUILDINFO contains a list of arg indices which point to LF_STRING_ID
200   // records in the IPI stream.  The order of the arg indices is as follows:
201   // [0] - working directory where compiler was invoked.
202   // [1] - absolute path to compiler binary
203   // [2] - source file name
204   // [3] - path to compiler generated PDB (the /Zi PDB, although this entry gets
205   //       added even when using /Z7)
206   // [4] - full command line invocation.
207   //
208   // We need to form the path [0]\[2] to generate the full path to the main
209   // file.source
210   if (item.m_build_info.size() < 3)
211     return {""};
212 
213   LazyRandomTypeCollection &types = m_index.ipi().typeCollection();
214 
215   StringIdRecord working_dir;
216   StringIdRecord file_name;
217   CVType dir_cvt = types.getType(item.m_build_info[0]);
218   CVType file_cvt = types.getType(item.m_build_info[2]);
219   llvm::cantFail(
220       TypeDeserializer::deserializeAs<StringIdRecord>(dir_cvt, working_dir));
221   llvm::cantFail(
222       TypeDeserializer::deserializeAs<StringIdRecord>(file_cvt, file_name));
223 
224   llvm::SmallString<64> absolute_path = working_dir.String;
225   llvm::sys::path::append(absolute_path, file_name.String);
226   return absolute_path;
227 }
228