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