<div dir="ltr">Hi Enrico,<div><br></div><div>Could you add some tests for this?  python API tests and appropriate methods added to SBTarget would be ideal.</div></div><br><div class="gmail_quote"><div dir="ltr">On Thu, Oct 1, 2015 at 11:17 AM Enrico Granata via lldb-commits <<a href="mailto:lldb-commits@lists.llvm.org">lldb-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: enrico<br>
Date: Thu Oct  1 13:16:18 2015<br>
New Revision: 249047<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=249047&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=249047&view=rev</a><br>
Log:<br>
Add a 'type lookup' command. This command is meant to look up type information by name in a language-specific way.<br>
<br>
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<br>
<br>
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<br>
<br>
<br>
Modified:<br>
    lldb/trunk/include/lldb/Target/Language.h<br>
    lldb/trunk/source/Commands/CommandObjectType.cpp<br>
    lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.cpp<br>
    lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.h<br>
    lldb/trunk/source/Target/Language.cpp<br>
<br>
Modified: lldb/trunk/include/lldb/Target/Language.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Language.h?rev=249047&r1=249046&r2=249047&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Language.h?rev=249047&r1=249046&r2=249047&view=diff</a><br>
==============================================================================<br>
--- lldb/trunk/include/lldb/Target/Language.h (original)<br>
+++ lldb/trunk/include/lldb/Target/Language.h Thu Oct  1 13:16:18 2015<br>
@@ -13,6 +13,8 @@<br>
 // C Includes<br>
 // C++ Includes<br>
 #include <functional><br>
+#include <memory><br>
+#include <set><br>
 #include <vector><br>
<br>
 // Other libraries and framework includes<br>
@@ -29,6 +31,42 @@ class Language :<br>
 public PluginInterface<br>
 {<br>
 public:<br>
+<br>
+    class TypeScavenger<br>
+    {<br>
+    public:<br>
+        class Result<br>
+        {<br>
+        public:<br>
+            virtual bool<br>
+            IsValid () = 0;<br>
+<br>
+            virtual bool<br>
+            DumpToStream (Stream& stream,<br>
+                          bool print_help_if_available) = 0;<br>
+<br>
+            virtual ~Result() = default;<br>
+        };<br>
+<br>
+        typedef std::set<std::unique_ptr<Result>> ResultSet;<br>
+<br>
+        virtual ~TypeScavenger () = default;<br>
+<br>
+        size_t<br>
+        Find (ExecutionContextScope *exe_scope,<br>
+              const char *key,<br>
+              ResultSet &results,<br>
+              bool append = true);<br>
+<br>
+    protected:<br>
+        TypeScavenger () = default;<br>
+<br>
+        virtual bool<br>
+        Find_Impl (ExecutionContextScope *exe_scope,<br>
+                   const char *key,<br>
+                   ResultSet &results) = 0;<br>
+    };<br>
+<br>
     ~Language() override;<br>
<br>
     static Language*<br>
@@ -65,6 +103,9 @@ public:<br>
     virtual lldb_private::formatters::StringPrinter::EscapingHelper<br>
     GetStringPrinterEscapingHelper (lldb_private::formatters::StringPrinter::GetPrintableElementType);<br>
<br>
+    virtual std::unique_ptr<TypeScavenger><br>
+    GetTypeScavenger ();<br>
+<br>
     // These are accessors for general information about the Languages lldb knows about:<br>
<br>
     static lldb::LanguageType<br>
@@ -91,7 +132,6 @@ public:<br>
<br>
     static bool<br>
     LanguageIsPascal (lldb::LanguageType language);<br>
-<br>
<br>
 protected:<br>
     //------------------------------------------------------------------<br>
<br>
Modified: lldb/trunk/source/Commands/CommandObjectType.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectType.cpp?rev=249047&r1=249046&r2=249047&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectType.cpp?rev=249047&r1=249046&r2=249047&view=diff</a><br>
==============================================================================<br>
--- lldb/trunk/source/Commands/CommandObjectType.cpp (original)<br>
+++ lldb/trunk/source/Commands/CommandObjectType.cpp Thu Oct  1 13:16:18 2015<br>
@@ -4558,6 +4558,218 @@ CommandObjectTypeFilterAdd::CommandOptio<br>
     { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }<br>
 };<br>
