[lldb-dev] [RFC} [Patch] SBFunction::ExecuteFunction (v3)

Carlo Kok ck at remobjects.com
Mon Oct 13 06:05:17 PDT 2014


Oke got that figured out. Attached patch works perfectly and stores the 
cached functions in the Target. I've managed to make the changes in 
existing classes minimal by creating a ClangFunction subclass.

comments welcome.

-- 
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/Expression/ClangFunction.h
===================================================================
--- include/lldb/Expression/ClangFunction.h	(revision 219490)
+++ include/lldb/Expression/ClangFunction.h	(working copy)
@@ -23,6 +23,7 @@
 #include "lldb/Core/ValueObjectList.h"
 #include "lldb/Expression/ClangExpression.h"
 #include "lldb/Target/Process.h"
+#include "lldb/Target/ExecutionContext.h"
 
 namespace lldb_private
 {
@@ -133,7 +134,7 @@
     /// @return
     ///     The number of errors.
     //------------------------------------------------------------------
-    unsigned
+    virtual unsigned
     CompileFunction (Stream &errors);
     
     //------------------------------------------------------------------
@@ -406,7 +407,13 @@
     {
         return m_arg_values;
     }
-private:
+
+    Address
+    GetFunctionAddress() const
+    {
+        return m_function_addr;
+    }
+protected:
     //------------------------------------------------------------------
     // For ClangFunction only
     //------------------------------------------------------------------
@@ -443,6 +450,76 @@
     bool                            m_JITted;                       ///< True if the wrapper function has already been JIT-compiled.
 };
 
+class ClangFunctionWithDeclMap : public ClangFunction
+{
+public:
+    //------------------------------------------------------------------
+    /// Constructor
+    ///
+    /// @param[in] exe_scope
+    ///     An execution context scope that gets us at least a target and 
+    ///     process.
+    ///
+    /// @param[in] function_ptr
+    ///     The default function to be called.  Can be overridden using
+    ///     WriteFunctionArguments().
+    ///
+    /// @param[in] ast_context
+    ///     The AST context to evaluate argument types in.
+    ///
+    /// @param[in] arg_value_list
+    ///     The default values to use when calling this function.  Can
+    ///     be overridden using WriteFunctionArguments().
+    //------------------------------------------------------------------  
+    ClangFunctionWithDeclMap (ExecutionContextScope &exe_scope,
+        Function &function_ptr,
+        ClangASTContext *ast_context,
+        const ValueList &arg_value_list,
+        const char *name);
+
+    //------------------------------------------------------------------
+    /// Constructor
+    ///
+    /// @param[in] exe_scope
+    ///     An execution context scope that gets us at least a target and 
+    ///     process.
+    ///
+    /// @param[in] ast_context
+    ///     The AST context to evaluate argument types in.
+    ///
+    /// @param[in] return_qualtype
+    ///     An opaque Clang QualType for the function result.  Should be
+    ///     defined in ast_context.
+    ///
+    /// @param[in] function_address
+    ///     The address of the function to call.
+    ///
+    /// @param[in] arg_value_list
+    ///     The default values to use when calling this function.  Can
+    ///     be overridden using WriteFunctionArguments().
+    //------------------------------------------------------------------
+    ClangFunctionWithDeclMap (ExecutionContextScope &exe_scope,
+        const ClangASTType &return_type,
+        const Address& function_address,
+        const ValueList &arg_value_list,
+        const char *name);
+
+    ClangExpressionDeclMap *
+        DeclMap ()
+    {
+        return m_expr_decl_map.get();
+    }
+
+    unsigned
+    CompileFunction (Stream &errors);
+
+private:
+    ExecutionContext m_context;
+    std::shared_ptr<Materializer> m_materializer;
+    std::unique_ptr<ClangExpressionDeclMap>     m_expr_decl_map;        ///< The map to use when parsing the expression.
+
+};
+
 } // Namespace lldb_private
 
 #endif  // lldb_ClangFunction_h_
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: scripts/Python/interface/SBFunction.i
===================================================================
--- scripts/Python/interface/SBFunction.i	(revision 219490)
+++ scripts/Python/interface/SBFunction.i	(working copy)
@@ -85,7 +85,15 @@
 
     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);	
+
     bool
     operator == (const lldb::SBFunction &rhs) const;
     
Index: scripts/Python/interface/SBType.i
===================================================================
--- scripts/Python/interface/SBType.i	(revision 219490)
+++ scripts/Python/interface/SBType.i	(working copy)
@@ -101,7 +101,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:
     lldb::TypeMemberFunctionImplSP m_opaque_sp;
 };
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,79 @@
 
 
 
+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.
+    
+    std::shared_ptr<ClangFunction>& func = exe_ctx.GetTargetPtr ()->GetOrAddClangFunction (m_opaque_ptr);
+
+    if (!func)
+    {
+        func.reset (new ClangFunctionWithDeclMap (*frame.GetFrameSP (),
+            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 (exe_ctx.GetThreadPtr(), 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 ()->CalculateExecutionContext (exe_ctx);
+
+    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 ());
+    }
+
+    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 ClangFunctionWithDeclMap (*frame.GetFrameSP (),
+            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 (exe_ctx.GetThreadPtr (), res, ConstString ("<evaluation result>"));
+}
Index: source/Expression/ClangFunction.cpp
===================================================================
--- source/Expression/ClangFunction.cpp	(revision 219490)
+++ source/Expression/ClangFunction.cpp	(working copy)
@@ -43,6 +43,7 @@
 #include "lldb/Target/Thread.h"
 #include "lldb/Target/ThreadPlan.h"
 #include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Expression/ClangExpressionDeclMap.h"
 
 using namespace lldb_private;
 
@@ -594,3 +595,48 @@
     
     return m_struct_extractor.get();
 }
+
+
+ClangFunctionWithDeclMap::ClangFunctionWithDeclMap (ExecutionContextScope &exe_scope,
+    Function &function_ptr,
+    ClangASTContext *ast_context,
+    const ValueList &arg_value_list,
+    const char *name)
+    : ClangFunction (exe_scope, function_ptr, ast_context, arg_value_list, name)
+{
+    exe_scope.CalculateExecutionContext (m_context);
+    // ClangASTSource depends on the struct name starting with $ for external lookups
+    m_wrapper_struct_name = "$__lldb_caller_struct"; 
+}
+
+ClangFunctionWithDeclMap::ClangFunctionWithDeclMap (ExecutionContextScope &exe_scope,
+    const ClangASTType &return_type,
+    const Address& function_address,
+    const ValueList &arg_value_list,
+    const char *name)
+
+    : ClangFunction (exe_scope, return_type, function_address, arg_value_list, name)
+{
+    exe_scope.CalculateExecutionContext (m_context);
+    // ClangASTSource depends on the struct name starting with $ for external lookups
+    m_wrapper_struct_name = "$__lldb_caller_struct";
+}
+
+
+unsigned ClangFunctionWithDeclMap::CompileFunction (Stream &errors)
+{
+    if (!m_materializer)
+        m_materializer.reset (new Materializer ());
+    
+    if (!m_expr_decl_map) 
+        m_expr_decl_map.reset (new ClangExpressionDeclMap (false, m_context));
+        
+    if (!m_expr_decl_map->WillParse (m_context, m_materializer.get ()))
+    {
+        errors.PutCString ("Could not materialize");
+        return 1;
+    }
+    unsigned res = ClangFunction::CompileFunction (errors);
+
+    return res;
+}
\ No newline at end of file
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