[lldb-dev] [RFC} [Patch] SBFunction::ExecuteFunction

Carlo Kok ck at remobjects.com
Fri Oct 10 07:43:14 PDT 2014



jingham at apple.com schreef op 9/23/2014 om 7:28 PM:
> So one thing that you will have to work out here is that Symbols
aren't specific to Targets, but ClangFunctions are. The was lldb works,
if two targets load the same shared library, only one
lldb_private::Module is made, and added to the "global shared module
cache" and then both Targets use the Symbols, Functions, etc that come
from that module. So you can't put a ClangFunction into a Symbol
directly, or different Targets will fight over that resource. It has to
live in the Target somehow.

Yeah, what I did is a map<void*, std::shared_ptr<ClangFunction>> in 
Target with only accessors for the two types I accept here (they don't 
have a common ancestor and I didn't want to break that)


> Also, you shouldn't access ObjC specific info directly from the
Target, that functionality belongs in the ObjCLanguageRuntime plugin.
That way we can track changes in this if/when runtime behaviors change.
It already keeps a map <Class,Selector> -> Implementation so maybe you
can hook into that to do what you want. You can get the ObjC Language
Runtime from the process.
>

Also fixed in the attached patch.

The only issue I'm having now is the context issue, when I use say 
NSString from an objc function, the ClangFunction parser doesn't know 
about that type. I think the EvaluateExpression does something special 
for that but I cannot find where that's located, anyone know where to 
find that?

Thanks,

-- 
Carlo Kok
RemObjects Software
-------------- next part --------------
Index: include/lldb/API/SBExpressionOptions.h
===================================================================
--- include/lldb/API/SBExpressionOptions.h	(revision 219490)
+++ include/lldb/API/SBExpressionOptions.h	(working copy)
@@ -118,6 +118,8 @@
     friend class SBFrame;
     friend class SBValue;
     friend class SBTarget;
+    friend class SBTypeMemberFunction;
+    friend class SBFunction;
 
 private:
     // This auto_pointer is made in the constructor and is always valid.
Index: include/lldb/API/SBFrame.h
===================================================================
--- include/lldb/API/SBFrame.h	(revision 219490)
+++ include/lldb/API/SBFrame.h	(working copy)
@@ -210,6 +210,8 @@
     friend class SBInstruction;
     friend class SBThread;
     friend class SBValue;
+    friend class SBTypeMemberFunction;
+    friend class SBFunction;
 #ifndef LLDB_DISABLE_PYTHON
     friend class lldb_private::ScriptInterpreterPython;
 #endif
Index: include/lldb/API/SBFunction.h
===================================================================
--- include/lldb/API/SBFunction.h	(revision 219490)
+++ include/lldb/API/SBFunction.h	(working copy)
@@ -68,6 +68,13 @@
     bool
     GetDescription (lldb::SBStream &description);
 
+    lldb::SBValue ExecuteFunction(lldb::SBFrame &frame,
+                                  lldb::SBValueList arguments,
+                                  lldb::SBStream &errors,
+                                  lldb::SBExpressionOptions options,
+                                  bool reusable);
+
+    void RemoveReusableFunction (lldb::SBTarget &target);
 protected:
 
     lldb_private::Function *
Index: include/lldb/API/SBTarget.h
===================================================================
--- include/lldb/API/SBTarget.h	(revision 219490)
+++ include/lldb/API/SBTarget.h	(working copy)
@@ -942,6 +942,7 @@
     friend class SBSourceManager;
     friend class SBSymbol;
     friend class SBValue;
+    friend class SBTypeMemberFunction;
 
     //------------------------------------------------------------------
     // Constructors are private, use static Target::Create function to
Index: include/lldb/API/SBType.h
===================================================================
--- include/lldb/API/SBType.h	(revision 219490)
+++ include/lldb/API/SBType.h	(working copy)
@@ -104,7 +104,15 @@
     bool
     GetDescription (lldb::SBStream &description,
                     lldb::DescriptionLevel description_level);
-    
+
+    lldb::SBValue ExecuteFunction (lldb::SBFrame &frame,
+                                   lldb::SBValue self,
+                                   lldb::SBValueList arguments,
+                                   lldb::SBStream &errors,
+                                   lldb::SBExpressionOptions options,
+                                   bool reusable);
+
+    void RemoveReusableFunction(lldb::SBTarget& target);
 protected:
     friend class SBType;
     
Index: include/lldb/API/SBValueList.h
===================================================================
--- include/lldb/API/SBValueList.h	(revision 219490)
+++ include/lldb/API/SBValueList.h	(working copy)
@@ -59,6 +59,7 @@
 
 private:
     friend class SBFrame;
+    friend class SBTypeMemberFunction;
     
     SBValueList (const ValueListImpl *lldb_object_ptr);
 
Index: include/lldb/Expression/ClangFunction.h
===================================================================
--- include/lldb/Expression/ClangFunction.h	(revision 219490)
+++ include/lldb/Expression/ClangFunction.h	(working copy)
@@ -406,6 +406,12 @@
     {
         return m_arg_values;
     }
+
+    Address
+    GetFunctionAddress() const
+    {
+        return m_function_addr;
+    }
 private:
     //------------------------------------------------------------------
     // For ClangFunction only
Index: include/lldb/Target/ObjCLanguageRuntime.h
===================================================================
--- include/lldb/Target/ObjCLanguageRuntime.h	(revision 219490)
+++ include/lldb/Target/ObjCLanguageRuntime.h	(working copy)
@@ -510,6 +510,11 @@
     {
         m_negative_complete_class_cache.clear();
     }
+
+
+    lldb::addr_t
+    GetSelectorFor(const ConstString& value, ExecutionContextScope *exe_scope);
+
     
 protected:
     //------------------------------------------------------------------
@@ -607,11 +612,13 @@
     typedef std::multimap<uint32_t, ObjCISA> HashToISAMap;
     typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator;
     typedef HashToISAMap::iterator HashToISAIterator;
+    typedef std::map<ConstString, lldb::addr_t> SelectorMap;
 
     MsgImplMap m_impl_cache;
     LazyBool m_has_new_literals_and_indexing;
     ISAToDescriptorMap m_isa_to_descriptor;
     HashToISAMap m_hash_to_isa_map;
+    SelectorMap m_selector_map;
 
 protected:
     uint32_t m_isa_to_descriptor_stop_id;
Index: include/lldb/Target/Target.h
===================================================================
--- include/lldb/Target/Target.h	(revision 219490)
+++ include/lldb/Target/Target.h	(working copy)
@@ -1345,6 +1345,25 @@
     lldb::SearchFilterSP
     GetSearchFilterForModuleAndCUList (const FileSpecList *containingModules, const FileSpecList *containingSourceFiles);
 
+    std::shared_ptr<ClangFunction>& GetOrAddClangFunction (Function* func)
+    {
+        return m_clang_functions[func];
+    }
+
+    std::shared_ptr<ClangFunction>& GetOrAddClangFunction (TypeMemberFunctionImpl* func)
+    {
+        return m_clang_functions[func];
+    }
+
+    void RemoveClangFunction (Function* func)
+    {
+        m_clang_functions.erase (func);
+    }
+
+    void RemoveClangFunction (TypeMemberFunctionImpl* func)
+    {
+        m_clang_functions.erase (func);
+    }
 protected:
     //------------------------------------------------------------------
     // Member variables.
@@ -1378,6 +1397,9 @@
     lldb::user_id_t         m_stop_hook_next_id;
     bool                    m_valid;
     bool                    m_suppress_stop_hooks;
+    typedef std::map<void*, std::shared_ptr<ClangFunction>> ClangFunctionCollection;
+    ClangFunctionCollection m_clang_functions;
+
     
     static void
     ImageSearchPathsChanged (const PathMappingList &path_list,
Index: source/API/SBFunction.cpp
===================================================================
--- source/API/SBFunction.cpp	(revision 219490)
+++ source/API/SBFunction.cpp	(working copy)
@@ -18,6 +18,12 @@
 #include "lldb/Symbol/Type.h"
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/Target.h"
+#include "lldb/API/SBExpressionOptions.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/API/SBFrame.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Expression/ClangFunction.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -229,3 +235,81 @@
 
 
 
+lldb::SBValue SBFunction::ExecuteFunction(lldb::SBFrame &frame,
+    lldb::SBValueList arguments,
+    lldb::SBStream &errors,
+    lldb::SBExpressionOptions options,
+    bool reusable)
+{
+    if (!m_opaque_ptr)
+    {
+        errors->PutCString("no value");
+        return SBValue();
+    }
+
+    ExecutionContext exe_ctx = frame.GetFrameSP();
+
+    if (!exe_ctx.GetFrameSP())
+    {
+        errors->PutCString("no frame");
+        return SBValue();
+    }
+
+    ValueList args;
+    for (int i = 0; i < arguments.GetSize(); i++)
+    {
+        const ValueObjectSP value = arguments.GetValueAtIndex(i).GetSP();
+        value->UpdateValueIfNeeded();
+        args.PushValue(value->GetValue());
+    }
+    //arguments.
+    Thread& thread = *exe_ctx.GetThreadSP();
+
+
+    std::shared_ptr<ClangFunction>& func = exe_ctx.GetTargetPtr ()->GetOrAddClangFunction (m_opaque_ptr);
+
+    if (!func)
+    {
+        func.reset (new ClangFunction (thread,
+            m_opaque_ptr->GetClangType ().GetFunctionReturnType (),
+            m_opaque_ptr->GetAddressRange ().GetBaseAddress (),
+            args,
+            m_opaque_ptr->GetName ().GetCString ()));
+
+        if (func->CompileFunction (*errors.get ()))
+            return SBValue ();
+
+        if (!func->WriteFunctionWrapper (exe_ctx, *errors.get ()))
+            return SBValue ();
+    }
+    errors.Clear ();
+
+    lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;
+    if (!func->WriteFunctionArguments (exe_ctx, args_addr,
+        func->GetFunctionAddress (), args, *errors.get ()))
+    {
+        return SBValue ();
+    }
+
+    Value res;
+    if (func->ExecuteFunction (exe_ctx, &args_addr, *options.get (), *errors.get (), res))
+    {
+        func->DeallocateFunctionResults (exe_ctx, args_addr);
+        if (!reusable)
+            exe_ctx.GetTargetPtr ()->RemoveClangFunction (m_opaque_ptr);
+        return SBValue ();
+    }
+
+    SBValue results = ValueObjectConstResult::Create (&thread, res, ConstString ("<evaluation result>"));
+
+    func->DeallocateFunctionResults (exe_ctx, args_addr);
+    if (!reusable)
+        exe_ctx.GetTargetPtr ()->RemoveClangFunction (m_opaque_ptr);
+    return results;
+}
+
+void SBFunction::RemoveReusableFunction (lldb::SBTarget &target)
+{
+    if (target.m_opaque_sp)
+        target.m_opaque_sp->RemoveClangFunction (m_opaque_ptr);
+}
\ No newline at end of file
Index: source/API/SBType.cpp
===================================================================
--- source/API/SBType.cpp	(revision 219490)
+++ source/API/SBType.cpp	(working copy)
@@ -17,6 +17,22 @@
 #include "lldb/Symbol/ClangASTContext.h"
 #include "lldb/Symbol/ClangASTType.h"
 #include "lldb/Symbol/Type.h"
+#include "lldb/API/SBValue.h"
+#include "lldb/API/SBValueList.h"
+#include "lldb/API/SBExpressionOptions.h"
+#include "lldb/API/SBError.h"
+#include "lldb/API/SBFrame.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/API/SBValueList.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/API/SBTarget.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
 
 #include "clang/AST/Decl.h"
 
@@ -821,3 +837,106 @@
 {
     return *m_opaque_sp.get();
 }
+
+void SBTypeMemberFunction::RemoveReusableFunction (lldb::SBTarget& target)
+{
+    if (target.m_opaque_sp)
+        target.m_opaque_sp->RemoveClangFunction (m_opaque_sp.get ());
+}
+
+lldb::SBValue SBTypeMemberFunction::ExecuteFunction (lldb::SBFrame &frame,
+    lldb::SBValue self,
+    lldb::SBValueList arguments,
+    lldb::SBStream &errors,
+    lldb::SBExpressionOptions options,
+    bool reusable)
+{
+    if (!m_opaque_sp)
+    {
+        errors->PutCString ("no value");
+        return SBValue ();
+    }
+    if (!self.IsValid ())
+    {
+        errors->PutCString ("No self");
+        return SBValue ();
+    }
+
+    if (frame.GetFrameSP ())
+    {
+        errors->PutCString ("no frame");
+        return SBValue ();
+    }
+
+    ExecutionContext exe_ctx = frame.GetFrameSP ();
+
+    TypeMemberFunctionImpl& val = *m_opaque_sp.get ();
+
+    ValueList args;
+    ClangASTContext* ast = exe_ctx.GetTargetPtr ()->GetScratchClangASTContext ();
+    ClangASTType pointertype = ast->GetCStringType (true);
+    ValueObjectSP selfptr = self.GetSP ()->Cast (pointertype);
+    selfptr->UpdateValueIfNeeded ();
+    args.PushValue (selfptr->GetValue ());
+
+    uint64_t sel = exe_ctx.GetProcessPtr ()->GetObjCLanguageRuntime ()->GetSelectorFor (ConstString (m_opaque_sp->GetName ()), exe_ctx.GetFramePtr ());
+    Value selectorvalue (ast->GetPointerByteSize () == 4 ? Scalar ((uint32_t)sel) : Scalar (sel));
+    selectorvalue.SetClangType (pointertype);
+    args.PushValue (selectorvalue);
+
+
+    for (int i = 0; i < arguments.GetSize (); i++)  {
+        const ValueObjectSP value = arguments.GetValueAtIndex (i).GetSP ();
+        value->UpdateValueIfNeeded ();
+        args.PushValue (value->GetValue ());
+    }
+
+    Thread& thread = *exe_ctx.GetThreadSP ();
+
+    std::shared_ptr<ClangFunction>& func = exe_ctx.GetTargetPtr ()->GetOrAddClangFunction (m_opaque_sp.get ());
+
+    if (!func)
+    {
+        SymbolContextList sclist;
+        exe_ctx.GetTargetPtr ()->GetImages ().FindFunctions (ConstString ("objc_msgSend"), eFunctionNameTypeAny,
+            true, false, true, sclist);
+        if (!sclist.GetSize ()) {
+            errors->PutCString ("Cannot find msgSend");
+            return SBValue ();
+        }
+        Address* msgsend_address = &sclist[0].symbol->GetAddress ();
+        func.reset (new ClangFunction (thread,
+            m_opaque_sp->GetReturnType (),
+            *msgsend_address,
+            args,
+            m_opaque_sp->GetName ().GetCString ()));
+
+        if (func->CompileFunction (*errors.get ()))
+            return SBValue ();
+
+        if (!func->WriteFunctionWrapper (exe_ctx, *errors.get ()))
+            return SBValue ();
+    }
+    errors.Clear ();
+
+    lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;
+    if (!func->WriteFunctionArguments (exe_ctx, args_addr,
+        func->GetFunctionAddress (), args, *errors.get ()))
+    {
+        return SBValue ();
+    }
+
+    Value res;
+    if (func->ExecuteFunction (exe_ctx, &args_addr, *options.get (), *errors.get (), res))
+    {
+        func->DeallocateFunctionResults (exe_ctx, args_addr);
+        if (!reusable)
+            exe_ctx.GetTargetPtr ()->RemoveClangFunction (m_opaque_sp.get ());
+        return SBValue ();
+    }
+
+    func->DeallocateFunctionResults (exe_ctx, args_addr);
+    if (!reusable)
+        exe_ctx.GetTargetPtr ()->RemoveClangFunction (m_opaque_sp.get ());
+    return ValueObjectConstResult::Create (&thread, res, ConstString ("<evaluation result>"));
+}
Index: source/Expression/ClangFunction.cpp
===================================================================
--- source/Expression/ClangFunction.cpp	(revision 219490)
+++ source/Expression/ClangFunction.cpp	(working copy)
@@ -126,7 +126,7 @@
     // FIXME: How does clang tell us there's no return value?  We need to handle that case.
     unsigned num_errors = 0;
     
-    std::string return_type_str (m_function_return_type.GetTypeName().AsCString(""));
+    std::string return_type_str (m_function_return_type.GetCanonicalType().GetTypeName().AsCString(""));
     
     // Cons up the function we're going to wrap our call in, then compile it...
     // We declare the function "extern "C"" because the compiler might be in C++
@@ -177,11 +177,11 @@
 
         if (trust_function)
         {
-            type_name = function_clang_type.GetFunctionArgumentTypeAtIndex(i).GetTypeName().AsCString("");
+            type_name = function_clang_type.GetFunctionArgumentTypeAtIndex(i).GetCanonicalType().GetTypeName().AsCString("");
         }
         else
         {
-            ClangASTType clang_qual_type = m_arg_values.GetValueAtIndex(i)->GetClangType ();
+            ClangASTType clang_qual_type = m_arg_values.GetValueAtIndex(i)->GetClangType().GetCanonicalType();
             if (clang_qual_type)
             {
                 type_name = clang_qual_type.GetTypeName().AsCString("");
Index: source/Target/ObjCLanguageRuntime.cpp
===================================================================
--- source/Target/ObjCLanguageRuntime.cpp	(revision 219490)
+++ source/Target/ObjCLanguageRuntime.cpp	(working copy)
@@ -19,6 +19,7 @@
 #include "lldb/Symbol/TypeList.h"
 #include "lldb/Target/ObjCLanguageRuntime.h"
 #include "lldb/Target/Target.h"
+#include "lldb/Core/ValueObjectConstResult.h"
 
 #include "llvm/ADT/StringRef.h"
 
@@ -626,3 +627,22 @@
 {
     return nullptr;
 }
+
+lldb::addr_t
+ObjCLanguageRuntime::GetSelectorFor (const ConstString& value, ExecutionContextScope *exe_scope)
+{
+    auto res = m_selector_map.find (value);
+    if (res != m_selector_map.end ())
+        return res->second;
+
+    ValueList args;
+    std::string selector;
+    selector = selector + "((void* (*)(char*))sel_registerName)(\"" + value.AsCString () + "\")";
+    ValueObjectSP selectorptr;
+    exe_scope->CalculateTarget ()->EvaluateExpression (selector.c_str (), exe_scope->CalculateStackFrame ().get (), selectorptr);
+
+    addr_t result = selectorptr->GetValueAsUnsigned (0);
+    if (result)
+        m_selector_map[value] = result;
+    return result;
+}
\ No newline at end of file


More information about the lldb-dev mailing list