EwanCrawford updated this revision to Diff 29343.
EwanCrawford added a comment.

To address that final point of not doing any code execution at all for certain 
targets. I used the CanJIT() idea to create a similar 
CanInterpretFunctionCalls() member function of Process.
This means that we can just pass the value of the 
m_can_interpret_function_calls variable to CanInterpret() instead of the Arch 
or execution context.

Since interpreting function calls is a special case for hexagon right now the 
value defaults to false, and is only set to true by the hexagon dynamic loader.

In the future though when more targets support this feature, 
CanInterpretFunctionCalls() would be enabled by default and then specifically 
disabled by targets. 
Using the example of the OSX kernel, which can't do any code execution, the 
patch explicitly sets jitting and interpreting function calls to false in the 
dynamic loader using an added CanRunCode() function.


Repository:
  rL LLVM

http://reviews.llvm.org/D9404

Files:
  include/lldb/Expression/IRInterpreter.h
  include/lldb/Expression/IRMemoryMap.h
  include/lldb/Target/ABI.h
  include/lldb/Target/Process.h
  include/lldb/Target/ThreadPlanCallFunction.h
  include/lldb/Target/ThreadPlanCallFunctionUsingABI.h
  lldb.xcodeproj/project.pbxproj
  source/Expression/ClangExpressionParser.cpp
  source/Expression/ClangUserExpression.cpp
  source/Expression/IRInterpreter.cpp
  source/Expression/IRMemoryMap.cpp
  source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
  source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
  source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
  source/Target/CMakeLists.txt
  source/Target/Process.cpp
  source/Target/ThreadPlanCallFunction.cpp
  source/Target/ThreadPlanCallFunctionUsingABI.cpp
  test/expression_command/call-function/TestCallUserDefinedFunction.py
  test/expression_command/call-function/main.cpp

Index: test/expression_command/call-function/main.cpp
===================================================================
--- test/expression_command/call-function/main.cpp
+++ test/expression_command/call-function/main.cpp
@@ -1,5 +1,6 @@
 #include <iostream>
 #include <string>
+#include <cstring>
 
 struct Five
 {
@@ -14,6 +15,30 @@
     return my_five;
 }
 
