diff options
author | Enrico Granata <egranata@apple.com> | 2015-10-01 18:16:18 +0000 |
---|---|---|
committer | Enrico Granata <egranata@apple.com> | 2015-10-01 18:16:18 +0000 |
commit | 9b0af1b86f435fd490596af1b7812bd02565888a (patch) | |
tree | 5ad02c8a589de53388f900fd86db7fc849758c14 /lldb/source | |
parent | 12629324a4e97e9619848826c80314a88f9eae85 (diff) | |
download | bcm5719-llvm-9b0af1b86f435fd490596af1b7812bd02565888a.tar.gz bcm5719-llvm-9b0af1b86f435fd490596af1b7812bd02565888a.zip |
Add a 'type lookup' command. This command is meant to look up type information by name in a language-specific way.
Currently, it only supports Objective-C - C++ types can be looked up through debug info via 'image lookup -t', whereas ObjC types via this command are looked up by runtime introspection
This behavior is in line with type lookup's behavior in Xcode 7, but I am definitely open to feedback as to what makes the most sense here
llvm-svn: 249047
Diffstat (limited to 'lldb/source')
-rw-r--r-- | lldb/source/Commands/CommandObjectType.cpp | 213 | ||||
-rw-r--r-- | lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp | 88 | ||||
-rw-r--r-- | lldb/source/Plugins/Language/ObjC/ObjCLanguage.h | 3 | ||||
-rw-r--r-- | lldb/source/Target/Language.cpp | 28 |
4 files changed, 332 insertions, 0 deletions
diff --git a/lldb/source/Commands/CommandObjectType.cpp b/lldb/source/Commands/CommandObjectType.cpp index 842c323b62e..f0f4a14d4fc 100644 --- a/lldb/source/Commands/CommandObjectType.cpp +++ b/lldb/source/Commands/CommandObjectType.cpp @@ -4558,6 +4558,218 @@ CommandObjectTypeFilterAdd::CommandOptions::g_option_table[] = { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; +//---------------------------------------------------------------------- +// "type lookup" +//---------------------------------------------------------------------- +class CommandObjectTypeLookup : public CommandObjectRaw +{ +protected: + + class CommandOptions : public OptionGroup + { + public: + + CommandOptions () : + OptionGroup(), + m_show_help(false), + m_language(eLanguageTypeUnknown) + {} + + virtual + ~CommandOptions () {} + + virtual uint32_t + GetNumDefinitions () + { + return 3; + } + + virtual const OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + virtual Error + SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_value) + { + Error error; + + const int short_option = g_option_table[option_idx].short_option; + + switch (short_option) + { + case 'h': + m_show_help = true; + break; + + case 'l': + m_language = Language::GetLanguageTypeFromString(option_value); + break; + + default: + error.SetErrorStringWithFormat("invalid short option character '%c'", short_option); + break; + } + + return error; + } + + virtual void + OptionParsingStarting (CommandInterpreter &interpreter) + { + m_show_help = false; + m_language = eLanguageTypeUnknown; + } + + // Options table: Required for subclasses of Options. + + static OptionDefinition g_option_table[]; + bool m_show_help; + lldb::LanguageType m_language; + }; + + OptionGroupOptions m_option_group; + CommandOptions m_command_options; + +public: + + CommandObjectTypeLookup (CommandInterpreter &interpreter) : + CommandObjectRaw (interpreter, + "type lookup", + "Lookup a type by name in the select target.", + "type lookup <typename>", + eCommandRequiresTarget), + m_option_group(interpreter), + m_command_options() + { + m_option_group.Append(&m_command_options); + m_option_group.Finalize(); + } + + virtual + ~CommandObjectTypeLookup () + { + } + + virtual + Options * + GetOptions () + { + return &m_option_group; + } + + virtual bool + DoExecute (const char *raw_command_line, CommandReturnObject &result) + { + if (!raw_command_line || !raw_command_line[0]) + { + result.SetError("type lookup cannot be invoked without a type name as argument"); + return false; + } + + m_option_group.NotifyOptionParsingStarting(); + + const char * name_of_type = NULL; + + if (raw_command_line[0] == '-') + { + // We have some options and these options MUST end with --. + const char *end_options = NULL; + const char *s = raw_command_line; + while (s && s[0]) + { + end_options = ::strstr (s, "--"); + if (end_options) + { + end_options += 2; // Get past the "--" + if (::isspace (end_options[0])) + { + name_of_type = end_options; + while (::isspace (*name_of_type)) + ++name_of_type; + break; + } + } + s = end_options; + } + + if (end_options) + { + Args args (llvm::StringRef(raw_command_line, end_options - raw_command_line)); + if (!ParseOptions (args, result)) + return false; + + Error error (m_option_group.NotifyOptionParsingFinished()); + if (error.Fail()) + { + result.AppendError (error.AsCString()); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + } + if (nullptr == name_of_type) + name_of_type = raw_command_line; + + TargetSP target_sp(GetCommandInterpreter().GetDebugger().GetSelectedTarget()); + const bool fill_all_in = true; + ExecutionContext exe_ctx(target_sp.get(), fill_all_in); + ExecutionContextScope *best_scope = exe_ctx.GetBestExecutionContextScope(); + + bool any_found = false; + + std::vector<Language*> languages; + + if (m_command_options.m_language == eLanguageTypeUnknown) + { + // FIXME: hardcoding languages is not good + languages.push_back(Language::FindPlugin(eLanguageTypeObjC)); + languages.push_back(Language::FindPlugin(eLanguageTypeC_plus_plus)); + } + else + { + languages.push_back(Language::FindPlugin(m_command_options.m_language)); + } + + for (Language* language : languages) + { + if (!language) + continue; + + if (auto scavenger = language->GetTypeScavenger()) + { + Language::TypeScavenger::ResultSet search_results; + if (scavenger->Find(best_scope, name_of_type, search_results) > 0) + { + for (const auto& search_result : search_results) + { + if (search_result && search_result->IsValid()) + { + any_found = true; + search_result->DumpToStream(result.GetOutputStream(), this->m_command_options.m_show_help); + } + } + } + } + } + + result.SetStatus (any_found ? lldb::eReturnStatusSuccessFinishResult : lldb::eReturnStatusSuccessFinishNoResult); + return true; + } + +}; + +OptionDefinition +CommandObjectTypeLookup::CommandOptions::g_option_table[] = +{ + { LLDB_OPT_SET_ALL, false, "show-help", 'h', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display available help for types"}, + { LLDB_OPT_SET_ALL, false, "language", 'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLanguage, "Which language's types should the search scope be"}, + { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } +}; + template <typename FormatterType> class CommandObjectFormatterInfo : public CommandObjectRaw { @@ -4778,6 +4990,7 @@ CommandObjectType::CommandObjectType (CommandInterpreter &interpreter) : #ifndef LLDB_DISABLE_PYTHON LoadSubCommand ("synthetic", CommandObjectSP (new CommandObjectTypeSynth (interpreter))); #endif + LoadSubCommand ("lookup", CommandObjectSP (new CommandObjectTypeLookup (interpreter))); } diff --git a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp index c7e024c66c7..6c1aee9be6d 100644 --- a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp +++ b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp @@ -656,3 +656,91 @@ ObjCLanguage::GetPossibleFormattersMatches (ValueObject& valobj, lldb::DynamicVa return result; } + +std::unique_ptr<Language::TypeScavenger> +ObjCLanguage::GetTypeScavenger () +{ + class ObjCTypeScavenger : public Language::TypeScavenger + { + private: + class ObjCScavengerResult : public Language::TypeScavenger::Result + { + public: + ObjCScavengerResult (CompilerType type) : + Language::TypeScavenger::Result(), + m_compiler_type(type) + { + } + + bool + IsValid () override + { + return m_compiler_type.IsValid(); + } + + bool + DumpToStream (Stream& stream, + bool print_help_if_available) override + { + if (IsValid()) + { + m_compiler_type.DumpTypeDescription(&stream); + stream.EOL(); + return true; + } + return false; + } + + virtual ~ObjCScavengerResult() = default; + private: + CompilerType m_compiler_type; + }; + + protected: + ObjCTypeScavenger() = default; + + virtual ~ObjCTypeScavenger() = default; + + bool + Find_Impl (ExecutionContextScope *exe_scope, + const char *key, + ResultSet &results) override + { + bool result = false; + + Process* process = exe_scope->CalculateProcess().get(); + if (process) + { + const bool create_on_demand = false; + auto objc_runtime = process->GetObjCLanguageRuntime(create_on_demand); + if (objc_runtime) + { + auto decl_vendor = objc_runtime->GetDeclVendor(); + if (decl_vendor) + { + std::vector<clang::NamedDecl *> decls; + ConstString name(key); + decl_vendor->FindDecls(name, true, UINT32_MAX, decls); + for (auto decl : decls) + { + if (decl) + { + if (CompilerType candidate = ClangASTContext::GetTypeForDecl(decl)) + { + result = true; + std::unique_ptr<Language::TypeScavenger::Result> result(new ObjCScavengerResult(candidate)); + results.insert(std::move(result)); + } + } + } + } + } + } + return result; + } + + friend class ObjCLanguage; + }; + + return std::unique_ptr<TypeScavenger>(new ObjCTypeScavenger()); +} diff --git a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h index 0e3c45f0ff1..09ee55d274f 100644 --- a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h +++ b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h @@ -146,6 +146,9 @@ public: std::vector<ConstString> GetPossibleFormattersMatches (ValueObject& valobj, lldb::DynamicValueType use_dynamic) override; + std::unique_ptr<TypeScavenger> + GetTypeScavenger () override; + //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ diff --git a/lldb/source/Target/Language.cpp b/lldb/source/Target/Language.cpp index 02b36519b13..f7c2cf6249f 100644 --- a/lldb/source/Target/Language.cpp +++ b/lldb/source/Target/Language.cpp @@ -287,6 +287,34 @@ Language::LanguageIsPascal (LanguageType language) } } +std::unique_ptr<Language::TypeScavenger> +Language::GetTypeScavenger () +{ + return nullptr; +} + +size_t +Language::TypeScavenger::Find (ExecutionContextScope *exe_scope, + const char *key, + ResultSet &results, + bool append) +{ + if (!exe_scope || !exe_scope->CalculateTarget().get()) + return false; + + if (!key || !key[0]) + return false; + + if (!append) + results.clear(); + + size_t old_size = results.size(); + + if (this->Find_Impl(exe_scope, key, results)) + return results.size() - old_size; + return 0; +} + //---------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------- |