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