1dda28197Spatrick //===-- CompileUnit.cpp ---------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Symbol/CompileUnit.h"
10061da546Spatrick #include "lldb/Core/Module.h"
11061da546Spatrick #include "lldb/Symbol/LineTable.h"
12061da546Spatrick #include "lldb/Symbol/SymbolFile.h"
13061da546Spatrick #include "lldb/Symbol/VariableList.h"
14061da546Spatrick #include "lldb/Target/Language.h"
15061da546Spatrick #include "lldb/Utility/Timer.h"
16*f6aab3d8Srobert #include <optional>
17061da546Spatrick
18061da546Spatrick using namespace lldb;
19061da546Spatrick using namespace lldb_private;
20061da546Spatrick
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)21061da546Spatrick CompileUnit::CompileUnit(const lldb::ModuleSP &module_sp, void *user_data,
22061da546Spatrick const char *pathname, const lldb::user_id_t cu_sym_id,
23061da546Spatrick lldb::LanguageType language,
24061da546Spatrick lldb_private::LazyBool is_optimized)
25061da546Spatrick : CompileUnit(module_sp, user_data, FileSpec(pathname), cu_sym_id, language,
26061da546Spatrick is_optimized) {}
27061da546Spatrick
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)28061da546Spatrick CompileUnit::CompileUnit(const lldb::ModuleSP &module_sp, void *user_data,
29061da546Spatrick const FileSpec &fspec, const lldb::user_id_t cu_sym_id,
30061da546Spatrick lldb::LanguageType language,
31061da546Spatrick lldb_private::LazyBool is_optimized)
32061da546Spatrick : ModuleChild(module_sp), UserID(cu_sym_id), m_user_data(user_data),
33061da546Spatrick m_language(language), m_flags(0), m_file_spec(fspec),
34061da546Spatrick m_is_optimized(is_optimized) {
35061da546Spatrick if (language != eLanguageTypeUnknown)
36061da546Spatrick m_flags.Set(flagsParsedLanguage);
37061da546Spatrick assert(module_sp);
38061da546Spatrick }
39061da546Spatrick
CalculateSymbolContext(SymbolContext * sc)40061da546Spatrick void CompileUnit::CalculateSymbolContext(SymbolContext *sc) {
41061da546Spatrick sc->comp_unit = this;
42061da546Spatrick GetModule()->CalculateSymbolContext(sc);
43061da546Spatrick }
44061da546Spatrick
CalculateSymbolContextModule()45061da546Spatrick ModuleSP CompileUnit::CalculateSymbolContextModule() { return GetModule(); }
46061da546Spatrick
CalculateSymbolContextCompileUnit()47061da546Spatrick CompileUnit *CompileUnit::CalculateSymbolContextCompileUnit() { return this; }
48061da546Spatrick
DumpSymbolContext(Stream * s)49061da546Spatrick void CompileUnit::DumpSymbolContext(Stream *s) {
50061da546Spatrick GetModule()->DumpSymbolContext(s);
51061da546Spatrick s->Printf(", CompileUnit{0x%8.8" PRIx64 "}", GetID());
52061da546Spatrick }
53061da546Spatrick
GetDescription(Stream * s,lldb::DescriptionLevel level) const54061da546Spatrick void CompileUnit::GetDescription(Stream *s,
55061da546Spatrick lldb::DescriptionLevel level) const {
56*f6aab3d8Srobert const char *language = GetCachedLanguage();
57061da546Spatrick *s << "id = " << (const UserID &)*this << ", file = \""
58061da546Spatrick << this->GetPrimaryFile() << "\", language = \"" << language << '"';
59061da546Spatrick }
60061da546Spatrick
ForeachFunction(llvm::function_ref<bool (const FunctionSP &)> lambda) const61061da546Spatrick void CompileUnit::ForeachFunction(
62061da546Spatrick llvm::function_ref<bool(const FunctionSP &)> lambda) const {
63061da546Spatrick std::vector<lldb::FunctionSP> sorted_functions;
64061da546Spatrick sorted_functions.reserve(m_functions_by_uid.size());
65061da546Spatrick for (auto &p : m_functions_by_uid)
66061da546Spatrick sorted_functions.push_back(p.second);
67*f6aab3d8Srobert llvm::sort(sorted_functions,
68061da546Spatrick [](const lldb::FunctionSP &a, const lldb::FunctionSP &b) {
69061da546Spatrick return a->GetID() < b->GetID();
70061da546Spatrick });
71061da546Spatrick
72061da546Spatrick for (auto &f : sorted_functions)
73061da546Spatrick if (lambda(f))
74061da546Spatrick return;
75061da546Spatrick }
76061da546Spatrick
FindFunction(llvm::function_ref<bool (const FunctionSP &)> matching_lambda)77061da546Spatrick lldb::FunctionSP CompileUnit::FindFunction(
78061da546Spatrick llvm::function_ref<bool(const FunctionSP &)> matching_lambda) {
79be691f3bSpatrick LLDB_SCOPED_TIMER();
80061da546Spatrick
81061da546Spatrick lldb::ModuleSP module = CalculateSymbolContextModule();
82061da546Spatrick
83061da546Spatrick if (!module)
84061da546Spatrick return {};
85061da546Spatrick
86061da546Spatrick SymbolFile *symbol_file = module->GetSymbolFile();
87061da546Spatrick
88061da546Spatrick if (!symbol_file)
89061da546Spatrick return {};
90061da546Spatrick
91061da546Spatrick // m_functions_by_uid is filled in lazily but we need all the entries.
92061da546Spatrick symbol_file->ParseFunctions(*this);
93061da546Spatrick
94061da546Spatrick for (auto &p : m_functions_by_uid) {
95061da546Spatrick if (matching_lambda(p.second))
96061da546Spatrick return p.second;
97061da546Spatrick }
98061da546Spatrick return {};
99061da546Spatrick }
100061da546Spatrick
GetCachedLanguage() const101*f6aab3d8Srobert const char *CompileUnit::GetCachedLanguage() const {
102*f6aab3d8Srobert if (m_flags.IsClear(flagsParsedLanguage))
103*f6aab3d8Srobert return "<not loaded>";
104*f6aab3d8Srobert return Language::GetNameForLanguageType(m_language);
105*f6aab3d8Srobert }
106*f6aab3d8Srobert
107061da546Spatrick // Dump the current contents of this object. No functions that cause on demand
108061da546Spatrick // parsing of functions, globals, statics are called, so this is a good
109061da546Spatrick // function to call to get an idea of the current contents of the CompileUnit
110061da546Spatrick // object.
Dump(Stream * s,bool show_context) const111061da546Spatrick void CompileUnit::Dump(Stream *s, bool show_context) const {
112*f6aab3d8Srobert const char *language = GetCachedLanguage();
113061da546Spatrick
114061da546Spatrick s->Printf("%p: ", static_cast<const void *>(this));
115061da546Spatrick s->Indent();
116061da546Spatrick *s << "CompileUnit" << static_cast<const UserID &>(*this) << ", language = \""
117061da546Spatrick << language << "\", file = '" << GetPrimaryFile() << "'\n";
118061da546Spatrick
119061da546Spatrick // m_types.Dump(s);
120061da546Spatrick
121061da546Spatrick if (m_variables.get()) {
122061da546Spatrick s->IndentMore();
123061da546Spatrick m_variables->Dump(s, show_context);
124061da546Spatrick s->IndentLess();
125061da546Spatrick }
126061da546Spatrick
127061da546Spatrick if (!m_functions_by_uid.empty()) {
128061da546Spatrick s->IndentMore();
129061da546Spatrick ForeachFunction([&s, show_context](const FunctionSP &f) {
130061da546Spatrick f->Dump(s, show_context);
131061da546Spatrick return false;
132061da546Spatrick });
133061da546Spatrick
134061da546Spatrick s->IndentLess();
135061da546Spatrick s->EOL();
136061da546Spatrick }
137061da546Spatrick }
138061da546Spatrick
139061da546Spatrick // Add a function to this compile unit
AddFunction(FunctionSP & funcSP)140061da546Spatrick void CompileUnit::AddFunction(FunctionSP &funcSP) {
141061da546Spatrick m_functions_by_uid[funcSP->GetID()] = funcSP;
142061da546Spatrick }
143061da546Spatrick
FindFunctionByUID(lldb::user_id_t func_uid)144061da546Spatrick FunctionSP CompileUnit::FindFunctionByUID(lldb::user_id_t func_uid) {
145061da546Spatrick auto it = m_functions_by_uid.find(func_uid);
146061da546Spatrick if (it == m_functions_by_uid.end())
147061da546Spatrick return FunctionSP();
148061da546Spatrick return it->second;
149061da546Spatrick }
150061da546Spatrick
GetLanguage()151061da546Spatrick lldb::LanguageType CompileUnit::GetLanguage() {
152061da546Spatrick if (m_language == eLanguageTypeUnknown) {
153061da546Spatrick if (m_flags.IsClear(flagsParsedLanguage)) {
154061da546Spatrick m_flags.Set(flagsParsedLanguage);
155061da546Spatrick if (SymbolFile *symfile = GetModule()->GetSymbolFile())
156061da546Spatrick m_language = symfile->ParseLanguage(*this);
157061da546Spatrick }
158061da546Spatrick }
159061da546Spatrick return m_language;
160061da546Spatrick }
161061da546Spatrick
GetLineTable()162061da546Spatrick LineTable *CompileUnit::GetLineTable() {
163061da546Spatrick if (m_line_table_up == nullptr) {
164061da546Spatrick if (m_flags.IsClear(flagsParsedLineTable)) {
165061da546Spatrick m_flags.Set(flagsParsedLineTable);
166061da546Spatrick if (SymbolFile *symfile = GetModule()->GetSymbolFile())
167061da546Spatrick symfile->ParseLineTable(*this);
168061da546Spatrick }
169061da546Spatrick }
170061da546Spatrick return m_line_table_up.get();
171061da546Spatrick }
172061da546Spatrick
SetLineTable(LineTable * line_table)173061da546Spatrick void CompileUnit::SetLineTable(LineTable *line_table) {
174061da546Spatrick if (line_table == nullptr)
175061da546Spatrick m_flags.Clear(flagsParsedLineTable);
176061da546Spatrick else
177061da546Spatrick m_flags.Set(flagsParsedLineTable);
178061da546Spatrick m_line_table_up.reset(line_table);
179061da546Spatrick }
180061da546Spatrick
SetSupportFiles(const FileSpecList & support_files)181061da546Spatrick void CompileUnit::SetSupportFiles(const FileSpecList &support_files) {
182061da546Spatrick m_support_files = support_files;
183061da546Spatrick }
184061da546Spatrick
SetSupportFiles(FileSpecList && support_files)185*f6aab3d8Srobert void CompileUnit::SetSupportFiles(FileSpecList &&support_files) {
186*f6aab3d8Srobert m_support_files = std::move(support_files);
187*f6aab3d8Srobert }
188*f6aab3d8Srobert
GetDebugMacros()189061da546Spatrick DebugMacros *CompileUnit::GetDebugMacros() {
190061da546Spatrick if (m_debug_macros_sp.get() == nullptr) {
191061da546Spatrick if (m_flags.IsClear(flagsParsedDebugMacros)) {
192061da546Spatrick m_flags.Set(flagsParsedDebugMacros);
193061da546Spatrick if (SymbolFile *symfile = GetModule()->GetSymbolFile())
194061da546Spatrick symfile->ParseDebugMacros(*this);
195061da546Spatrick }
196061da546Spatrick }
197061da546Spatrick
198061da546Spatrick return m_debug_macros_sp.get();
199061da546Spatrick }
200061da546Spatrick
SetDebugMacros(const DebugMacrosSP & debug_macros_sp)201061da546Spatrick void CompileUnit::SetDebugMacros(const DebugMacrosSP &debug_macros_sp) {
202061da546Spatrick if (debug_macros_sp.get() == nullptr)
203061da546Spatrick m_flags.Clear(flagsParsedDebugMacros);
204061da546Spatrick else
205061da546Spatrick m_flags.Set(flagsParsedDebugMacros);
206061da546Spatrick m_debug_macros_sp = debug_macros_sp;
207061da546Spatrick }
208061da546Spatrick
GetVariableList(bool can_create)209061da546Spatrick VariableListSP CompileUnit::GetVariableList(bool can_create) {
210061da546Spatrick if (m_variables.get() == nullptr && can_create) {
211061da546Spatrick SymbolContext sc;
212061da546Spatrick CalculateSymbolContext(&sc);
213061da546Spatrick assert(sc.module_sp);
214061da546Spatrick sc.module_sp->GetSymbolFile()->ParseVariablesForContext(sc);
215061da546Spatrick }
216061da546Spatrick
217061da546Spatrick return m_variables;
218061da546Spatrick }
219061da546Spatrick
FindFileIndexes(const FileSpecList & files,const FileSpec & file)220*f6aab3d8Srobert std::vector<uint32_t> FindFileIndexes(const FileSpecList &files,
221*f6aab3d8Srobert const FileSpec &file) {
222061da546Spatrick std::vector<uint32_t> result;
223061da546Spatrick uint32_t idx = -1;
224*f6aab3d8Srobert while ((idx = files.FindCompatibleIndex(idx + 1, file)) !=
225061da546Spatrick UINT32_MAX)
226061da546Spatrick result.push_back(idx);
227061da546Spatrick return result;
228061da546Spatrick }
229061da546Spatrick
FindLineEntry(uint32_t start_idx,uint32_t line,const FileSpec * file_spec_ptr,bool exact,LineEntry * line_entry_ptr)230061da546Spatrick uint32_t CompileUnit::FindLineEntry(uint32_t start_idx, uint32_t line,
231061da546Spatrick const FileSpec *file_spec_ptr, bool exact,
232061da546Spatrick LineEntry *line_entry_ptr) {
233061da546Spatrick if (!file_spec_ptr)
234061da546Spatrick file_spec_ptr = &GetPrimaryFile();
235*f6aab3d8Srobert std::vector<uint32_t> file_indexes = FindFileIndexes(GetSupportFiles(),
236*f6aab3d8Srobert *file_spec_ptr);
237061da546Spatrick if (file_indexes.empty())
238061da546Spatrick return UINT32_MAX;
239061da546Spatrick
240be691f3bSpatrick // TODO: Handle SourceLocationSpec column information
241*f6aab3d8Srobert SourceLocationSpec location_spec(*file_spec_ptr, line,
242*f6aab3d8Srobert /*column=*/std::nullopt,
243be691f3bSpatrick /*check_inlines=*/false, exact);
244be691f3bSpatrick
245061da546Spatrick LineTable *line_table = GetLineTable();
246061da546Spatrick if (line_table)
247061da546Spatrick return line_table->FindLineEntryIndexByFileIndex(
248be691f3bSpatrick start_idx, file_indexes, location_spec, line_entry_ptr);
249061da546Spatrick return UINT32_MAX;
250061da546Spatrick }
251061da546Spatrick
ResolveSymbolContext(const SourceLocationSpec & src_location_spec,SymbolContextItem resolve_scope,SymbolContextList & sc_list)252be691f3bSpatrick void CompileUnit::ResolveSymbolContext(
253be691f3bSpatrick const SourceLocationSpec &src_location_spec,
254be691f3bSpatrick SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
255be691f3bSpatrick const FileSpec file_spec = src_location_spec.GetFileSpec();
256*f6aab3d8Srobert const uint32_t line = src_location_spec.GetLine().value_or(0);
257be691f3bSpatrick const bool check_inlines = src_location_spec.GetCheckInlines();
258be691f3bSpatrick
259061da546Spatrick // First find all of the file indexes that match our "file_spec". If
260061da546Spatrick // "file_spec" has an empty directory, then only compare the basenames when
261061da546Spatrick // finding file indexes
262061da546Spatrick bool file_spec_matches_cu_file_spec =
263061da546Spatrick FileSpec::Match(file_spec, this->GetPrimaryFile());
264061da546Spatrick
265061da546Spatrick // If we are not looking for inlined functions and our file spec doesn't
266061da546Spatrick // match then we are done...
267061da546Spatrick if (!file_spec_matches_cu_file_spec && !check_inlines)
268061da546Spatrick return;
269061da546Spatrick
270061da546Spatrick SymbolContext sc(GetModule());
271061da546Spatrick sc.comp_unit = this;
272061da546Spatrick
273061da546Spatrick if (line == 0) {
274061da546Spatrick if (file_spec_matches_cu_file_spec && !check_inlines) {
275061da546Spatrick // only append the context if we aren't looking for inline call sites by
276061da546Spatrick // file and line and if the file spec matches that of the compile unit
277061da546Spatrick sc_list.Append(sc);
278061da546Spatrick }
279061da546Spatrick return;
280061da546Spatrick }
281061da546Spatrick
282*f6aab3d8Srobert std::vector<uint32_t> file_indexes = FindFileIndexes(GetSupportFiles(),
283*f6aab3d8Srobert file_spec);
284be691f3bSpatrick const size_t num_file_indexes = file_indexes.size();
285be691f3bSpatrick if (num_file_indexes == 0)
286be691f3bSpatrick return;
287be691f3bSpatrick
288*f6aab3d8Srobert // Found a matching source file in this compile unit load its debug info.
289*f6aab3d8Srobert GetModule()->GetSymbolFile()->SetLoadDebugInfoEnabled();
290*f6aab3d8Srobert
291061da546Spatrick LineTable *line_table = sc.comp_unit->GetLineTable();
292061da546Spatrick
293be691f3bSpatrick if (line_table == nullptr) {
294be691f3bSpatrick if (file_spec_matches_cu_file_spec && !check_inlines) {
295be691f3bSpatrick sc_list.Append(sc);
296be691f3bSpatrick }
297061da546Spatrick return;
298be691f3bSpatrick }
299061da546Spatrick
300061da546Spatrick uint32_t line_idx;
301061da546Spatrick LineEntry line_entry;
302061da546Spatrick
303061da546Spatrick if (num_file_indexes == 1) {
304061da546Spatrick // We only have a single support file that matches, so use the line
305061da546Spatrick // table function that searches for a line entries that match a single
306061da546Spatrick // support file index
307061da546Spatrick line_idx = line_table->FindLineEntryIndexByFileIndex(
308be691f3bSpatrick 0, file_indexes.front(), src_location_spec, &line_entry);
309061da546Spatrick } else {
310061da546Spatrick // We found multiple support files that match "file_spec" so use the
311061da546Spatrick // line table function that searches for a line entries that match a
312061da546Spatrick // multiple support file indexes.
313be691f3bSpatrick line_idx = line_table->FindLineEntryIndexByFileIndex(
314be691f3bSpatrick 0, file_indexes, src_location_spec, &line_entry);
315061da546Spatrick }
316061da546Spatrick
317061da546Spatrick // If "exact == true", then "found_line" will be the same as "line". If
318061da546Spatrick // "exact == false", the "found_line" will be the closest line entry
319061da546Spatrick // with a line number greater than "line" and we will use this for our
320061da546Spatrick // subsequent line exact matches below.
321be691f3bSpatrick const bool inlines = false;
322be691f3bSpatrick const bool exact = true;
323*f6aab3d8Srobert const std::optional<uint16_t> column =
324*f6aab3d8Srobert src_location_spec.GetColumn() ? std::optional<uint16_t>(line_entry.column)
325*f6aab3d8Srobert : std::nullopt;
326*f6aab3d8Srobert
327*f6aab3d8Srobert SourceLocationSpec found_entry(line_entry.file, line_entry.line, column,
328*f6aab3d8Srobert inlines, exact);
329061da546Spatrick
330061da546Spatrick while (line_idx != UINT32_MAX) {
331061da546Spatrick // If they only asked for the line entry, then we're done, we can
332061da546Spatrick // just copy that over. But if they wanted more than just the line
333061da546Spatrick // number, fill it in.
334*f6aab3d8Srobert SymbolContext resolved_sc;
335061da546Spatrick sc.line_entry = line_entry;
336*f6aab3d8Srobert if (resolve_scope == eSymbolContextLineEntry) {
337*f6aab3d8Srobert sc_list.Append(sc);
338061da546Spatrick } else {
339*f6aab3d8Srobert line_entry.range.GetBaseAddress().CalculateSymbolContext(&resolved_sc,
340061da546Spatrick resolve_scope);
341*f6aab3d8Srobert // Sometimes debug info is bad and isn't able to resolve the line entry's
342*f6aab3d8Srobert // address back to the same compile unit and/or line entry. If the compile
343*f6aab3d8Srobert // unit changed, then revert back to just the compile unit and line entry.
344*f6aab3d8Srobert // Prior to this fix, the above code might end up not being able to lookup
345*f6aab3d8Srobert // the address, and then it would clear compile unit and the line entry in
346*f6aab3d8Srobert // the symbol context and the breakpoint would fail to get set even though
347*f6aab3d8Srobert // we have a valid line table entry in this compile unit. The address
348*f6aab3d8Srobert // lookup can also end up finding another function in another compiler
349*f6aab3d8Srobert // unit if the DWARF has overlappging address ranges. So if we end up with
350*f6aab3d8Srobert // no compile unit or a different one after the above function call,
351*f6aab3d8Srobert // revert back to the same results as if resolve_scope was set exactly to
352*f6aab3d8Srobert // eSymbolContextLineEntry.
353*f6aab3d8Srobert if (resolved_sc.comp_unit == this) {
354*f6aab3d8Srobert sc_list.Append(resolved_sc);
355*f6aab3d8Srobert } else {
356*f6aab3d8Srobert if (resolved_sc.comp_unit == nullptr && resolved_sc.module_sp) {
357*f6aab3d8Srobert // Only report an error if we don't map back to any compile unit. With
358*f6aab3d8Srobert // link time optimizations, the debug info might have many compile
359*f6aab3d8Srobert // units that have the same address range due to function outlining
360*f6aab3d8Srobert // or other link time optimizations. If the compile unit is NULL, then
361*f6aab3d8Srobert // address resolving is completely failing and more deserving of an
362*f6aab3d8Srobert // error message the user can see.
363*f6aab3d8Srobert resolved_sc.module_sp->ReportError(
364*f6aab3d8Srobert "unable to resolve a line table file address {0:x16} back "
365*f6aab3d8Srobert "to a compile unit, please file a bug and attach the address "
366*f6aab3d8Srobert "and file.",
367*f6aab3d8Srobert line_entry.range.GetBaseAddress().GetFileAddress());
368*f6aab3d8Srobert }
369*f6aab3d8Srobert sc_list.Append(sc);
370*f6aab3d8Srobert }
371061da546Spatrick }
372061da546Spatrick
373061da546Spatrick if (num_file_indexes == 1)
374061da546Spatrick line_idx = line_table->FindLineEntryIndexByFileIndex(
375be691f3bSpatrick line_idx + 1, file_indexes.front(), found_entry, &line_entry);
376061da546Spatrick else
377061da546Spatrick line_idx = line_table->FindLineEntryIndexByFileIndex(
378be691f3bSpatrick line_idx + 1, file_indexes, found_entry, &line_entry);
379061da546Spatrick }
380061da546Spatrick }
381061da546Spatrick
GetIsOptimized()382061da546Spatrick bool CompileUnit::GetIsOptimized() {
383061da546Spatrick if (m_is_optimized == eLazyBoolCalculate) {
384061da546Spatrick m_is_optimized = eLazyBoolNo;
385061da546Spatrick if (SymbolFile *symfile = GetModule()->GetSymbolFile()) {
386061da546Spatrick if (symfile->ParseIsOptimized(*this))
387061da546Spatrick m_is_optimized = eLazyBoolYes;
388061da546Spatrick }
389061da546Spatrick }
390061da546Spatrick return m_is_optimized;
391061da546Spatrick }
392061da546Spatrick
SetVariableList(VariableListSP & variables)393061da546Spatrick void CompileUnit::SetVariableList(VariableListSP &variables) {
394061da546Spatrick m_variables = variables;
395061da546Spatrick }
396061da546Spatrick
GetImportedModules()397061da546Spatrick const std::vector<SourceModule> &CompileUnit::GetImportedModules() {
398061da546Spatrick if (m_imported_modules.empty() &&
399061da546Spatrick m_flags.IsClear(flagsParsedImportedModules)) {
400061da546Spatrick m_flags.Set(flagsParsedImportedModules);
401061da546Spatrick if (SymbolFile *symfile = GetModule()->GetSymbolFile()) {
402061da546Spatrick SymbolContext sc;
403061da546Spatrick CalculateSymbolContext(&sc);
404061da546Spatrick symfile->ParseImportedModules(sc, m_imported_modules);
405061da546Spatrick }
406061da546Spatrick }
407061da546Spatrick return m_imported_modules;
408061da546Spatrick }
409061da546Spatrick
ForEachExternalModule(llvm::DenseSet<SymbolFile * > & visited_symbol_files,llvm::function_ref<bool (Module &)> lambda)410061da546Spatrick bool CompileUnit::ForEachExternalModule(
411061da546Spatrick llvm::DenseSet<SymbolFile *> &visited_symbol_files,
412061da546Spatrick llvm::function_ref<bool(Module &)> lambda) {
413061da546Spatrick if (SymbolFile *symfile = GetModule()->GetSymbolFile())
414061da546Spatrick return symfile->ForEachExternalModule(*this, visited_symbol_files, lambda);
415061da546Spatrick return false;
416061da546Spatrick }
417061da546Spatrick
GetSupportFiles()418061da546Spatrick const FileSpecList &CompileUnit::GetSupportFiles() {
419061da546Spatrick if (m_support_files.GetSize() == 0) {
420061da546Spatrick if (m_flags.IsClear(flagsParsedSupportFiles)) {
421061da546Spatrick m_flags.Set(flagsParsedSupportFiles);
422061da546Spatrick if (SymbolFile *symfile = GetModule()->GetSymbolFile())
423061da546Spatrick symfile->ParseSupportFiles(*this, m_support_files);
424061da546Spatrick }
425061da546Spatrick }
426061da546Spatrick return m_support_files;
427061da546Spatrick }
428061da546Spatrick
GetUserData() const429061da546Spatrick void *CompileUnit::GetUserData() const { return m_user_data; }
430