+unsigned int
+fib(unsigned int n)
+{
+    if (n < 2)
+        return n;
+    else
+        return fib(n - 1) + fib(n - 2);
+}
+
+int
+add(int a, int b)
+{
+    return a + b;
+}
+
+bool
+stringCompare(const char *str)
+{
+    if (strcmp( str, "Hello world" ) == 0)
+        return true;
+    else
+        return false;
+}
+
 int main (int argc, char const *argv[])
 {
     std::string str = "Hello world";
Index: test/expression_command/call-function/TestCallUserDefinedFunction.py
===================================================================
--- test/expression_command/call-function/TestCallUserDefinedFunction.py
+++ test/expression_command/call-function/TestCallUserDefinedFunction.py
@@ -0,0 +1,68 @@
+"""
+Test calling user defined functions using expression evaluation.
+
+Note:
+  LLDBs current first choice of evaluating functions is using the IR interpreter,
+  which is only supported on Hexagon. Otherwise JIT is used for the evaluation.
+
+"""
+
+import unittest2
+import lldb
+import lldbutil
+from lldbtest import *
+
+class ExprCommandCallUserDefinedFunction(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Find the line number to break for main.c.
+        self.line = line_number('main.cpp',
+                                '// Please test these expressions while stopped at this line:')
+    @skipUnlessDarwin
+    @dsym_test
+    @expectedFailureDarwin("llvm.org/pr20274") # intermittent failure on MacOSX
+    def test_with_dsym(self):
+        """Test return values of user defined function calls."""
+        self.buildDsym()
+        self.call_function()
+
+    @dwarf_test
+    @expectedFailureFreeBSD("llvm.org/pr20274") # intermittent failure
+    def test_with_dwarf(self):
+        """Test return values of user defined function calls."""
+        self.buildDwarf()
+        self.call_functions()
+
+    def call_functions(self):
+        """Test return values of user defined function calls."""
+
+        # Set breakpoint in main and run exe
+        self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
+        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, num_expected_locations=-1, loc_exact=True)
+
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # Test recursive function call.
+        self.expect("expr fib(5)", substrs = ['$0 = 5'])
+
+        # Test function with more than one paramter
+        self.expect("expr add(4,8)", substrs = ['$1 = 12'])
+
+        # Test nesting function calls in function paramters
+        self.expect("expr add(add(5,2),add(3,4))", substrs = ['$2 = 14'])
+        self.expect("expr add(add(5,2),fib(5))", substrs = ['$3 = 12'])
+
+        # Test function with pointer paramter
+        self.expect("exp stringCompare((const char*) \"Hello world\")", substrs = ['$4 = true'])
+        self.expect("exp stringCompare((const char*) \"Hellworld\")", substrs = ['$5 = false'])
+
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()
Index: source/Target/ThreadPlanCallFunctionUsingABI.cpp
===================================================================
--- source/Target/ThreadPlanCallFunctionUsingABI.cpp
+++ source/Target/ThreadPlanCallFunctionUsingABI.cpp
@@ -0,0 +1,91 @@
+//===-- ThreadPlanCallFunctionUsingABI.cpp ------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/ThreadPlanCallFunctionUsingABI.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//--------------------------------------------------------------------------------------------
+// ThreadPlanCallFunctionUsingABI: Plan to call a single function using the ABI instead of JIT
+//-------------------------------------------------------------------------------------------
+ThreadPlanCallFunctionUsingABI::ThreadPlanCallFunctionUsingABI (Thread &thread,
+                                                          const Address &function,
+                                                          llvm::Type &prototype,
+                                                          llvm::Type &return_type,
+                                                          llvm::ArrayRef<ABI::CallArgument> args,
+                                                          const EvaluateExpressionOptions &options) :
+     ThreadPlanCallFunction(thread,function,options),
+     m_return_type(return_type)
+{
+    lldb::addr_t start_load_addr = LLDB_INVALID_ADDRESS;
+    lldb::addr_t function_load_addr = LLDB_INVALID_ADDRESS;
+    ABI *abi = nullptr;
+
+    if (!ConstructorSetup(thread, abi, start_load_addr, function_load_addr))
+        return;
+
+    if (!abi->PrepareTrivialCall(thread,
+        m_function_sp,
+        function_load_addr,
+        start_load_addr,
+        prototype,
+        args))
+        return;
+
+    ReportRegisterState("ABI Function call was set up.  Register state was:");
+
+    m_valid = true;
+}
+
+ThreadPlanCallFunctionUsingABI::~ThreadPlanCallFunctionUsingABI()
+{
+
+}
+
+void
+ThreadPlanCallFunctionUsingABI::GetDescription(Stream *s, DescriptionLevel level)
+{
+    if (level == eDescriptionLevelBrief)
+    {
+        s->Printf("Function call thread plan using ABI instead of JIT");
+    }
+    else
+    {
+        TargetSP target_sp(m_thread.CalculateTarget());
+        s->Printf("Thread plan to call 0x%" PRIx64" using ABI instead of JIT", m_function_addr.GetLoadAddress(target_sp.get()));
+    }
+}
+
+void
+ThreadPlanCallFunctionUsingABI::SetReturnValue()
+{
+    ProcessSP process_sp(m_thread.GetProcess());
+    const ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
+
+    // Ask the abi for the return value
+    if (abi)
+    {
+        const bool persistent = false;
+        m_return_valobj_sp = abi->GetReturnValueObject(m_thread, m_return_type, persistent);
+    }
+}
Index: source/Target/ThreadPlanCallFunction.cpp
===================================================================
--- source/Target/ThreadPlanCallFunction.cpp
+++ source/Target/ThreadPlanCallFunction.cpp
@@ -147,15 +147,16 @@
     m_trap_exceptions (options.GetTrapExceptions()),
     m_function_addr (function),
     m_function_sp (0),
-    m_return_type (return_type),
     m_takedown_done (false),
     m_should_clear_objc_exception_bp(false),
     m_should_clear_cxx_exception_bp (false),
-    m_stop_address (LLDB_INVALID_ADDRESS)
+    m_stop_address (LLDB_INVALID_ADDRESS),
+    m_return_type (return_type)
 {
-    lldb::addr_t start_load_addr;
-    ABI *abi;
-    lldb::addr_t function_load_addr;
+    lldb::addr_t start_load_addr = LLDB_INVALID_ADDRESS;
+    lldb::addr_t function_load_addr = LLDB_INVALID_ADDRESS;
+    ABI *abi = nullptr;
+
     if (!ConstructorSetup (thread, abi, start_load_addr, function_load_addr))
         return;
 
@@ -171,6 +172,27 @@
     m_valid = true;    
 }
 
+ThreadPlanCallFunction::ThreadPlanCallFunction(Thread &thread,
+                                               const Address &function,
+                                               const EvaluateExpressionOptions &options) :
+    ThreadPlan(ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
+    m_valid(false),
+    m_stop_other_threads(options.GetStopOthers()),
+    m_unwind_on_error(options.DoesUnwindOnError()),
+    m_ignore_breakpoints(options.DoesIgnoreBreakpoints()),
+    m_debug_execution(options.GetDebug()),
+    m_trap_exceptions(options.GetTrapExceptions()),
+    m_function_addr(function),
+    m_function_sp(0),
+    m_takedown_done(false),
+    m_should_clear_objc_exception_bp(false),
+    m_should_clear_cxx_exception_bp(false),
+    m_stop_address(LLDB_INVALID_ADDRESS),
+    m_return_type(ClangASTType())
+{
+
+}
+
 ThreadPlanCallFunction::~ThreadPlanCallFunction ()
 {
     DoTakedown(PlanSucceeded());
@@ -222,13 +244,7 @@
     {
         if (success)
         {
-            ProcessSP process_sp (m_thread.GetProcess());
-            const ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
-            if (abi && m_return_type.IsValid())
-            {
-                const bool persistent = false;
-                m_return_valobj_sp = abi->GetReturnValueObject (m_thread, m_return_type, persistent);
-            }
+            SetReturnValue();
         }
         if (log)
             log->Printf ("ThreadPlanCallFunction(%p): DoTakedown called for thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n",
@@ -574,3 +590,15 @@
     return GetThread().RestoreThreadStateFromCheckpoint(m_stored_thread_state);
 }
 
+
+void
+ThreadPlanCallFunction::SetReturnValue()
+{
+    ProcessSP process_sp(m_thread.GetProcess());
+    const ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
+    if (abi && m_return_type.IsValid())
+    {
+        const bool persistent = false;
+        m_return_valobj_sp = abi->GetReturnValueObject(m_thread, m_return_type, persistent);
+    }
+}
Index: source/Target/Process.cpp
===================================================================
--- source/Target/Process.cpp
+++ source/Target/Process.cpp
@@ -754,6 +754,7 @@
     m_force_next_event_delivery (false),
     m_last_broadcast_state (eStateInvalid),
     m_destroy_in_process (false),
+    m_can_interpret_function_calls(false),
     m_can_jit(eCanJITDontKnow)
 {
     CheckInWithManager ();
@@ -3011,6 +3012,13 @@
     m_can_jit = (can_jit ? eCanJITYes : eCanJITNo);
 }
 
+void
+Process::SetCanRunCode (bool can_run_code)
+{
+    SetCanJIT(can_run_code);
+    m_can_interpret_function_calls = can_run_code;
+}
+
 Error
 Process::DeallocateMemory (addr_t ptr)
 {
Index: source/Target/CMakeLists.txt
===================================================================
--- source/Target/CMakeLists.txt
+++ source/Target/CMakeLists.txt
@@ -40,6 +40,7 @@
   ThreadPlan.cpp
   ThreadPlanBase.cpp
   ThreadPlanCallFunction.cpp
+  ThreadPlanCallFunctionUsingABI.cpp
   ThreadPlanCallUserExpression.cpp
   ThreadPlanPython.cpp
   ThreadPlanRunToAddress.cpp
Index: source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
===================================================================
--- source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
+++ source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
@@ -167,6 +167,9 @@
         
     // Disable JIT for hexagon targets because its not supported
     m_process->SetCanJIT(false);
+
+    // Enable Interpreting of function call expressions
+    m_process->SetCanInterpretFunctionCalls(true);
 
     // Add the current executable to the module list
     ModuleList module_list;
Index: source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
===================================================================
--- source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
+++ source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
@@ -182,7 +182,7 @@
     addr_t kernel_load_address = SearchForDarwinKernel (process);
     if (kernel_load_address != LLDB_INVALID_ADDRESS)
     {
-        process->SetCanJIT(false);
+        process->SetCanRunCode(false);
         return new DynamicLoaderDarwinKernel (process, kernel_load_address);
     }
     return NULL;
Index: source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
===================================================================
--- source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
+++ source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
@@ -257,7 +257,7 @@
         sp -= argSize;
 
         // write this argument onto the stack of the host process
-        proc.get( )->WriteMemory( sp, arg.data, arg.size, error );
+        proc.get( )->WriteMemory( sp, arg.data_ap.get(), arg.size, error );
         if ( error.Fail( ) )
             return false;
 
Index: source/Expression/IRMemoryMap.cpp
===================================================================
--- source/Expression/IRMemoryMap.cpp
+++ source/Expression/IRMemoryMap.cpp
@@ -418,6 +418,32 @@
     m_allocations.erase(iter);
 }
 
+bool
+IRMemoryMap::GetAllocSize(lldb::addr_t address, size_t &size)
+{
+    AllocationMap::iterator iter = FindAllocation(address, size);
+    if (iter == m_allocations.end())
+        return false;
+
+    Allocation &al = iter->second;
+
+    if (address > (al.m_process_start + al.m_size))
+    {
+        size = 0;
+        return false;
+    }
+
+    if (address > al.m_process_start)
+    {
+        int dif = address - al.m_process_start;
+        size = al.m_size - dif;
+        return true;
+    }
+
+    size = al.m_size;
+    return true;
+}
+
 void
 IRMemoryMap::WriteMemory (lldb::addr_t process_address, const uint8_t *bytes, size_t size, Error &error)
 {
Index: source/Expression/IRInterpreter.cpp
===================================================================
--- source/Expression/IRInterpreter.cpp
+++ source/Expression/IRInterpreter.cpp
@@ -10,17 +10,28 @@
 #include "lldb/Core/DataExtractor.h"
 #include "lldb/Core/Error.h"
 #include "lldb/Core/Log.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Module.h"
 #include "lldb/Core/Scalar.h"
 #include "lldb/Core/StreamString.h"
+#include "lldb/Core/ValueObject.h"
 #include "lldb/Expression/IRMemoryMap.h"
 #include "lldb/Expression/IRInterpreter.h"
 #include "lldb/Host/Endian.h"
 
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanCallFunctionUsingABI.h"
+
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -455,7 +466,8 @@
 bool
 IRInterpreter::CanInterpret (llvm::Module &module,
                              llvm::Function &function,
-                             lldb_private::Error &error)
+                             lldb_private::Error &error,
+                             const bool support_function_calls)
 {
     lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
 
@@ -507,7 +519,7 @@
                         return false;
                     }
 
-                    if (!CanIgnoreCall(call_inst))
+                    if (!CanIgnoreCall(call_inst) && !support_function_calls)
                     {
                         if (log)
                             log->Printf("Unsupported instruction: %s", PrintValue(ii).c_str());
@@ -611,7 +623,8 @@
                           lldb_private::IRMemoryMap &memory_map,
                           lldb_private::Error &error,
                           lldb::addr_t stack_frame_bottom,
-                          lldb::addr_t stack_frame_top)
+                          lldb::addr_t stack_frame_top,
+                          lldb_private::ExecutionContext &exe_ctx)
 {
     lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
 
@@ -668,29 +681,7 @@
         {
             default:
                 break;
-            case Instruction::Call:
-            {
-                const CallInst *call_inst = dyn_cast<CallInst>(inst);
 
-                if (!call_inst)
-                {
-                    if (log)
-                        log->Printf("getOpcode() returns %s, but instruction is not a CallInst", inst->getOpcodeName());
-                    error.SetErrorToGenericError();
-                    error.SetErrorString(interpreter_internal_error);
-                    return false;
-                }
-
-                if (!CanIgnoreCall(call_inst))
-                {
-                    if (log)
-                        log->Printf("The interpreter shouldn't have accepted %s", PrintValue(call_inst).c_str());
-                    error.SetErrorToGenericError();
-                    error.SetErrorString(interpreter_internal_error);
-                    return false;
-                }
-            }
-                break;
             case Instruction::Add:
             case Instruction::Sub:
             case Instruction::Mul:
@@ -1476,6 +1467,242 @@
                 }
             }
                 break;
+            case Instruction::Call:
+            {
+                const CallInst *call_inst = dyn_cast<CallInst>(inst);
+
+                if (!call_inst)
+                {
+                    if (log)
+                       log->Printf("getOpcode() returns %s, but instruction is not a CallInst", inst->getOpcodeName());
+                    error.SetErrorToGenericError();
+                    error.SetErrorString(interpreter_internal_error);
+                    return false;
+                }
+
+                if (CanIgnoreCall(call_inst))
+                    break;
+
+                // Get the return type
+                llvm::Type *returnType = call_inst->getType();
+                if (returnType == nullptr)
+                {
+                    error.SetErrorToGenericError();
+                    error.SetErrorString("unable to access return type");
+                    return false;
+                }
+
+                // Work with void, integer and pointer return types
+                if (!returnType->isVoidTy() &&
+                    !returnType->isIntegerTy() &&
+                    !returnType->isPointerTy())
+                {
+                    error.SetErrorToGenericError();
+                    error.SetErrorString("return type is not supported");
+                    return false;
+                }
+
+                // Check we can actually get a thread
+                if (exe_ctx.GetThreadPtr() == nullptr)
+                {
+                    error.SetErrorToGenericError();
+                    error.SetErrorStringWithFormat("unable to acquire thread");
+                    return false;
+                }
+
+                // Make sure we have a valid process
+                if (!exe_ctx.GetProcessPtr())
+                {
+                    error.SetErrorToGenericError();
+                    error.SetErrorStringWithFormat("unable to get the process");
+                    return false;
+                }
+
+                // Find the address of the callee function
+                lldb_private::Scalar I;
+                const llvm::Value *val = call_inst->getCalledValue();
+
+                if (!frame.EvaluateValue(I, val, module))
+                {
+                    error.SetErrorToGenericError();
+                    error.SetErrorString("unable to get address of function");
+                    return false;
+                }
+                lldb_private::Address funcAddr(I.ULongLong(LLDB_INVALID_ADDRESS));
+
+                lldb_private::StreamString error_stream;
+                lldb_private::EvaluateExpressionOptions options;
+
+                // We generally receive a function pointer which we must dereference
+                llvm::Type* prototype = val->getType();
+                if (!prototype->isPointerTy())
+                {
+                    error.SetErrorToGenericError();
+                    error.SetErrorString("call need function pointer");
+                    return false;
+                }
+
+                // Dereference the function pointer
+                prototype = prototype->getPointerElementType();
+                if (!(prototype->isFunctionTy() || prototype->isFunctionVarArg()))
+                {
+                    error.SetErrorToGenericError();
+                    error.SetErrorString("call need function pointer");
+                    return false;
+                }
+
+                // Find number of arguments
+                const int numArgs = call_inst->getNumArgOperands();
+
+                // We work with a fixed array of 16 arguments which is our upper limit
+                static lldb_private::ABI::CallArgument rawArgs[16];
+                if (numArgs >= 16)
+                {
+                    error.SetErrorToGenericError();
+                    error.SetErrorStringWithFormat("function takes too many arguments");
+                    return false;
+                }
+
+                // Push all function arguments to the argument list that will
+                // be passed to the call function thread plan
+                for (int i = 0; i < numArgs; i++)
+                {
+                    // Get details of this argument
+                    llvm::Value *arg_op = call_inst->getArgOperand(i);
+                    llvm::Type  *arg_ty = arg_op->getType();
+
+                    // Ensure that this argument is an supported type
+                    if (!arg_ty->isIntegerTy() && !arg_ty->isPointerTy())
+                    {
+                         error.SetErrorToGenericError();
+                         error.SetErrorStringWithFormat("argument %d must be integer type", i);
+                         return false;
+                    }
+
+                    // Extract the arguments value
+                    lldb_private::Scalar tmp_op = 0;
+                    if (!frame.EvaluateValue(tmp_op, arg_op, module))
+                    {
+                         error.SetErrorToGenericError();
+                         error.SetErrorStringWithFormat("unable to evaluate argument %d", i);
+                         return false;
+                    }
+
+                    // Check if this is a string literal or constant string pointer
+                    if (arg_ty->isPointerTy())
+                    {
+                        // Pointer to just one type
+                        assert(arg_ty->getNumContainedTypes() == 1);
+
+                        lldb::addr_t addr = tmp_op.ULongLong();
+                        size_t dataSize = 0;
+
+                        if (memory_map.GetAllocSize(addr, dataSize))
+                        {
+                            // Create the required buffer
+                            rawArgs[i].size = dataSize;
+                            rawArgs[i].data_ap.reset(new uint8_t[dataSize + 1]);
+
+                            // Read string from host memory
+                            memory_map.ReadMemory(rawArgs[i].data_ap.get(), addr, dataSize, error);
+                            if (error.Fail())
+                            {
+                                assert(!"we have failed to read the string from memory");
+                                return false;
+                            }
+                            // Add null terminator
+                            rawArgs[i].data_ap[dataSize] = '\0';
+                            rawArgs[i].type = lldb_private::ABI::CallArgument::HostPointer;
+                        }
+                        else
+                        {
+                            assert(!"unable to locate host data for transfer to device");
+                            return false;
+                        }
+                    }
+                    else /* if ( arg_ty->isPointerTy() ) */
+                    {
+                        rawArgs[i].type = lldb_private::ABI::CallArgument::TargetValue;
+                        // Get argument size in bytes
+                        rawArgs[i].size = arg_ty->getIntegerBitWidth() / 8;
+                        // Push value into argument list for thread plan
+                        rawArgs[i].value = tmp_op.ULongLong();
+                    }
+
+                }
+
+                // Pack the arguments into an llvm::array
+                llvm::ArrayRef<lldb_private::ABI::CallArgument> args(rawArgs, numArgs);
+
+                // Setup a thread plan to call the target function
+                lldb::ThreadPlanSP call_plan_sp
+                (
+                    new lldb_private::ThreadPlanCallFunctionUsingABI
+                    (
+                        exe_ctx.GetThreadRef(),
+                        funcAddr,
+                        *prototype,
+                        *returnType,
+                        args,
+                        options
+                    )
+                );
+
+                // Check if the plan is valid
+                if (!call_plan_sp || !call_plan_sp->ValidatePlan(&error_stream))
+                {
+                    error.SetErrorToGenericError();
+                    error.SetErrorStringWithFormat("unable to make ThreadPlanCallFunctionUsingABI for 0x%llx", I.ULongLong());
+                    return false;
+                }
+
+                exe_ctx.GetProcessPtr()->SetRunningUserExpression(true);
+
+                // Execute the actual function call thread plan
+                lldb::ExpressionResults res = exe_ctx.GetProcessRef().RunThreadPlan(exe_ctx, call_plan_sp, options, error_stream);
+
+                // Check that the thread plan completed successfully
+                if (res != lldb::ExpressionResults::eExpressionCompleted)
+                {
+                    error.SetErrorToGenericError();
+                    error.SetErrorStringWithFormat("ThreadPlanCallFunctionUsingABI failed");
+                    return false;
+                }
+
+                exe_ctx.GetProcessPtr()->SetRunningUserExpression(false);
+
+                // Void return type
+                if (returnType->isVoidTy())
+                {
+                    // Cant assign to void types, so we leave the frame untouched
+                }
+                else
+                    // Integer or pointer return type
+                    if (returnType->isIntegerTy() || returnType->isPointerTy())
+                    {
+                        // Get the encapsulated return value
+                        lldb::ValueObjectSP retVal = call_plan_sp.get()->GetReturnValueObject();
+
+                        lldb_private::Scalar returnVal = -1;
+                        lldb_private::ValueObject *vobj = retVal.get();
+
+                        // Check if the return value is valid
+                        if (vobj == nullptr || retVal.empty())
+                        {
+                            error.SetErrorToGenericError();
+                            error.SetErrorStringWithFormat("unable to get the return value");
+                            return false;
+                        }
+
+                        // Extract the return value as a integer
+                        lldb_private::Value & value = vobj->GetValue();
+                        returnVal = value.GetScalar();
+
+                        // Push the return value as the result
+                        frame.AssignValue(inst, returnVal, module);
+                    }
+            }
+                break;
         }
 
         ++frame.m_ii;
Index: source/Expression/ClangUserExpression.cpp
===================================================================
--- source/Expression/ClangUserExpression.cpp
+++ source/Expression/ClangUserExpression.cpp
@@ -891,7 +891,8 @@
                                       *m_execution_unit_sp.get(),
                                       interpreter_error,
                                       function_stack_bottom,
-                                      function_stack_top);
+                                      function_stack_top,
+                                      exe_ctx);
 
             if (!interpreter_error.Success())
             {
Index: source/Expression/ClangExpressionParser.cpp
===================================================================
--- source/Expression/ClangExpressionParser.cpp
+++ source/Expression/ClangExpressionParser.cpp
@@ -541,11 +541,12 @@
         bool ir_can_run = ir_for_target.runOnModule(*execution_unit_sp->GetModule());
 
         Error interpret_error;
+        Process *process = exe_ctx.GetProcessPtr();
+
+        bool interpret_function_calls = !process ? false : process->CanInterpretFunctionCalls();
+        can_interpret = IRInterpreter::CanInterpret(*execution_unit_sp->GetModule(), *execution_unit_sp->GetFunction(), interpret_error, interpret_function_calls);
 
-        can_interpret = IRInterpreter::CanInterpret(*execution_unit_sp->GetModule(), *execution_unit_sp->GetFunction(), interpret_error);
 
-        Process *process = exe_ctx.GetProcessPtr();
-
         if (!ir_can_run)
         {
             err.SetErrorString("The expression could not be prepared to run in the target");
Index: lldb.xcodeproj/project.pbxproj
===================================================================
--- lldb.xcodeproj/project.pbxproj
+++ lldb.xcodeproj/project.pbxproj
@@ -859,6 +859,7 @@
 		E7723D481AC4A8C8002BA082 /* RegisterContextFreeBSD_arm64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E7723D461AC4A8C8002BA082 /* RegisterContextFreeBSD_arm64.cpp */; };
 		E7723D4C1AC4A944002BA082 /* RegisterContextPOSIX_arm64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E7723D4A1AC4A944002BA082 /* RegisterContextPOSIX_arm64.cpp */; };
 		E778E9A21B062D1700247609 /* EmulateInstructionMIPS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E778E99F1B062D1700247609 /* EmulateInstructionMIPS.cpp */; };