<br>
+//----------------------------------------------------------------------<br>
+// "type lookup"<br>
+//----------------------------------------------------------------------<br>
+class CommandObjectTypeLookup : public CommandObjectRaw<br>
+{<br>
+protected:<br>
+<br>
+    class CommandOptions : public OptionGroup<br>
+    {<br>
+    public:<br>
+<br>
+        CommandOptions () :<br>
+        OptionGroup(),<br>
+        m_show_help(false),<br>
+        m_language(eLanguageTypeUnknown)<br>
+        {}<br>
+<br>
+        virtual<br>
+        ~CommandOptions () {}<br>
+<br>
+        virtual uint32_t<br>
+        GetNumDefinitions ()<br>
+        {<br>
+            return 3;<br>
+        }<br>
+<br>
+        virtual const OptionDefinition*<br>
+        GetDefinitions ()<br>
+        {<br>
+            return g_option_table;<br>
+        }<br>
+<br>
+        virtual Error<br>
+        SetOptionValue (CommandInterpreter &interpreter,<br>
+                        uint32_t option_idx,<br>
+                        const char *option_value)<br>
+        {<br>
+            Error error;<br>
+<br>
+            const int short_option = g_option_table[option_idx].short_option;<br>
+<br>
+            switch (short_option)<br>
+            {<br>
+                case 'h':<br>
+                    m_show_help = true;<br>
+                    break;<br>
+<br>
+                case 'l':<br>
+                    m_language = Language::GetLanguageTypeFromString(option_value);<br>
+                    break;<br>
+<br>
+                default:<br>
+                    error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);<br>
+                    break;<br>
+            }<br>
+<br>
+            return error;<br>
+        }<br>
+<br>
+        virtual void<br>
+        OptionParsingStarting (CommandInterpreter &interpreter)<br>
+        {<br>
+            m_show_help = false;<br>
+            m_language = eLanguageTypeUnknown;<br>
+        }<br>
+<br>
+        // Options table: Required for subclasses of Options.<br>
+<br>
+        static OptionDefinition g_option_table[];<br>
+        bool m_show_help;<br>
+        lldb::LanguageType m_language;<br>
+    };<br>
+<br>
+    OptionGroupOptions m_option_group;<br>
+    CommandOptions m_command_options;<br>
+<br>
+public:<br>
+<br>
+    CommandObjectTypeLookup (CommandInterpreter &interpreter) :<br>
+    CommandObjectRaw (interpreter,<br>
+                      "type lookup",<br>
+                      "Lookup a type by name in the select target.",<br>
+                      "type lookup <typename>",<br>
+                      eCommandRequiresTarget),<br>
+    m_option_group(interpreter),<br>
+    m_command_options()<br>
+    {<br>
+        m_option_group.Append(&m_command_options);<br>
+        m_option_group.Finalize();<br>
+    }<br>
+<br>
+    virtual<br>
+    ~CommandObjectTypeLookup ()<br>
+    {<br>
+    }<br>
+<br>
+    virtual<br>
+    Options *<br>
+    GetOptions ()<br>
+    {<br>
+        return &m_option_group;<br>
+    }<br>
+<br>
+    virtual bool<br>
+    DoExecute (const char *raw_command_line, CommandReturnObject &result)<br>
+    {<br>
+        if (!raw_command_line || !raw_command_line[0])<br>
+        {<br>
+            result.SetError("type lookup cannot be invoked without a type name as argument");<br>
+            return false;<br>
+        }<br>
+<br>
+        m_option_group.NotifyOptionParsingStarting();<br>
+<br>
+        const char * name_of_type = NULL;<br>
+<br>
+        if (raw_command_line[0] == '-')<br>
+        {<br>
+            // We have some options and these options MUST end with --.<br>
+            const char *end_options = NULL;<br>
+            const char *s = raw_command_line;<br>
+            while (s && s[0])<br>
+            {<br>
+                end_options = ::strstr (s, "--");<br>
+                if (end_options)<br>
+                {<br>
+                    end_options += 2; // Get past the "--"<br>
+                    if (::isspace (end_options[0]))<br>
+                    {<br>
+                        name_of_type = end_options;<br>
+                        while (::isspace (*name_of_type))<br>
+                            ++name_of_type;<br>
+                        break;<br>
+                    }<br>
+                }<br>
+                s = end_options;<br>
+            }<br>
+<br>
+            if (end_options)<br>
+            {<br>
+                Args args (llvm::StringRef(raw_command_line, end_options - raw_command_line));<br>
+                if (!ParseOptions (args, result))<br>
+                    return false;<br>
+<br>
+                Error error (m_option_group.NotifyOptionParsingFinished());<br>
+                if (error.Fail())<br>
+                {<br>
+                    result.AppendError (error.AsCString());<br>
+                    result.SetStatus (eReturnStatusFailed);<br>
+                    return false;<br>
+                }<br>
+            }<br>
+        }<br>
+        if (nullptr == name_of_type)<br>
+            name_of_type = raw_command_line;<br>
+<br>
+        TargetSP target_sp(GetCommandInterpreter().GetDebugger().GetSelectedTarget());<br>
+        const bool fill_all_in = true;<br>
+        ExecutionContext exe_ctx(target_sp.get(), fill_all_in);<br>
+        ExecutionContextScope *best_scope = exe_ctx.GetBestExecutionContextScope();<br>
+<br>
+        bool any_found = false;<br>
+<br>
+        std::vector<Language*> languages;<br>
+<br>
+        if (m_command_options.m_language == eLanguageTypeUnknown)<br>
+        {<br>
+            // FIXME: hardcoding languages is not good<br>
+            languages.push_back(Language::FindPlugin(eLanguageTypeObjC));<br>
+            languages.push_back(Language::FindPlugin(eLanguageTypeC_plus_plus));<br>
+        }<br>
+        else<br>
+        {<br>
+            languages.push_back(Language::FindPlugin(m_command_options.m_language));<br>
+        }<br>
+<br>
+        for (Language* language : languages)<br>
+        {<br>
+            if (!language)<br>
+                continue;<br>
+<br>
+            if (auto scavenger = language->GetTypeScavenger())<br>
+            {<br>
+                Language::TypeScavenger::ResultSet search_results;<br>
+                if (scavenger->Find(best_scope, name_of_type, search_results) > 0)<br>
+                {<br>
+                    for (const auto& search_result : search_results)<br>
+                    {<br>
+                        if (search_result && search_result->IsValid())<br>
+                        {<br>
+                            any_found = true;<br>
+                            search_result->DumpToStream(result.GetOutputStream(), this->m_command_options.m_show_help);<br>
+                        }<br>
+                    }<br>
+                }<br>
+            }<br>
+        }<br>
+<br>
+        result.SetStatus (any_found ? lldb::eReturnStatusSuccessFinishResult : lldb::eReturnStatusSuccessFinishNoResult);<br>
+        return true;<br>
+    }<br>
+<br>
+};<br>
+<br>
+OptionDefinition<br>
+CommandObjectTypeLookup::CommandOptions::g_option_table[] =<br>
+{<br>
+    { LLDB_OPT_SET_ALL, false, "show-help",        'h', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,    "Display available help for types"},<br>
+    { LLDB_OPT_SET_ALL, false, "language",         'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLanguage,    "Which language's types should the search scope be"},<br>
+    { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }<br>
+};<br>
+<br>
 template <typename FormatterType><br>
 class CommandObjectFormatterInfo : public CommandObjectRaw<br>
 {<br>
@@ -4778,6 +4990,7 @@ CommandObjectType::CommandObjectType (Co<br>
 #ifndef LLDB_DISABLE_PYTHON<br>
     LoadSubCommand ("synthetic", CommandObjectSP (new CommandObjectTypeSynth (interpreter)));<br>
 #endif<br>
+    LoadSubCommand ("lookup",   CommandObjectSP (new CommandObjectTypeLookup (interpreter)));<br>
 }<br>
<br>
<br>
<br>
Modified: lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.cpp?rev=249047&r1=249046&r2=249047&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.cpp?rev=249047&r1=249046&r2=249047&view=diff</a><br>
==============================================================================<br>
--- lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.cpp (original)<br>
+++ lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.cpp Thu Oct  1 13:16:18 2015<br>
@@ -656,3 +656,91 @@ ObjCLanguage::GetPossibleFormattersMatch<br>
<br>
     return result;<br>
 }<br>
+<br>
+std::unique_ptr<Language::TypeScavenger><br>
+ObjCLanguage::GetTypeScavenger ()<br>
+{<br>
+    class ObjCTypeScavenger : public Language::TypeScavenger<br>
+    {<br>
+    private:<br>
+        class ObjCScavengerResult : public Language::TypeScavenger::Result<br>
+        {<br>
+        public:<br>
+            ObjCScavengerResult (CompilerType type) :<br>
+                Language::TypeScavenger::Result(),<br>
+                m_compiler_type(type)<br>
+            {<br>
+            }<br>
+<br>
+            bool<br>
+            IsValid () override<br>
+            {<br>
+                return m_compiler_type.IsValid();<br>
+            }<br>
+<br>
+            bool<br>
+            DumpToStream (Stream& stream,<br>
+                          bool print_help_if_available) override<br>
+            {<br>
+                if (IsValid())<br>
+                {<br>
+                    m_compiler_type.DumpTypeDescription(&stream);<br>
+                    stream.EOL();<br>
+                    return true;<br>
+                }<br>
+                return false;<br>
+            }<br>
+<br>
+            virtual ~ObjCScavengerResult() = default;<br>
+        private:<br>
+            CompilerType m_compiler_type;<br>
+        };<br>
+<br>
+    protected:<br>
+        ObjCTypeScavenger() = default;<br>
+<br>
+        virtual ~ObjCTypeScavenger() = default;<br>
+<br>
+        bool<br>
+        Find_Impl (ExecutionContextScope *exe_scope,<br>
+                   const char *key,<br>
+                   ResultSet &results) override<br>
+        {<br>
+            bool result = false;<br>
+<br>
+            Process* process = exe_scope->CalculateProcess().get();<br>
+            if (process)<br>
+            {<br>
+                const bool create_on_demand = false;<br>
+                auto objc_runtime = process->GetObjCLanguageRuntime(create_on_demand);<br>
+                if (objc_runtime)<br>
+                {<br>
+                    auto decl_vendor = objc_runtime->GetDeclVendor();<br>
+                    if (decl_vendor)<br>
+                    {<br>
+                        std::vector<clang::NamedDecl *> decls;<br>
+                        ConstString name(key);<br>
+                        decl_vendor->FindDecls(name, true, UINT32_MAX, decls);<br>
+                        for (auto decl : decls)<br>
+                        {<br>
+                            if (decl)<br>
+                            {<br>
+                                if (CompilerType candidate = ClangASTContext::GetTypeForDecl(decl))<br>
+                                {<br>
+                                    result = true;<br>
+                                    std::unique_ptr<Language::TypeScavenger::Result> result(new ObjCScavengerResult(candidate));<br>
+                                    results.insert(std::move(result));<br>
+                                }<br>
+                            }<br>
+                        }<br>
+                    }<br>
+                }<br>
+            }<br>
+            return result;<br>
+        }<br>
+<br>
+        friend class ObjCLanguage;<br>
+    };<br>
+<br>
+    return std::unique_ptr<TypeScavenger>(new ObjCTypeScavenger());<br>
+}<br>
<br>
Modified: lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.h?rev=249047&r1=249046&r2=249047&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.h?rev=249047&r1=249046&r2=249047&view=diff</a><br>
==============================================================================<br>
--- lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.h (original)<br>
+++ lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.h Thu Oct  1 13:16:18 2015<br>
@@ -146,6 +146,9 @@ public:<br>
     std::vector<ConstString><br>
     GetPossibleFormattersMatches (ValueObject& valobj, lldb::DynamicValueType use_dynamic) override;<br>
<br>
+    std::unique_ptr<TypeScavenger><br>
+    GetTypeScavenger () override;<br>
+<br>
     //------------------------------------------------------------------<br>
     // Static Functions<br>
     //------------------------------------------------------------------<br>
<br>
Modified: lldb/trunk/source/Target/Language.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Language.cpp?rev=249047&r1=249046&r2=249047&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Language.cpp?rev=249047&r1=249046&r2=249047&view=diff</a><br>
==============================================================================<br>
--- lldb/trunk/source/Target/Language.cpp (original)<br>
+++ lldb/trunk/source/Target/Language.cpp Thu Oct  1 13:16:18 2015<br>
@@ -287,6 +287,34 @@ Language::LanguageIsPascal (LanguageType<br>
     }<br>
 }<br>
<br>
+std::unique_ptr<Language::TypeScavenger><br>
+Language::GetTypeScavenger ()<br>
+{<br>
+    return nullptr;<br>
+}<br>
+<br>
+size_t<br>
+Language::TypeScavenger::Find (ExecutionContextScope *exe_scope,<br>
+                               const char *key,<br>
+                               ResultSet &results,<br>
+                               bool append)<br>
+{<br>
+    if (!exe_scope || !exe_scope->CalculateTarget().get())<br>
+        return false;<br>
+<br>
+    if (!key || !key[0])<br>
+        return false;<br>
+<br>
+    if (!append)<br>
+        results.clear();<br>
+<br>
+    size_t old_size = results.size();<br>
+<br>
+    if (this->Find_Impl(exe_scope, key, results))<br>
+        return results.size() - old_size;<br>
+    return 0;<br>
+}<br>
+<br>
 //----------------------------------------------------------------------<br>
 // Constructor<br>
 //----------------------------------------------------------------------<br>
<br>
<br>
_______________________________________________<br>
lldb-commits mailing list<br>
<a href="mailto:lldb-commits@lists.llvm.org" target="_blank">lldb-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits</a><br>
</blockquote></div>