aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Symbol/CompileUnit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Symbol/CompileUnit.cpp')
-rw-r--r--contrib/llvm-project/lldb/source/Symbol/CompileUnit.cpp413
1 files changed, 413 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Symbol/CompileUnit.cpp b/contrib/llvm-project/lldb/source/Symbol/CompileUnit.cpp
new file mode 100644
index 000000000000..5fb9b6b9f729
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Symbol/CompileUnit.cpp
@@ -0,0 +1,413 @@
+//===-- CompileUnit.cpp -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/Language.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+CompileUnit::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)
+ : ModuleChild(module_sp), FileSpec(pathname), UserID(cu_sym_id),
+ m_user_data(user_data), m_language(language), m_flags(0),
+ m_support_files(), m_line_table_up(), m_variables(),
+ m_is_optimized(is_optimized) {
+ if (language != eLanguageTypeUnknown)
+ m_flags.Set(flagsParsedLanguage);
+ assert(module_sp);
+}
+
+CompileUnit::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)
+ : ModuleChild(module_sp), FileSpec(fspec), UserID(cu_sym_id),
+ m_user_data(user_data), m_language(language), m_flags(0),
+ m_support_files(), m_line_table_up(), m_variables(),
+ m_is_optimized(is_optimized) {
+ if (language != eLanguageTypeUnknown)
+ m_flags.Set(flagsParsedLanguage);
+ assert(module_sp);
+}
+
+CompileUnit::~CompileUnit() {}
+
+void CompileUnit::CalculateSymbolContext(SymbolContext *sc) {
+ sc->comp_unit = this;
+ GetModule()->CalculateSymbolContext(sc);
+}
+
+ModuleSP CompileUnit::CalculateSymbolContextModule() { return GetModule(); }
+
+CompileUnit *CompileUnit::CalculateSymbolContextCompileUnit() { return this; }
+
+void CompileUnit::DumpSymbolContext(Stream *s) {
+ GetModule()->DumpSymbolContext(s);
+ s->Printf(", CompileUnit{0x%8.8" PRIx64 "}", GetID());
+}
+
+void CompileUnit::GetDescription(Stream *s,
+ lldb::DescriptionLevel level) const {
+ const char *language = Language::GetNameForLanguageType(m_language);
+ *s << "id = " << (const UserID &)*this << ", file = \""
+ << (const FileSpec &)*this << "\", language = \"" << language << '"';
+}
+
+void CompileUnit::ForeachFunction(
+ llvm::function_ref<bool(const FunctionSP &)> lambda) const {
+ std::vector<lldb::FunctionSP> sorted_functions;
+ sorted_functions.reserve(m_functions_by_uid.size());
+ for (auto &p : m_functions_by_uid)
+ sorted_functions.push_back(p.second);
+ llvm::sort(sorted_functions.begin(), sorted_functions.end(),
+ [](const lldb::FunctionSP &a, const lldb::FunctionSP &b) {
+ return a->GetID() < b->GetID();
+ });
+
+ for (auto &f : sorted_functions)
+ if (lambda(f))
+ return;
+}
+
+// Dump the current contents of this object. No functions that cause on demand
+// parsing of functions, globals, statics are called, so this is a good
+// function to call to get an idea of the current contents of the CompileUnit
+// object.
+void CompileUnit::Dump(Stream *s, bool show_context) const {
+ const char *language = Language::GetNameForLanguageType(m_language);
+
+ s->Printf("%p: ", static_cast<const void *>(this));
+ s->Indent();
+ *s << "CompileUnit" << static_cast<const UserID &>(*this) << ", language = \""
+ << language << "\", file = '" << static_cast<const FileSpec &>(*this)
+ << "'\n";
+
+ // m_types.Dump(s);
+
+ if (m_variables.get()) {
+ s->IndentMore();
+ m_variables->Dump(s, show_context);
+ s->IndentLess();
+ }
+
+ if (!m_functions_by_uid.empty()) {
+ s->IndentMore();
+ ForeachFunction([&s, show_context](const FunctionSP &f) {
+ f->Dump(s, show_context);
+ return false;
+ });
+
+ s->IndentLess();
+ s->EOL();
+ }
+}
+
+// Add a function to this compile unit
+void CompileUnit::AddFunction(FunctionSP &funcSP) {
+ m_functions_by_uid[funcSP->GetID()] = funcSP;
+}
+
+// Find functions using the Mangled::Tokens token list. This function currently
+// implements an interactive approach designed to find all instances of certain
+// functions. It isn't designed to the quickest way to lookup functions as it
+// will need to iterate through all functions and see if they match, though it
+// does provide a powerful and context sensitive way to search for all
+// functions with a certain name, all functions in a namespace, or all
+// functions of a template type. See Mangled::Tokens::Parse() comments for more
+// information.
+//
+// The function prototype will need to change to return a list of results. It
+// was originally used to help debug the Mangled class and the
+// Mangled::Tokens::MatchesQuery() function and it currently will print out a
+// list of matching results for the functions that are currently in this
+// compile unit.
+//
+// A FindFunctions method should be called prior to this that takes
+// a regular function name (const char * or ConstString as a parameter) before
+// resorting to this slower but more complete function. The other FindFunctions
+// method should be able to take advantage of any accelerator tables available
+// in the debug information (which is parsed by the SymbolFile parser plug-ins
+// and registered with each Module).
+// void
+// CompileUnit::FindFunctions(const Mangled::Tokens& tokens)
+//{
+// if (!m_functions.empty())
+// {
+// Stream s(stdout);
+// std::vector<FunctionSP>::const_iterator pos;
+// std::vector<FunctionSP>::const_iterator end = m_functions.end();
+// for (pos = m_functions.begin(); pos != end; ++pos)
+// {
+// const ConstString& demangled = (*pos)->Mangled().Demangled();
+// if (demangled)
+// {
+// const Mangled::Tokens& func_tokens =
+// (*pos)->Mangled().GetTokens();
+// if (func_tokens.MatchesQuery (tokens))
+// s << "demangled MATCH found: " << demangled << "\n";
+// }
+// }
+// }
+//}
+
+FunctionSP CompileUnit::FindFunctionByUID(lldb::user_id_t func_uid) {
+ auto it = m_functions_by_uid.find(func_uid);
+ if (it == m_functions_by_uid.end())
+ return FunctionSP();
+ return it->second;
+}
+
+lldb::LanguageType CompileUnit::GetLanguage() {
+ if (m_language == eLanguageTypeUnknown) {
+ if (m_flags.IsClear(flagsParsedLanguage)) {
+ m_flags.Set(flagsParsedLanguage);
+ SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor();
+ if (symbol_vendor) {
+ m_language = symbol_vendor->ParseLanguage(*this);
+ }
+ }
+ }
+ return m_language;
+}
+
+LineTable *CompileUnit::GetLineTable() {
+ if (m_line_table_up == nullptr) {
+ if (m_flags.IsClear(flagsParsedLineTable)) {
+ m_flags.Set(flagsParsedLineTable);
+ SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor();
+ if (symbol_vendor)
+ symbol_vendor->ParseLineTable(*this);
+ }
+ }
+ return m_line_table_up.get();
+}
+
+void CompileUnit::SetLineTable(LineTable *line_table) {
+ if (line_table == nullptr)
+ m_flags.Clear(flagsParsedLineTable);
+ else
+ m_flags.Set(flagsParsedLineTable);
+ m_line_table_up.reset(line_table);
+}
+
+DebugMacros *CompileUnit::GetDebugMacros() {
+ if (m_debug_macros_sp.get() == nullptr) {
+ if (m_flags.IsClear(flagsParsedDebugMacros)) {
+ m_flags.Set(flagsParsedDebugMacros);
+ SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor();
+ if (symbol_vendor) {
+ symbol_vendor->ParseDebugMacros(*this);
+ }
+ }
+ }
+
+ return m_debug_macros_sp.get();
+}
+
+void CompileUnit::SetDebugMacros(const DebugMacrosSP &debug_macros_sp) {
+ if (debug_macros_sp.get() == nullptr)
+ m_flags.Clear(flagsParsedDebugMacros);
+ else
+ m_flags.Set(flagsParsedDebugMacros);
+ m_debug_macros_sp = debug_macros_sp;
+}
+
+VariableListSP CompileUnit::GetVariableList(bool can_create) {
+ if (m_variables.get() == nullptr && can_create) {
+ SymbolContext sc;
+ CalculateSymbolContext(&sc);
+ assert(sc.module_sp);
+ sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc);
+ }
+
+ return m_variables;
+}
+
+uint32_t CompileUnit::FindLineEntry(uint32_t start_idx, uint32_t line,
+ const FileSpec *file_spec_ptr, bool exact,
+ LineEntry *line_entry_ptr) {
+ uint32_t file_idx = 0;
+
+ if (file_spec_ptr) {
+ file_idx = GetSupportFiles().FindFileIndex(1, *file_spec_ptr, true);
+ if (file_idx == UINT32_MAX)
+ return UINT32_MAX;
+ } else {
+ // All the line table entries actually point to the version of the Compile
+ // Unit that is in the support files (the one at 0 was artificially added.)
+ // So prefer the one further on in the support files if it exists...
+ const FileSpecList &support_files = GetSupportFiles();
+ const bool full = true;
+ file_idx = support_files.FindFileIndex(
+ 1, support_files.GetFileSpecAtIndex(0), full);
+ if (file_idx == UINT32_MAX)
+ file_idx = 0;
+ }
+ LineTable *line_table = GetLineTable();
+ if (line_table)
+ return line_table->FindLineEntryIndexByFileIndex(start_idx, file_idx, line,
+ exact, line_entry_ptr);
+ return UINT32_MAX;
+}
+
+uint32_t CompileUnit::ResolveSymbolContext(const FileSpec &file_spec,
+ uint32_t line, bool check_inlines,
+ bool exact,
+ SymbolContextItem resolve_scope,
+ SymbolContextList &sc_list) {
+ // First find all of the file indexes that match our "file_spec". If
+ // "file_spec" has an empty directory, then only compare the basenames when
+ // finding file indexes
+ std::vector<uint32_t> file_indexes;
+ const bool full_match = (bool)file_spec.GetDirectory();
+ bool file_spec_matches_cu_file_spec =
+ FileSpec::Equal(file_spec, *this, full_match);
+
+ // If we are not looking for inlined functions and our file spec doesn't
+ // match then we are done...
+ if (!file_spec_matches_cu_file_spec && !check_inlines)
+ return 0;
+
+ uint32_t file_idx =
+ GetSupportFiles().FindFileIndex(1, file_spec, true);
+ while (file_idx != UINT32_MAX) {
+ file_indexes.push_back(file_idx);
+ file_idx = GetSupportFiles().FindFileIndex(file_idx + 1, file_spec, true);
+ }
+
+ const size_t num_file_indexes = file_indexes.size();
+ if (num_file_indexes == 0)
+ return 0;
+
+ const uint32_t prev_size = sc_list.GetSize();
+
+ SymbolContext sc(GetModule());
+ sc.comp_unit = this;
+
+ if (line != 0) {
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+
+ if (line_table != nullptr) {
+ uint32_t found_line;
+ uint32_t line_idx;
+
+ if (num_file_indexes == 1) {
+ // We only have a single support file that matches, so use the line
+ // table function that searches for a line entries that match a single
+ // support file index
+ LineEntry line_entry;
+ line_idx = line_table->FindLineEntryIndexByFileIndex(
+ 0, file_indexes.front(), line, exact, &line_entry);
+
+ // If "exact == true", then "found_line" will be the same as "line". If
+ // "exact == false", the "found_line" will be the closest line entry
+ // with a line number greater than "line" and we will use this for our
+ // subsequent line exact matches below.
+ found_line = line_entry.line;
+
+ while (line_idx != UINT32_MAX) {
+ // If they only asked for the line entry, then we're done, we can
+ // just copy that over. But if they wanted more than just the line
+ // number, fill it in.
+ if (resolve_scope == eSymbolContextLineEntry) {
+ sc.line_entry = line_entry;
+ } else {
+ line_entry.range.GetBaseAddress().CalculateSymbolContext(
+ &sc, resolve_scope);
+ }
+
+ sc_list.Append(sc);
+ line_idx = line_table->FindLineEntryIndexByFileIndex(
+ line_idx + 1, file_indexes.front(), found_line, true,
+ &line_entry);
+ }
+ } else {
+ // We found multiple support files that match "file_spec" so use the
+ // line table function that searches for a line entries that match a
+ // multiple support file indexes.
+ LineEntry line_entry;
+ line_idx = line_table->FindLineEntryIndexByFileIndex(
+ 0, file_indexes, line, exact, &line_entry);
+
+ // If "exact == true", then "found_line" will be the same as "line". If
+ // "exact == false", the "found_line" will be the closest line entry
+ // with a line number greater than "line" and we will use this for our
+ // subsequent line exact matches below.
+ found_line = line_entry.line;
+
+ while (line_idx != UINT32_MAX) {
+ if (resolve_scope == eSymbolContextLineEntry) {
+ sc.line_entry = line_entry;
+ } else {
+ line_entry.range.GetBaseAddress().CalculateSymbolContext(
+ &sc, resolve_scope);
+ }
+
+ sc_list.Append(sc);
+ line_idx = line_table->FindLineEntryIndexByFileIndex(
+ line_idx + 1, file_indexes, found_line, true, &line_entry);
+ }
+ }
+ }
+ } else if (file_spec_matches_cu_file_spec && !check_inlines) {
+ // only append the context if we aren't looking for inline call sites by
+ // file and line and if the file spec matches that of the compile unit
+ sc_list.Append(sc);
+ }
+ return sc_list.GetSize() - prev_size;
+}
+
+bool CompileUnit::GetIsOptimized() {
+ if (m_is_optimized == eLazyBoolCalculate) {
+ m_is_optimized = eLazyBoolNo;
+ if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) {
+ if (symbol_vendor->ParseIsOptimized(*this))
+ m_is_optimized = eLazyBoolYes;
+ }
+ }
+ return m_is_optimized;
+}
+
+void CompileUnit::SetVariableList(VariableListSP &variables) {
+ m_variables = variables;
+}
+
+const std::vector<SourceModule> &CompileUnit::GetImportedModules() {
+ if (m_imported_modules.empty() &&
+ m_flags.IsClear(flagsParsedImportedModules)) {
+ m_flags.Set(flagsParsedImportedModules);
+ if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) {
+ SymbolContext sc;
+ CalculateSymbolContext(&sc);
+ symbol_vendor->ParseImportedModules(sc, m_imported_modules);
+ }
+ }
+ return m_imported_modules;
+}
+
+const FileSpecList &CompileUnit::GetSupportFiles() {
+ if (m_support_files.GetSize() == 0) {
+ if (m_flags.IsClear(flagsParsedSupportFiles)) {
+ m_flags.Set(flagsParsedSupportFiles);
+ SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor();
+ if (symbol_vendor) {
+ symbol_vendor->ParseSupportFiles(*this, m_support_files);
+ }
+ }
+ }
+ return m_support_files;
+}
+
+void *CompileUnit::GetUserData() const { return m_user_data; }