+		EBDD01251B39B62F00E04792 /* ThreadPlanCallFunctionUsingABI.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EBDD01241B39B62F00E04792 /* ThreadPlanCallFunctionUsingABI.cpp */; };
 		ED88244E15114A9200BC98B9 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDB919B414F6F10D008FF64B /* Security.framework */; };
 		ED88245015114CA200BC98B9 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = ED88244F15114CA200BC98B9 /* main.mm */; };
 		ED88245115114CA200BC98B9 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = ED88244F15114CA200BC98B9 /* main.mm */; };
@@ -2684,6 +2685,8 @@
 		E7723D4B1AC4A944002BA082 /* RegisterContextPOSIX_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextPOSIX_arm64.h; path = Utility/RegisterContextPOSIX_arm64.h; sourceTree = "<group>"; };
 		E778E99F1B062D1700247609 /* EmulateInstructionMIPS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EmulateInstructionMIPS.cpp; sourceTree = "<group>"; };
 		E778E9A01B062D1700247609 /* EmulateInstructionMIPS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EmulateInstructionMIPS.h; sourceTree = "<group>"; };
+		EBDD01241B39B62F00E04792 /* ThreadPlanCallFunctionUsingABI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanCallFunctionUsingABI.cpp; path = source/Target/ThreadPlanCallFunctionUsingABI.cpp; sourceTree = "<group>"; };
+		EBDD01261B39B66700E04792 /* ThreadPlanCallFunctionUsingABI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ThreadPlanCallFunctionUsingABI.h; path = include/lldb/Target/ThreadPlanCallFunctionUsingABI.h; sourceTree = "<group>"; };
 		ED88244F15114CA200BC98B9 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
 		ED88245215114CFC00BC98B9 /* LauncherRootXPCService.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LauncherRootXPCService.mm; sourceTree = "<group>"; };
 		EDB919B214F6EC85008FF64B /* LauncherXPCService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LauncherXPCService.h; sourceTree = "<group>"; };
@@ -4515,6 +4518,8 @@
 		26BC7DEF10F1B80200F91463 /* Target */ = {
 			isa = PBXGroup;
 			children = (
+				EBDD01261B39B66700E04792 /* ThreadPlanCallFunctionUsingABI.h */,
+				EBDD01241B39B62F00E04792 /* ThreadPlanCallFunctionUsingABI.cpp */,
 				8CF02AE019DCBF3B00B14BE0 /* InstrumentationRuntime.h */,
 				8CF02ADF19DCBF3B00B14BE0 /* InstrumentationRuntime.cpp */,
 				8CF02AEE19DD15CF00B14BE0 /* InstrumentationRuntimeStopInfo.h */,
@@ -6307,6 +6312,7 @@
 				26744EF11338317700EF765A /* GDBRemoteCommunicationClient.cpp in Sources */,
 				26744EF31338317700EF765A /* GDBRemoteCommunicationServer.cpp in Sources */,
 				264A97BF133918BC0017F0BE /* PlatformRemoteGDBServer.cpp in Sources */,
+				EBDD01251B39B62F00E04792 /* ThreadPlanCallFunctionUsingABI.cpp in Sources */,
 				2697A54D133A6305004E4240 /* PlatformDarwin.cpp in Sources */,
 				26651A18133BF9E0005B64B7 /* Opcode.cpp in Sources */,
 				3FDFED0B19B7C8DE009756A7 /* HostThreadMacOSX.mm in Sources */,
Index: include/lldb/Target/ThreadPlanCallFunctionUsingABI.h
===================================================================
--- include/lldb/Target/ThreadPlanCallFunctionUsingABI.h
+++ include/lldb/Target/ThreadPlanCallFunctionUsingABI.h
@@ -0,0 +1,58 @@
+//===-- ThreadPlanCallFunctionUsingABI.h --------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ThreadPlanCallFunctionUsingABI_h_
+#define liblldb_ThreadPlanCallFunctionUsingABI_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/IR/Type.h"
+
+namespace lldb_private {
+
+class ThreadPlanCallFunctionUsingABI : public ThreadPlanCallFunction
+{
+    // Create a thread plan to call a function at the address passed in the "function"
+    // argument, this function is executed using register manipulation instead of JIT.
+    // Class derives from ThreadPlanCallFunction and differs by calling a alternative
+    // ABI interface ABI::PrepareTrivialCall() which provides more detailed information.
+public:
+    ThreadPlanCallFunctionUsingABI (Thread &thread,
+                                 const Address &function_address,
+                                 llvm::Type &function_prototype,
+                                 llvm::Type &return_type,
+                                 llvm::ArrayRef<ABI::CallArgument> args,
+                                 const EvaluateExpressionOptions &options);
+
+    ~ThreadPlanCallFunctionUsingABI ();
+
+    void
+    GetDescription (Stream *s, lldb::DescriptionLevel level) override;
+
+protected:
+    void
+    SetReturnValue () override;
+
+
+private:
+    llvm::Type                                     &m_return_type;
+    DISALLOW_COPY_AND_ASSIGN (ThreadPlanCallFunctionUsingABI);
+};
+
+} // namespace lldb_private
+
+#endif  // liblldb_ThreadPlanCallFunctionUsingABI_h_
Index: include/lldb/Target/ThreadPlanCallFunction.h
===================================================================
--- include/lldb/Target/ThreadPlanCallFunction.h
+++ include/lldb/Target/ThreadPlanCallFunction.h
@@ -34,6 +34,10 @@
                             llvm::ArrayRef<lldb::addr_t> args,
                             const EvaluateExpressionOptions &options);
 
+    ThreadPlanCallFunction(Thread &thread,
+                           const Address &function,
+                           const EvaluateExpressionOptions &options);
+
     virtual
     ~ThreadPlanCallFunction ();
 
@@ -133,9 +137,10 @@
 
     virtual bool
     DoPlanExplainsStop (Event *event_ptr);
+
+    virtual void
+    SetReturnValue();
 
-private:
-
     bool
     ConstructorSetup (Thread &thread,
                       ABI *& abi,
@@ -153,7 +158,7 @@
     
     bool
     BreakpointsExplainStop ();
-    
+
     bool                                            m_valid;
     bool                                            m_stop_other_threads;
     bool                                            m_unwind_on_error;
@@ -172,13 +177,14 @@
                                                                          // it's nice to know the real stop reason.
                                                                          // This gets set in DoTakedown.
     StreamString                                    m_constructor_errors;
-    ClangASTType                                    m_return_type;
     lldb::ValueObjectSP                             m_return_valobj_sp;  // If this contains a valid pointer, use the ABI to extract values when complete
     bool                                            m_takedown_done;    // We want to ensure we only do the takedown once.  This ensures that.
     bool                                            m_should_clear_objc_exception_bp;
     bool                                            m_should_clear_cxx_exception_bp;
     lldb::addr_t                                    m_stop_address;     // This is the address we stopped at.  Also set in DoTakedown;
 
+private:
+    ClangASTType                                    m_return_type;
     DISALLOW_COPY_AND_ASSIGN (ThreadPlanCallFunction);
 };
 
Index: include/lldb/Target/Process.h
===================================================================
--- include/lldb/Target/Process.h
+++ include/lldb/Target/Process.h
@@ -2439,8 +2439,41 @@
     ///     True if execution of JIT code is possible; false otherwise.
     //------------------------------------------------------------------
     void SetCanJIT (bool can_jit);
+
+    //------------------------------------------------------------------
+    /// Determines whether executing function calls using the interpreter
+    /// is possible for this process.
+    ///
+    /// @return
+    ///     True if possible; false otherwise.
+    //------------------------------------------------------------------
+    bool CanInterpretFunctionCalls ()
+    {
+        return m_can_interpret_function_calls;
+    }
     
     //------------------------------------------------------------------
+    /// Sets whether executing function calls using the interpreter
+    /// is possible for this process.
+    ///
+    /// @param[in] can_interpret_function_calls
+    ///     True if possible; false otherwise.
+    //------------------------------------------------------------------
+    void SetCanInterpretFunctionCalls (bool can_interpret_function_calls)
+    {
+        m_can_interpret_function_calls = can_interpret_function_calls;
+    }
+
+    //------------------------------------------------------------------
+    /// Sets whether executing code in this process is possible.
+    /// This could be either through JIT or interpreting.
+    ///
+    /// @param[in] can_run_code
+    ///     True if execution of code is possible; false otherwise.
+    //------------------------------------------------------------------
+    void SetCanRunCode (bool can_run_code);
+
+    //------------------------------------------------------------------
     /// Actually deallocate memory in the process.
     ///
     /// This function will deallocate memory in the process's address
@@ -3236,6 +3269,7 @@
     lldb::StateType             m_last_broadcast_state;   /// This helps with the Public event coalescing in ShouldBroadcastEvent.
     std::map<lldb::addr_t,lldb::addr_t> m_resolved_indirect_addresses;
     bool m_destroy_in_process;
+    bool m_can_interpret_function_calls; // Some targets, e.g the OSX kernel, don't support the ability to modify the stack.
     
     enum {
         eCanJITDontKnow= 0,
Index: include/lldb/Target/ABI.h
===================================================================
--- include/lldb/Target/ABI.h
+++ include/lldb/Target/ABI.h
@@ -39,10 +39,9 @@
         };
         eType  type;                /* value of eType */
         size_t size;                /* size in bytes of this argument */
-        union {
-            lldb::addr_t  value;    /* literal value */
-            uint8_t      *data;     /* host data pointer */
-        };
+
+        lldb::addr_t  value;                    /* literal value */
+        std::unique_ptr<uint8_t[]> data_ap;     /* host data pointer */
     };
 
     virtual
