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 VariableListSP
272 CompileUnit::GetVariableList(bool can_create)
273 {
274     if (m_variables.get() == nullptr && can_create)
275     {
276         SymbolContext sc;
277         CalculateSymbolContext(&sc);
278         assert(sc.module_sp);
279         sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc);
280     }
281 
282     return m_variables;
283 }
284 
285 uint32_t
286 CompileUnit::FindLineEntry (uint32_t start_idx, uint32_t line, const FileSpec* file_spec_ptr, bool exact, LineEntry *line_entry_ptr)
287 {
288     uint32_t file_idx = 0;
289 
290     if (file_spec_ptr)
291     {
292         file_idx = GetSupportFiles().FindFileIndex (1, *file_spec_ptr, true);
293         if (file_idx == UINT32_MAX)
294             return UINT32_MAX;
295     }
296     else
297     {
298         // All the line table entries actually point to the version of the Compile
299         // Unit that is in the support files (the one at 0 was artificially added.)
300         // So prefer the one further on in the support files if it exists...
301         FileSpecList &support_files = GetSupportFiles();
302         const bool full = true;
303         file_idx = support_files.FindFileIndex (1, support_files.GetFileSpecAtIndex(0), full);
304         if (file_idx == UINT32_MAX)
305             file_idx = 0;
306     }
307     LineTable *line_table = GetLineTable();
308     if (line_table)
309         return line_table->FindLineEntryIndexByFileIndex (start_idx, file_idx, line, exact, line_entry_ptr);
310     return UINT32_MAX;
311 }
312 
313 
314 
315 
316 uint32_t
317 CompileUnit::ResolveSymbolContext
318 (
319     const FileSpec& file_spec,
320     uint32_t line,
321     bool check_inlines,
322     bool exact,
323     uint32_t resolve_scope,
324     SymbolContextList &sc_list
325 )
326 {
327     // First find all of the file indexes that match our "file_spec". If
328     // "file_spec" has an empty directory, then only compare the basenames
329     // when finding file indexes
330     std::vector<uint32_t> file_indexes;
331     const bool full_match = (bool)file_spec.GetDirectory();
332     const bool remove_backup_dots = true;
333     bool file_spec_matches_cu_file_spec = FileSpec::Equal(file_spec, *this, full_match, remove_backup_dots);
334 
335     // If we are not looking for inlined functions and our file spec doesn't
336     // match then we are done...
337     if (file_spec_matches_cu_file_spec == false && check_inlines == false)
338         return 0;
339 
340     uint32_t file_idx = GetSupportFiles().FindFileIndex (1, file_spec, true, remove_backup_dots);
341     while (file_idx != UINT32_MAX)
342     {
343         file_indexes.push_back (file_idx);
344         file_idx = GetSupportFiles().FindFileIndex (file_idx + 1, file_spec, true, remove_backup_dots);
345     }
346 
347     const size_t num_file_indexes = file_indexes.size();
348     if (num_file_indexes == 0)
349         return 0;
350 
351     const uint32_t prev_size = sc_list.GetSize();
352 
353     SymbolContext sc(GetModule());
354     sc.comp_unit = this;
355 
356 
357     if (line != 0)
358     {
359         LineTable *line_table = sc.comp_unit->GetLineTable();
360 
361         if (line_table != nullptr)
362         {
363             uint32_t found_line;
364             uint32_t line_idx;
365 
366             if (num_file_indexes == 1)
367             {
368                 // We only have a single support file that matches, so use
369                 // the line table function that searches for a line entries
370                 // that match a single support file index
371                 LineEntry line_entry;
372                 line_idx = line_table->FindLineEntryIndexByFileIndex (0, file_indexes.front(), line, exact, &line_entry);
373 
374                 // If "exact == true", then "found_line" will be the same
375                 // as "line". If "exact == false", the "found_line" will be the
376                 // closest line entry with a line number greater than "line" and
377                 // we will use this for our subsequent line exact matches below.
378                 found_line = line_entry.line;
379 
380                 while (line_idx != UINT32_MAX)
381                 {
382                     // If they only asked for the line entry, then we're done, we can just copy that over.
383                     // But if they wanted more than just the line number, fill it in.
384                     if (resolve_scope == eSymbolContextLineEntry)
385                     {
386                         sc.line_entry = line_entry;
387                     }
388                     else
389                     {
390                         line_entry.range.GetBaseAddress().CalculateSymbolContext(&sc, resolve_scope);
391                     }
392 
393                     sc_list.Append(sc);
394                     line_idx = line_table->FindLineEntryIndexByFileIndex (line_idx + 1, file_indexes.front(), found_line, true, &line_entry);
395                 }
396             }
397             else
398             {
399                 // We found multiple support files that match "file_spec" so use
400                 // the line table function that searches for a line entries
401                 // that match a multiple support file indexes.
402                 LineEntry line_entry;
403                 line_idx = line_table->FindLineEntryIndexByFileIndex (0, file_indexes, 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 (resolve_scope == eSymbolContextLineEntry)
414                     {
415                         sc.line_entry = line_entry;
416                     }
417                     else
418                     {
419                         line_entry.range.GetBaseAddress().CalculateSymbolContext(&sc, resolve_scope);
420                     }
421 
422                     sc_list.Append(sc);
423                     line_idx = line_table->FindLineEntryIndexByFileIndex (line_idx + 1, file_indexes, found_line, true, &line_entry);
424                 }
425             }
426         }
427     }
428     else if (file_spec_matches_cu_file_spec && !check_inlines)
429     {
430         // only append the context if we aren't looking for inline call sites
431         // by file and line and if the file spec matches that of the compile unit
432         sc_list.Append(sc);
433     }
434     return sc_list.GetSize() - prev_size;
435 }
436 
437 bool
438 CompileUnit::GetIsOptimized ()
439 {
440     return m_is_optimized;
441 }
442 
443 void
444 CompileUnit::SetVariableList(VariableListSP &variables)
445 {
446     m_variables = variables;
447 }
448 
449 const std::vector<ConstString> &
450 CompileUnit::GetImportedModules ()
451 {
452     if (m_imported_modules.empty() &&
453         m_flags.IsClear(flagsParsedImportedModules))
454     {
455         m_flags.Set(flagsParsedImportedModules);
456         if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor())
457         {
458             SymbolContext sc;
459             CalculateSymbolContext(&sc);
460             symbol_vendor->ParseImportedModules(sc, m_imported_modules);
461         }
462     }
463     return m_imported_modules;
464 }
465 
466 FileSpecList&
467 CompileUnit::GetSupportFiles ()
468 {
469     if (m_support_files.GetSize() == 0)
470     {
471         if (m_flags.IsClear(flagsParsedSupportFiles))
472         {
473             m_flags.Set(flagsParsedSupportFiles);
474             SymbolVendor* symbol_vendor = GetModule()->GetSymbolVendor();
475             if (symbol_vendor)
476             {
477                 SymbolContext sc;
478                 CalculateSymbolContext(&sc);
479                 symbol_vendor->ParseCompileUnitSupportFiles(sc, m_support_files);
480             }
481         }
482     }
483     return m_support_files;
484 }
485 
486 void *
487 CompileUnit::GetUserData () const
488 {
489     return m_user_data;
490 }
491 
492 
493