]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/Symbol/CompileUnit.cpp
Vendor import of lldb release_40 branch r292009:
[FreeBSD/FreeBSD.git] / source / Symbol / CompileUnit.cpp
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
71 // demand parsing of functions, globals, statics are called, so this
72 // is a good function to call to get an idea of the current contents of
73 // the CompileUnit 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
122 // function currently implements an interactive approach designed to find
123 // all instances of certain functions. It isn't designed to the
124 // quickest way to lookup functions as it will need to iterate through
125 // all functions and see if they match, though it does provide a powerful
126 // and context sensitive way to search for all functions with a certain
127 // name, all functions in a namespace, or all functions of a template
128 // type. See Mangled::Tokens::Parse() comments for more information.
129 //
130 // The function prototype will need to change to return a list of
131 // results. It was originally used to help debug the Mangled class
132 // and the Mangled::Tokens::MatchesQuery() function and it currently
133 // will print out a list of matching results for the functions that
134 // are currently in this 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)
138 // before resorting to this slower but more complete function. The
139 // other FindFunctions method should be able to take advantage of any
140 // accelerator tables available in the debug information (which is
141 // parsed by the SymbolFile parser plug-ins and registered with each
142 // Module).
143 //----------------------------------------------------------------------
144 // void
145 // CompileUnit::FindFunctions(const Mangled::Tokens& tokens)
146 //{
147 //  if (!m_functions.empty())
148 //  {
149 //      Stream s(stdout);
150 //      std::vector<FunctionSP>::const_iterator pos;
151 //      std::vector<FunctionSP>::const_iterator end = m_functions.end();
152 //      for (pos = m_functions.begin(); pos != end; ++pos)
153 //      {
154 //          const ConstString& demangled = (*pos)->Mangled().Demangled();
155 //          if (demangled)
156 //          {
157 //              const Mangled::Tokens& func_tokens =
158 //              (*pos)->Mangled().GetTokens();
159 //              if (func_tokens.MatchesQuery (tokens))
160 //                  s << "demangled MATCH found: " << demangled << "\n";
161 //          }
162 //      }
163 //  }
164 //}
165
166 FunctionSP CompileUnit::FindFunctionByUID(lldb::user_id_t func_uid) {
167   FunctionSP funcSP;
168   if (!m_functions.empty()) {
169     std::vector<FunctionSP>::const_iterator pos;
170     std::vector<FunctionSP>::const_iterator end = m_functions.end();
171     for (pos = m_functions.begin(); pos != end; ++pos) {
172       if ((*pos)->GetID() == func_uid) {
173         funcSP = *pos;
174         break;
175       }
176     }
177   }
178   return funcSP;
179 }
180
181 lldb::LanguageType CompileUnit::GetLanguage() {
182   if (m_language == eLanguageTypeUnknown) {
183     if (m_flags.IsClear(flagsParsedLanguage)) {
184       m_flags.Set(flagsParsedLanguage);
185       SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor();
186       if (symbol_vendor) {
187         SymbolContext sc;
188         CalculateSymbolContext(&sc);
189         m_language = symbol_vendor->ParseCompileUnitLanguage(sc);
190       }
191     }
192   }
193   return m_language;
194 }
195
196 LineTable *CompileUnit::GetLineTable() {
197   if (m_line_table_ap.get() == nullptr) {
198     if (m_flags.IsClear(flagsParsedLineTable)) {
199       m_flags.Set(flagsParsedLineTable);
200       SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor();
201       if (symbol_vendor) {
202         SymbolContext sc;
203         CalculateSymbolContext(&sc);
204         symbol_vendor->ParseCompileUnitLineTable(sc);
205       }
206     }
207   }
208   return m_line_table_ap.get();
209 }
210
211 void CompileUnit::SetLineTable(LineTable *line_table) {
212   if (line_table == nullptr)
213     m_flags.Clear(flagsParsedLineTable);
214   else
215     m_flags.Set(flagsParsedLineTable);
216   m_line_table_ap.reset(line_table);
217 }
218
219 DebugMacros *CompileUnit::GetDebugMacros() {
220   if (m_debug_macros_sp.get() == nullptr) {
221     if (m_flags.IsClear(flagsParsedDebugMacros)) {
222       m_flags.Set(flagsParsedDebugMacros);
223       SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor();
224       if (symbol_vendor) {
225         SymbolContext sc;
226         CalculateSymbolContext(&sc);
227         symbol_vendor->ParseCompileUnitDebugMacros(sc);
228       }
229     }
230   }
231
232   return m_debug_macros_sp.get();
233 }
234
235 void CompileUnit::SetDebugMacros(const DebugMacrosSP &debug_macros_sp) {
236   if (debug_macros_sp.get() == nullptr)
237     m_flags.Clear(flagsParsedDebugMacros);
238   else
239     m_flags.Set(flagsParsedDebugMacros);
240   m_debug_macros_sp = debug_macros_sp;
241 }
242
243 VariableListSP CompileUnit::GetVariableList(bool can_create) {
244   if (m_variables.get() == nullptr && can_create) {
245     SymbolContext sc;
246     CalculateSymbolContext(&sc);
247     assert(sc.module_sp);
248     sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc);
249   }
250
251   return m_variables;
252 }
253
254 uint32_t CompileUnit::FindLineEntry(uint32_t start_idx, uint32_t line,
255                                     const FileSpec *file_spec_ptr, bool exact,
256                                     LineEntry *line_entry_ptr) {
257   uint32_t file_idx = 0;
258
259   if (file_spec_ptr) {
260     file_idx = GetSupportFiles().FindFileIndex(1, *file_spec_ptr, true);
261     if (file_idx == UINT32_MAX)
262       return UINT32_MAX;
263   } else {
264     // All the line table entries actually point to the version of the Compile
265     // Unit that is in the support files (the one at 0 was artificially added.)
266     // So prefer the one further on in the support files if it exists...
267     FileSpecList &support_files = GetSupportFiles();
268     const bool full = true;
269     file_idx = support_files.FindFileIndex(
270         1, support_files.GetFileSpecAtIndex(0), full);
271     if (file_idx == UINT32_MAX)
272       file_idx = 0;
273   }
274   LineTable *line_table = GetLineTable();
275   if (line_table)
276     return line_table->FindLineEntryIndexByFileIndex(start_idx, file_idx, line,
277                                                      exact, line_entry_ptr);
278   return UINT32_MAX;
279 }
280
281 uint32_t CompileUnit::ResolveSymbolContext(const FileSpec &file_spec,
282                                            uint32_t line, bool check_inlines,
283                                            bool exact, uint32_t resolve_scope,
284                                            SymbolContextList &sc_list) {
285   // First find all of the file indexes that match our "file_spec". If
286   // "file_spec" has an empty directory, then only compare the basenames
287   // when finding file indexes
288   std::vector<uint32_t> file_indexes;
289   const bool full_match = (bool)file_spec.GetDirectory();
290   const bool remove_backup_dots = true;
291   bool file_spec_matches_cu_file_spec =
292       FileSpec::Equal(file_spec, *this, full_match, remove_backup_dots);
293
294   // If we are not looking for inlined functions and our file spec doesn't
295   // match then we are done...
296   if (file_spec_matches_cu_file_spec == false && check_inlines == false)
297     return 0;
298
299   uint32_t file_idx =
300       GetSupportFiles().FindFileIndex(1, file_spec, true, remove_backup_dots);
301   while (file_idx != UINT32_MAX) {
302     file_indexes.push_back(file_idx);
303     file_idx = GetSupportFiles().FindFileIndex(file_idx + 1, file_spec, true,
304                                                remove_backup_dots);
305   }
306
307   const size_t num_file_indexes = file_indexes.size();
308   if (num_file_indexes == 0)
309     return 0;
310
311   const uint32_t prev_size = sc_list.GetSize();
312
313   SymbolContext sc(GetModule());
314   sc.comp_unit = this;
315
316   if (line != 0) {
317     LineTable *line_table = sc.comp_unit->GetLineTable();
318
319     if (line_table != nullptr) {
320       uint32_t found_line;
321       uint32_t line_idx;
322
323       if (num_file_indexes == 1) {
324         // We only have a single support file that matches, so use
325         // the line table function that searches for a line entries
326         // that match a single support file index
327         LineEntry line_entry;
328         line_idx = line_table->FindLineEntryIndexByFileIndex(
329             0, file_indexes.front(), line, exact, &line_entry);
330
331         // If "exact == true", then "found_line" will be the same
332         // as "line". If "exact == false", the "found_line" will be the
333         // closest line entry with a line number greater than "line" and
334         // we will use this for our subsequent line exact matches below.
335         found_line = line_entry.line;
336
337         while (line_idx != UINT32_MAX) {
338           // If they only asked for the line entry, then we're done, we can just
339           // copy that over.
340           // But if they wanted more than just the line number, fill it in.
341           if (resolve_scope == eSymbolContextLineEntry) {
342             sc.line_entry = line_entry;
343           } else {
344             line_entry.range.GetBaseAddress().CalculateSymbolContext(
345                 &sc, resolve_scope);
346           }
347
348           sc_list.Append(sc);
349           line_idx = line_table->FindLineEntryIndexByFileIndex(
350               line_idx + 1, file_indexes.front(), found_line, true,
351               &line_entry);
352         }
353       } else {
354         // We found multiple support files that match "file_spec" so use
355         // the line table function that searches for a line entries
356         // that match a multiple support file indexes.
357         LineEntry line_entry;
358         line_idx = line_table->FindLineEntryIndexByFileIndex(
359             0, file_indexes, line, exact, &line_entry);
360
361         // If "exact == true", then "found_line" will be the same
362         // as "line". If "exact == false", the "found_line" will be the
363         // closest line entry with a line number greater than "line" and
364         // we will use this for our subsequent line exact matches below.
365         found_line = line_entry.line;
366
367         while (line_idx != UINT32_MAX) {
368           if (resolve_scope == eSymbolContextLineEntry) {
369             sc.line_entry = line_entry;
370           } else {
371             line_entry.range.GetBaseAddress().CalculateSymbolContext(
372                 &sc, resolve_scope);
373           }
374
375           sc_list.Append(sc);
376           line_idx = line_table->FindLineEntryIndexByFileIndex(
377               line_idx + 1, file_indexes, found_line, true, &line_entry);
378         }
379       }
380     }
381   } else if (file_spec_matches_cu_file_spec && !check_inlines) {
382     // only append the context if we aren't looking for inline call sites
383     // by file and line and if the file spec matches that of the compile unit
384     sc_list.Append(sc);
385   }
386   return sc_list.GetSize() - prev_size;
387 }
388
389 bool CompileUnit::GetIsOptimized() {
390   if (m_is_optimized == eLazyBoolCalculate) {
391     m_is_optimized = eLazyBoolNo;
392     if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) {
393       SymbolContext sc;
394       CalculateSymbolContext(&sc);
395       if (symbol_vendor->ParseCompileUnitIsOptimized(sc))
396         m_is_optimized = eLazyBoolYes;
397     }
398   }
399   return m_is_optimized;
400 }
401
402 void CompileUnit::SetVariableList(VariableListSP &variables) {
403   m_variables = variables;
404 }
405
406 const std::vector<ConstString> &CompileUnit::GetImportedModules() {
407   if (m_imported_modules.empty() &&
408       m_flags.IsClear(flagsParsedImportedModules)) {
409     m_flags.Set(flagsParsedImportedModules);
410     if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) {
411       SymbolContext sc;
412       CalculateSymbolContext(&sc);
413       symbol_vendor->ParseImportedModules(sc, m_imported_modules);
414     }
415   }
416   return m_imported_modules;
417 }
418
419 FileSpecList &CompileUnit::GetSupportFiles() {
420   if (m_support_files.GetSize() == 0) {
421     if (m_flags.IsClear(flagsParsedSupportFiles)) {
422       m_flags.Set(flagsParsedSupportFiles);
423       SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor();
424       if (symbol_vendor) {
425         SymbolContext sc;
426         CalculateSymbolContext(&sc);
427         symbol_vendor->ParseCompileUnitSupportFiles(sc, m_support_files);
428       }
429     }
430   }
431   return m_support_files;
432 }
433
434 void *CompileUnit::GetUserData() const { return m_user_data; }