@@ -58,7 +57,7 @@
                          lldb::addr_t returnAddress, 
                          llvm::ArrayRef<lldb::addr_t> args) const = 0;
 
-    // Prepare trivial call used from ThreadPlanFunctionCallGDB
+    // Prepare trivial call used from ThreadPlanFunctionCallUsingABI
     // AD:
     //  . Because i don't want to change other ABI's this is not declared pure virtual.
     //    The dummy implementation will simply fail.  Only HexagonABI will currently
Index: include/lldb/Expression/IRMemoryMap.h
===================================================================
--- include/lldb/Expression/IRMemoryMap.h
+++ include/lldb/Expression/IRMemoryMap.h
@@ -60,7 +60,7 @@
     void ReadMemory (uint8_t *bytes, lldb::addr_t process_address, size_t size, Error &error);
     void ReadScalarFromMemory (Scalar &scalar, lldb::addr_t process_address, size_t size, Error &error);
     void ReadPointerFromMemory (lldb::addr_t *address, lldb::addr_t process_address, Error &error);
-    
+    bool GetAllocSize(lldb::addr_t address, size_t &size);
     void GetMemoryData (DataExtractor &extractor, lldb::addr_t process_address, size_t size, Error &error);
     
     lldb::ByteOrder GetByteOrder();
Index: include/lldb/Expression/IRInterpreter.h
===================================================================
--- include/lldb/Expression/IRInterpreter.h
+++ include/lldb/Expression/IRInterpreter.h
@@ -44,7 +44,8 @@
     static bool
     CanInterpret (llvm::Module &module,
                   llvm::Function &function,
-                  lldb_private::Error &error);
+                  lldb_private::Error &error,
+                  const bool support_function_calls);
     
     static bool
     Interpret (llvm::Module &module,
@@ -53,7 +54,8 @@
                lldb_private::IRMemoryMap &memory_map,
                lldb_private::Error &error,
                lldb::addr_t stack_frame_bottom,
-               lldb::addr_t stack_frame_top);
+               lldb::addr_t stack_frame_top,
+               lldb_private::ExecutionContext &exe_ctx);
     
 private:   
     static bool
_______________________________________________
lldb-commits mailing list
lldb-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits

Reply via email to