This revision was automatically updated to reflect the committed changes.
Closed by commit rL242137: Expression evaluation, a new 
ThreadPlanCallFunctionUsingABI for executing a… (authored by EwanCrawford).

Changed prior to commit:
  http://reviews.llvm.org/D9404?vs=29343&id=29661#toc

Repository:
  rL LLVM

http://reviews.llvm.org/D9404

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

Index: lldb/trunk/source/Target/Process.cpp
===================================================================
--- lldb/trunk/source/Target/Process.cpp
+++ lldb/trunk/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: lldb/trunk/source/Target/CMakeLists.txt
===================================================================
--- lldb/trunk/source/Target/CMakeLists.txt
+++ lldb/trunk/source/Target/CMakeLists.txt
@@ -40,6 +40,7 @@
   ThreadPlan.cpp
   ThreadPlanBase.cpp
   ThreadPlanCallFunction.cpp
+  ThreadPlanCallFunctionUsingABI.cpp
   ThreadPlanCallUserExpression.cpp
   ThreadPlanPython.cpp
   ThreadPlanRunToAddress.cpp
Index: lldb/trunk/source/Target/ThreadPlanCallFunction.cpp
===================================================================
--- lldb/trunk/source/Target/ThreadPlanCallFunction.cpp
+++ lldb/trunk/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: lldb/trunk/source/Target/ThreadPlanCallFunctionUsingABI.cpp
===================================================================
--- lldb/trunk/source/Target/ThreadPlanCallFunctionUsingABI.cpp
+++ lldb/trunk/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: lldb/trunk/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
===================================================================
--- lldb/trunk/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
+++ lldb/trunk/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: lldb/trunk/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
===================================================================
--- lldb/trunk/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
+++ lldb/trunk/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
@@ -168,6 +168,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;
     module_list.Append(executable);
Index: lldb/trunk/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
===================================================================
--- lldb/trunk/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
+++ lldb/trunk/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: lldb/trunk/source/Expression/ClangUserExpression.cpp
===================================================================
--- lldb/trunk/source/Expression/ClangUserExpression.cpp
+++ lldb/trunk/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: lldb/trunk/source/Expression/IRMemoryMap.cpp
===================================================================
--- lldb/trunk/source/Expression/IRMemoryMap.cpp
+++ lldb/trunk/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: lldb/trunk/source/Expression/IRInterpreter.cpp
===================================================================
--- lldb/trunk/source/Expression/IRInterpreter.cpp
+++ lldb/trunk/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: lldb/trunk/source/Expression/ClangExpressionParser.cpp
===================================================================
--- lldb/trunk/source/Expression/ClangExpressionParser.cpp
+++ lldb/trunk/source/Expression/ClangExpressionParser.cpp
@@ -541,10 +541,11 @@
         bool ir_can_run = ir_for_target.runOnModule(*execution_unit_sp->GetModule());
 
         Error interpret_error;
+        Process *process = exe_ctx.GetProcessPtr();
 
-        can_interpret = IRInterpreter::CanInterpret(*execution_unit_sp->GetModule(), *execution_unit_sp->GetFunction(), interpret_error);
+        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);
 
-        Process *process = exe_ctx.GetProcessPtr();
 
         if (!ir_can_run)
         {
Index: lldb/trunk/include/lldb/Expression/IRMemoryMap.h
===================================================================
--- lldb/trunk/include/lldb/Expression/IRMemoryMap.h
+++ lldb/trunk/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: lldb/trunk/include/lldb/Expression/IRInterpreter.h
===================================================================
--- lldb/trunk/include/lldb/Expression/IRInterpreter.h
+++ lldb/trunk/include/lldb/Expression/IRInterpreter.h
@@ -44,16 +44,18 @@
     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,
                llvm::Function &function,
                llvm::ArrayRef<lldb::addr_t> args,
                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
Index: lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h
===================================================================
--- lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h
+++ lldb/trunk/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 ();
 
@@ -134,7 +138,8 @@
     virtual bool
     DoPlanExplainsStop (Event *event_ptr);
 
-private:
+    virtual void
+    SetReturnValue();
 
     bool
     ConstructorSetup (Thread &thread,
@@ -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: lldb/trunk/include/lldb/Target/Process.h
===================================================================
--- lldb/trunk/include/lldb/Target/Process.h
+++ lldb/trunk/include/lldb/Target/Process.h
@@ -2471,8 +2471,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
@@ -3268,6 +3301,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: lldb/trunk/include/lldb/Target/ThreadPlanCallFunctionUsingABI.h
===================================================================
--- lldb/trunk/include/lldb/Target/ThreadPlanCallFunctionUsingABI.h
+++ lldb/trunk/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: lldb/trunk/include/lldb/Target/ABI.h
===================================================================
--- lldb/trunk/include/lldb/Target/ABI.h
+++ lldb/trunk/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: lldb/trunk/test/expression_command/call-function/TestCallUserDefinedFunction.py
===================================================================
--- lldb/trunk/test/expression_command/call-function/TestCallUserDefinedFunction.py
+++ lldb/trunk/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: lldb/trunk/test/expression_command/call-function/main.cpp
===================================================================
--- lldb/trunk/test/expression_command/call-function/main.cpp
+++ lldb/trunk/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: lldb/trunk/lldb.xcodeproj/project.pbxproj
===================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj
@@ -2689,6 +2689,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>"; };
@@ -4522,6 +4524,8 @@
 		26BC7DEF10F1B80200F91463 /* Target */ = {
 			isa = PBXGroup;
 			children = (
+				EBDD01261B39B66700E04792 /* ThreadPlanCallFunctionUsingABI.h */,
+				EBDD01241B39B62F00E04792 /* ThreadPlanCallFunctionUsingABI.cpp */,
 				8CF02AE019DCBF3B00B14BE0 /* InstrumentationRuntime.h */,
 				8CF02ADF19DCBF3B00B14BE0 /* InstrumentationRuntime.cpp */,
 				8CF02AEE19DD15CF00B14BE0 /* InstrumentationRuntimeStopInfo.h */,
@@ -6315,6 +6319,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 */,
_______________________________________________
lldb-commits mailing list
lldb-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits

Reply via email to