1 //===-- CompileUnit.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 "lldb/Symbol/CompileUnit.h"
11 #include "lldb/Core/Module.h"
12 #include "lldb/Symbol/LineTable.h"
13 #include "lldb/Symbol/SymbolVendor.h"
14 #include "lldb/Symbol/VariableList.h"
15 #include "lldb/Target/Language.h"
16 
17 using namespace lldb;
18 using namespace lldb_private;
19 
20 CompileUnit::CompileUnit(const lldb::ModuleSP &module_sp, void *user_data,
21                          const char *pathname, const lldb::user_id_t cu_sym_id,
22                          lldb::LanguageType language,
23                          lldb_private::LazyBool is_optimized)
24     : ModuleChild(module_sp), FileSpec(pathname, false), UserID(cu_sym_id),
25       m_user_data(user_data), m_language(language), m_flags(0), m_functions(),
26       m_support_files(), m_line_table_ap(), m_variables(),
27       m_is_optimized(is_optimized) {
28   if (language != eLanguageTypeUnknown)
29     m_flags.Set(flagsParsedLanguage);
30   assert(module_sp);
31 }
32 
33 CompileUnit::CompileUnit(const lldb::ModuleSP &module_sp, void *user_data,
34                          const FileSpec &fspec, const lldb::user_id_t cu_sym_id,
35                          lldb::LanguageType language,
36                          lldb_private::LazyBool is_optimized)
37     : ModuleChild(module_sp), FileSpec(fspec), UserID(cu_sym_id),
38       m_user_data(user_data), m_language(language), m_flags(0), m_functions(),
39       m_support_files(), m_line_table_ap(), m_variables(),
40       m_is_optimized(is_optimized) {
41   if (language != eLanguageTypeUnknown)
42     m_flags.Set(flagsParsedLanguage);
43   assert(module_sp);
44 }
45 
46 CompileUnit::~CompileUnit() {}
47 
48 void CompileUnit::CalculateSymbolContext(SymbolContext *sc) {
49   sc->comp_unit = this;
50   GetModule()->CalculateSymbolContext(sc);
51 }
52 
53 ModuleSP CompileUnit::CalculateSymbolContextModule() { return GetModule(); }
54 
55 CompileUnit *CompileUnit::CalculateSymbolContextCompileUnit() { return this; }
56 
57 void CompileUnit::DumpSymbolContext(Stream *s) {
58   GetModule()->DumpSymbolContext(s);
59   s->Printf(", CompileUnit{0x%8.8" PRIx64 "}", GetID());
60 }
61 
62 void CompileUnit::GetDescription(Stream *s,
63                                  lldb::DescriptionLevel level) const {
64   const char *language = Language::GetNameForLanguageType(m_language);
65   *s << "id = " << (const UserID &)*this << ", file = \""
66      << (const FileSpec &)*this << "\", language = \"" << language << '"';
67 }
68 
69 //----------------------------------------------------------------------
70 // Dump the current contents of this object. No functions that cause on demand
71 // parsing of functions, globals, statics are called, so this is a good
72 // function to call to get an idea of the current contents of the CompileUnit
73 // object.
74 //----------------------------------------------------------------------
75 void CompileUnit::Dump(Stream *s, bool show_context) const {
76   const char *language = Language::GetNameForLanguageType(m_language);
77 
78   s->Printf("%p: ", static_cast<const void *>(this));
79   s->Indent();
80   *s << "CompileUnit" << static_cast<const UserID &>(*this) << ", language = \""
81      << language << "\", file = '" << static_cast<const FileSpec &>(*this)
82      << "'\n";
83 
84   //  m_types.Dump(s);
85 
86   if (m_variables.get()) {
87     s->IndentMore();
88     m_variables->Dump(s, show_context);
89     s->IndentLess();
90   }
91 
92   if (!m_functions.empty()) {
93     s->IndentMore();
94     std::vector<FunctionSP>::const_iterator pos;
95     std::vector<FunctionSP>::const_iterator end = m_functions.end();
96     for (pos = m_functions.begin(); pos != end; ++pos) {
97       (*pos)->Dump(s, show_context);
98     }
99 
100     s->IndentLess();
101     s->EOL();
102   }
103 }
104 
105 //----------------------------------------------------------------------
106 // Add a function to this compile unit
107 //----------------------------------------------------------------------
108 void CompileUnit::AddFunction(FunctionSP &funcSP) {
109   // TODO: order these by address
110   m_functions.push_back(funcSP);
111 }
112 
113 FunctionSP CompileUnit::GetFunctionAtIndex(size_t idx) {
114   FunctionSP funcSP;
115   if (idx < m_functions.size())
116     funcSP = m_functions[idx];
117   return funcSP;
118 }
119 
120 //----------------------------------------------------------------------
121 // Find functions using the Mangled::Tokens token list. This function currently
122 // implements an interactive approach designed to find all instances of certain
123 // functions. It isn't designed to the quickest way to lookup functions as it
124 // will need to iterate through all functions and see if they match, though it
125 // does provide a powerful and context sensitive way to search for all
126 // functions with a certain name, all functions in a namespace, or all
127 // functions of a template type. See Mangled::Tokens::Parse() comments for more
128 // information.
129 //
130 // The function prototype will need to change to return a list of results. It
131 // was originally used to help debug the Mangled class and the
132 // Mangled::Tokens::MatchesQuery() function and it currently will print out a
133 // list of matching results for the functions that are currently in this
134 // compile unit.
135 //
136 // A FindFunctions method should be called prior to this that takes
137 // a regular function name (const char * or ConstString as a parameter) before
138 // resorting to this slower but more complete function. The other FindFunctions
139 // method should be able to take advantage of any accelerator tables available
140 // in the debug information (which is parsed by the SymbolFile parser plug-ins
141 // and registered with each Module).
142 //----------------------------------------------------------------------
143 // void
144 // CompileUnit::FindFunctions(const Mangled::Tokens& tokens)
145 //{
146 //  if (!m_functions.empty())
147 //  {
148 //      Stream s(stdout);
149 //      std::vector<FunctionSP>::const_iterator pos;
150 //      std::vector<FunctionSP>::const_iterator end = m_functions.end();
151 //      for (pos = m_functions.begin(); pos != end; ++pos)
152 //      {
153 //          const ConstString& demangled = (*pos)->Mangled().Demangled();
154 //          if (demangled)
155 //          {
156 //              const Mangled::Tokens& func_tokens =
157 //              (*pos)->Mangled().GetTokens();
158 //              if (func_tokens.MatchesQuery (tokens))
159 //                  s << "demangled MATCH found: " << demangled << "\n";
160 //          }
161 //      }
162 //  }
163 //}
164 
165 FunctionSP CompileUnit::FindFunctionByUID(lldb::user_id_t func_uid) {
166   FunctionSP funcSP;
167   if (!m_functions.empty()) {
168     std::vector<FunctionSP>::const_iterator pos;
169     std::vector<FunctionSP>::const_iterator end = m_functions.end();
170     for (pos = m_functions.begin(); pos != end; ++pos) {
171       if ((*pos)->GetID() == func_uid) {
172         funcSP = *pos;
173         break;
174       }
175     }
176   }
177   return funcSP;
178 }
179 
180 lldb::LanguageType CompileUnit::GetLanguage() {
181   if (m_language == eLanguageTypeUnknown) {
182     if (m_flags.IsClear(flagsParsedLanguage)) {
183       m_flags.Set(flagsParsedLanguage);
184       SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor();
185       if (symbol_vendor) {
186         SymbolContext sc;
187         CalculateSymbolContext(&sc);
188         m_language = symbol_vendor->ParseCompileUnitLanguage(sc);
189       }
190     }
191   }
192   return m_language;
193 }
194 
195 LineTable *CompileUnit::GetLineTable() {
196   if (m_line_table_ap.get() == nullptr) {
197     if (m_flags.IsClear(flagsParsedLineTable)) {
198       m_flags.Set(flagsParsedLineTable);
199       SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor();
200       if (symbol_vendor) {
201         SymbolContext sc;
202         CalculateSymbolContext(&sc);
203         symbol_vendor->ParseCompileUnitLineTable(sc);
204       }
205     }
206   }
207   return m_line_table_ap.get();
208 }
209 
210 void CompileUnit::SetLineTable(LineTable *line_table) {
211   if (line_table == nullptr)
212     m_flags.Clear(flagsParsedLineTable);
213   else
214     m_flags.Set(flagsParsedLineTable);
215   m_line_table_ap.reset(line_table);
216 }
217 
218 DebugMacros *CompileUnit::GetDebugMacros() {
219   if (m_debug_macros_sp.get() == nullptr) {
220     if (m_flags.IsClear(flagsParsedDebugMacros)) {
221       m_flags.Set(flagsParsedDebugMacros);
222       SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor();
223       if (symbol_vendor) {
224         SymbolContext sc;
225         CalculateSymbolContext(&sc);
226         symbol_vendor->ParseCompileUnitDebugMacros(sc);
227       }
228     }
229   }
230 
231   return m_debug_macros_sp.get();
232 }
233 
234 void CompileUnit::SetDebugMacros(const DebugMacrosSP &debug_macros_sp) {
235   if (debug_macros_sp.get() == nullptr)
236     m_flags.Clear(flagsParsedDebugMacros);
237   else
238     m_flags.Set(flagsParsedDebugMacros);
239   m_debug_macros_sp = debug_macros_sp;
240 }
241 
242 VariableListSP CompileUnit::GetVariableList(bool can_create) {
243   if (m_variables.get() == nullptr && can_create) {
244     SymbolContext sc;
245     CalculateSymbolContext(&sc);
246     assert(sc.module_sp);
247     sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc);
248   }
249 
250   return m_variables;
251 }
252 
253 uint32_t CompileUnit::FindLineEntry(uint32_t start_idx, uint32_t line,
254                                     const FileSpec *file_spec_ptr, bool exact,
255                                     LineEntry *line_entry_ptr) {
256   uint32_t file_idx = 0;
257 
258   if (file_spec_ptr) {
259     file_idx = GetSupportFiles().FindFileIndex(1, *file_spec_ptr, true);
260     if (file_idx == UINT32_MAX)
261       return UINT32_MAX;
262   } else {
263     // All the line table entries actually point to the version of the Compile
264     // Unit that is in the support files (the one at 0 was artificially added.)
265     // So prefer the one further on in the support files if it exists...
266     FileSpecList &support_files = GetSupportFiles();
267     const bool full = true;
268     file_idx = support_files.FindFileIndex(
269         1, support_files.GetFileSpecAtIndex(0), full);
270     if (file_idx == UINT32_MAX)
271       file_idx = 0;
272   }
273   LineTable *line_table = GetLineTable();
274   if (line_table)
275     return line_table->FindLineEntryIndexByFileIndex(start_idx, file_idx, line,
276                                                      exact, line_entry_ptr);
277   return UINT32_MAX;
278 }
279 
280 uint32_t CompileUnit::ResolveSymbolContext(const FileSpec &file_spec,
281                                            uint32_t line, bool check_inlines,
282                                            bool exact, uint32_t resolve_scope,
283                                            SymbolContextList &sc_list) {
284   // First find all of the file indexes that match our "file_spec". If
285   // "file_spec" has an empty directory, then only compare the basenames when
286   // finding file indexes
287   std::vector<uint32_t> file_indexes;
288   const bool full_match = (bool)file_spec.GetDirectory();
289   bool file_spec_matches_cu_file_spec =
290       FileSpec::Equal(file_spec, *this, full_match);
291 
292   // If we are not looking for inlined functions and our file spec doesn't
293   // match then we are done...
294   if (file_spec_matches_cu_file_spec == false && check_inlines == false)
295     return 0;
296 
297   uint32_t file_idx =
298       GetSupportFiles().FindFileIndex(1, file_spec, true);
299   while (file_idx != UINT32_MAX) {
300     file_indexes.push_back(file_idx);
301     file_idx = GetSupportFiles().FindFileIndex(file_idx + 1, file_spec, true);
302   }
303 
304   const size_t num_file_indexes = file_indexes.size();
305   if (num_file_indexes == 0)
306     return 0;
307 
308   const uint32_t prev_size = sc_list.GetSize();
309 
310   SymbolContext sc(GetModule());
311   sc.comp_unit = this;
312 
313   if (line != 0) {
314     LineTable *line_table = sc.comp_unit->GetLineTable();
315 
316     if (line_table != nullptr) {
317       uint32_t found_line;
318       uint32_t line_idx;
319 
320       if (num_file_indexes == 1) {
321         // We only have a single support file that matches, so use the line
322         // table function that searches for a line entries that match a single
323         // support file index
324         LineEntry line_entry;
325         line_idx = line_table->FindLineEntryIndexByFileIndex(
326             0, file_indexes.front(), line, exact, &line_entry);
327 
328         // If "exact == true", then "found_line" will be the same as "line". If
329         // "exact == false", the "found_line" will be the closest line entry
330         // with a line number greater than "line" and we will use this for our
331         // subsequent line exact matches below.
332         found_line = line_entry.line;
333 
334         while (line_idx != UINT32_MAX) {
335           // If they only asked for the line entry, then we're done, we can
336           // just copy that over. But if they wanted more than just the line
337           // number, fill it in.
338           if (resolve_scope == eSymbolContextLineEntry) {
339             sc.line_entry = line_entry;
340           } else {
341             line_entry.range.GetBaseAddress().CalculateSymbolContext(
342                 &sc, resolve_scope);
343           }
344 
345           sc_list.Append(sc);
346           line_idx = line_table->FindLineEntryIndexByFileIndex(
347               line_idx + 1, file_indexes.front(), found_line, true,
348               &line_entry);
349         }
350       } else {
351         // We found multiple support files that match "file_spec" so use the
352         // line table function that searches for a line entries that match a
353         // multiple support file indexes.
354         LineEntry line_entry;
355         line_idx = line_table->FindLineEntryIndexByFileIndex(
356             0, file_indexes, line, exact, &line_entry);
357 
358         // If "exact == true", then "found_line" will be the same as "line". If
359         // "exact == false", the "found_line" will be the closest line entry
360         // with a line number greater than "line" and we will use this for our
361         // subsequent line exact matches below.
362         found_line = line_entry.line;
363 
364         while (line_idx != UINT32_MAX) {
365           if (resolve_scope == eSymbolContextLineEntry) {
366             sc.line_entry = line_entry;
367           } else {
368             line_entry.range.GetBaseAddress().CalculateSymbolContext(
369                 &sc, resolve_scope);
370           }
371 
372           sc_list.Append(sc);
373           line_idx = line_table->FindLineEntryIndexByFileIndex(
374               line_idx + 1, file_indexes, found_line, true, &line_entry);
375         }
376       }
377     }
378   } else if (file_spec_matches_cu_file_spec && !check_inlines) {
379     // only append the context if we aren't looking for inline call sites by
380     // file and line and if the file spec matches that of the compile unit
381     sc_list.Append(sc);
382   }
383   return sc_list.GetSize() - prev_size;
384 }
385 
386 bool CompileUnit::GetIsOptimized() {
387   if (m_is_optimized == eLazyBoolCalculate) {
388     m_is_optimized = eLazyBoolNo;
389     if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) {
390       SymbolContext sc;
391       CalculateSymbolContext(&sc);
392       if (symbol_vendor->ParseCompileUnitIsOptimized(sc))
393         m_is_optimized = eLazyBoolYes;
394     }
395   }
396   return m_is_optimized;
397 }
398 
399 void CompileUnit::SetVariableList(VariableListSP &variables) {
400   m_variables = variables;
401 }
402 
403 const std::vector<ConstString> &CompileUnit::GetImportedModules() {
404   if (m_imported_modules.empty() &&
405       m_flags.IsClear(flagsParsedImportedModules)) {
406     m_flags.Set(flagsParsedImportedModules);
407     if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) {
408       SymbolContext sc;
409       CalculateSymbolContext(&sc);
410       symbol_vendor->ParseImportedModules(sc, m_imported_modules);
411     }
412   }
413   return m_imported_modules;
414 }
415 
416 FileSpecList &CompileUnit::GetSupportFiles() {
417   if (m_support_files.GetSize() == 0) {
418     if (m_flags.IsClear(flagsParsedSupportFiles)) {
419       m_flags.Set(flagsParsedSupportFiles);
420       SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor();
421       if (symbol_vendor) {
422         SymbolContext sc;
423         CalculateSymbolContext(&sc);
424         symbol_vendor->ParseCompileUnitSupportFiles(sc, m_support_files);
425       }
426     }
427   }
428   return m_support_files;
429 }
430 
431 void *CompileUnit::GetUserData() const { return m_user_data; }
432