[Lldb-commits] [lldb] r242137 - Expression evaluation, a new ThreadPlanCallFunctionUsingABI for executing a function call on target via register manipulation

Ewan Crawford ewan at codeplay.com
Tue Jul 14 03:56:58 PDT 2015


Author: ewancrawford
Date: Tue Jul 14 05:56:58 2015
New Revision: 242137

URL: http://llvm.org/viewvc/llvm-project?rev=242137&view=rev
Log:
Expression evaluation, a new ThreadPlanCallFunctionUsingABI for executing a function call on target via register manipulation

For Hexagon we want to be able to call functions during debugging, however currently lldb only supports this when there is JIT support. 
Although emulation using IR interpretation is an alternative, it is currently limited in that it can't make function calls.

In this patch we have extended the IR interpreter so that it can execute a function call on the target using register manipulation. 
To do this we need to handle the Call IR instruction, passing arguments to a new thread plan and collecting any return values to pass back into the IR interpreter. 

The new thread plan is needed to call an alternative ABI interface of "ABI::PerpareTrivialCall()", allowing more detailed information about arguments and return values.

Reviewers: jingham, spyffe

Subscribers: emaste, lldb-commits, ted, ADodds, deepak2427

Differential Revision: http://reviews.llvm.org/D9404

Added:
    lldb/trunk/include/lldb/Target/ThreadPlanCallFunctionUsingABI.h
    lldb/trunk/source/Target/ThreadPlanCallFunctionUsingABI.cpp
    lldb/trunk/test/expression_command/call-function/TestCallUserDefinedFunction.py
Modified:
    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/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/test/expression_command/call-function/main.cpp

Modified: lldb/trunk/include/lldb/Expression/IRInterpreter.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/IRInterpreter.h?rev=242137&r1=242136&r2=242137&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Expression/IRInterpreter.h (original)
+++ lldb/trunk/include/lldb/Expression/IRInterpreter.h Tue Jul 14 05:56:58 2015
@@ -44,7 +44,8 @@ public:
     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 @@ public:
                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

Modified: lldb/trunk/include/lldb/Expression/IRMemoryMap.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/IRMemoryMap.h?rev=242137&r1=242136&r2=242137&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Expression/IRMemoryMap.h (original)
+++ lldb/trunk/include/lldb/Expression/IRMemoryMap.h Tue Jul 14 05:56:58 2015
@@ -60,7 +60,7 @@ public:
     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();

Modified: lldb/trunk/include/lldb/Target/ABI.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/ABI.h?rev=242137&r1=242136&r2=242137&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/ABI.h (original)
+++ lldb/trunk/include/lldb/Target/ABI.h Tue Jul 14 05:56:58 2015
@@ -39,10 +39,9 @@ public:
         };
         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 @@ public:
                          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

Modified: lldb/trunk/include/lldb/Target/Process.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=242137&r1=242136&r2=242137&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Process.h (original)
+++ lldb/trunk/include/lldb/Target/Process.h Tue Jul 14 05:56:58 2015
@@ -2471,8 +2471,41 @@ public:
     ///     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 @@ protected:
     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,

Modified: lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h?rev=242137&r1=242136&r2=242137&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h (original)
+++ lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h Tue Jul 14 05:56:58 2015
@@ -34,6 +34,10 @@ public:
                             llvm::ArrayRef<lldb::addr_t> args,
                             const EvaluateExpressionOptions &options);
 
+    ThreadPlanCallFunction(Thread &thread,
+                           const Address &function,
+                           const EvaluateExpressionOptions &options);
+
     virtual
     ~ThreadPlanCallFunction ();
 
@@ -134,7 +138,8 @@ protected:
     virtual bool
     DoPlanExplainsStop (Event *event_ptr);
 
-private:
+    virtual void
+    SetReturnValue();
 
     bool
     ConstructorSetup (Thread &thread,
@@ -153,7 +158,7 @@ private:
     
     bool
     BreakpointsExplainStop ();
-    
+
     bool                                            m_valid;
     bool                                            m_stop_other_threads;
     bool                                            m_unwind_on_error;
@@ -172,13 +177,14 @@ private:
                                                                          // 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);
 };
 

Added: lldb/trunk/include/lldb/Target/ThreadPlanCallFunctionUsingABI.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/ThreadPlanCallFunctionUsingABI.h?rev=242137&view=auto
==============================================================================
--- lldb/trunk/include/lldb/Target/ThreadPlanCallFunctionUsingABI.h (added)
+++ lldb/trunk/include/lldb/Target/ThreadPlanCallFunctionUsingABI.h Tue Jul 14 05:56:58 2015
@@ -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_

Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=242137&r1=242136&r2=242137&view=diff
==============================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Tue Jul 14 05:56:58 2015
@@ -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 */,

Modified: lldb/trunk/source/Expression/ClangExpressionParser.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangExpressionParser.cpp?rev=242137&r1=242136&r2=242137&view=diff
==============================================================================
--- lldb/trunk/source/Expression/ClangExpressionParser.cpp (original)
+++ lldb/trunk/source/Expression/ClangExpressionParser.cpp Tue Jul 14 05:56:58 2015
@@ -541,10 +541,11 @@ ClangExpressionParser::PrepareForExecuti
         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)
         {

Modified: lldb/trunk/source/Expression/ClangUserExpression.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangUserExpression.cpp?rev=242137&r1=242136&r2=242137&view=diff
==============================================================================
--- lldb/trunk/source/Expression/ClangUserExpression.cpp (original)
+++ lldb/trunk/source/Expression/ClangUserExpression.cpp Tue Jul 14 05:56:58 2015
@@ -891,7 +891,8 @@ ClangUserExpression::Execute (Stream &er
                                       *m_execution_unit_sp.get(),
                                       interpreter_error,
                                       function_stack_bottom,
-                                      function_stack_top);
+                                      function_stack_top,
+                                      exe_ctx);
 
             if (!interpreter_error.Success())
             {

Modified: lldb/trunk/source/Expression/IRInterpreter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/IRInterpreter.cpp?rev=242137&r1=242136&r2=242137&view=diff
==============================================================================
--- lldb/trunk/source/Expression/IRInterpreter.cpp (original)
+++ lldb/trunk/source/Expression/IRInterpreter.cpp Tue Jul 14 05:56:58 2015
@@ -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 @@ static const char *infinite_loop_error
 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 @@ IRInterpreter::CanInterpret (llvm::Modul
                         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 @@ IRInterpreter::Interpret (llvm::Module &
                           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 @@ IRInterpreter::Interpret (llvm::Module &
         {
             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 @@ IRInterpreter::Interpret (llvm::Module &
                 }
             }
                 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;

Modified: lldb/trunk/source/Expression/IRMemoryMap.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/IRMemoryMap.cpp?rev=242137&r1=242136&r2=242137&view=diff
==============================================================================
--- lldb/trunk/source/Expression/IRMemoryMap.cpp (original)
+++ lldb/trunk/source/Expression/IRMemoryMap.cpp Tue Jul 14 05:56:58 2015
@@ -418,6 +418,32 @@ IRMemoryMap::Free (lldb::addr_t process_
     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)
 {

Modified: lldb/trunk/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp?rev=242137&r1=242136&r2=242137&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp (original)
+++ lldb/trunk/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp Tue Jul 14 05:56:58 2015
@@ -257,7 +257,7 @@ ABISysV_hexagon::PrepareTrivialCall ( Th
         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;
 

Modified: lldb/trunk/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp?rev=242137&r1=242136&r2=242137&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp (original)
+++ lldb/trunk/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp Tue Jul 14 05:56:58 2015
@@ -182,7 +182,7 @@ DynamicLoaderDarwinKernel::CreateInstanc
     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;

Modified: lldb/trunk/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp?rev=242137&r1=242136&r2=242137&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp (original)
+++ lldb/trunk/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp Tue Jul 14 05:56:58 2015
@@ -168,6 +168,9 @@ DynamicLoaderHexagonDYLD::DidAttach()
     // 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);

Modified: lldb/trunk/source/Target/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/CMakeLists.txt?rev=242137&r1=242136&r2=242137&view=diff
==============================================================================
--- lldb/trunk/source/Target/CMakeLists.txt (original)
+++ lldb/trunk/source/Target/CMakeLists.txt Tue Jul 14 05:56:58 2015
@@ -40,6 +40,7 @@ add_lldb_library(lldbTarget
   ThreadPlan.cpp
   ThreadPlanBase.cpp
   ThreadPlanCallFunction.cpp
+  ThreadPlanCallFunctionUsingABI.cpp
   ThreadPlanCallUserExpression.cpp
   ThreadPlanPython.cpp
   ThreadPlanRunToAddress.cpp

Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=242137&r1=242136&r2=242137&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Tue Jul 14 05:56:58 2015
@@ -754,6 +754,7 @@ Process::Process(Target &target, Listene
     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 @@ Process::SetCanJIT (bool can_jit)
     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)
 {

Modified: lldb/trunk/source/Target/ThreadPlanCallFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanCallFunction.cpp?rev=242137&r1=242136&r2=242137&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanCallFunction.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlanCallFunction.cpp Tue Jul 14 05:56:58 2015
@@ -147,15 +147,16 @@ ThreadPlanCallFunction::ThreadPlanCallFu
     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 @@ ThreadPlanCallFunction::ThreadPlanCallFu
     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 @@ ThreadPlanCallFunction::DoTakedown (bool
     {
         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 @@ ThreadPlanCallFunction::RestoreThreadSta
     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);
+    }
+}

Added: lldb/trunk/source/Target/ThreadPlanCallFunctionUsingABI.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanCallFunctionUsingABI.cpp?rev=242137&view=auto
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanCallFunctionUsingABI.cpp (added)
+++ lldb/trunk/source/Target/ThreadPlanCallFunctionUsingABI.cpp Tue Jul 14 05:56:58 2015
@@ -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);
+    }
+}

Added: lldb/trunk/test/expression_command/call-function/TestCallUserDefinedFunction.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/expression_command/call-function/TestCallUserDefinedFunction.py?rev=242137&view=auto
==============================================================================
--- lldb/trunk/test/expression_command/call-function/TestCallUserDefinedFunction.py (added)
+++ lldb/trunk/test/expression_command/call-function/TestCallUserDefinedFunction.py Tue Jul 14 05:56:58 2015
@@ -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()

Modified: lldb/trunk/test/expression_command/call-function/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/expression_command/call-function/main.cpp?rev=242137&r1=242136&r2=242137&view=diff
==============================================================================
--- lldb/trunk/test/expression_command/call-function/main.cpp (original)
+++ lldb/trunk/test/expression_command/call-function/main.cpp Tue Jul 14 05:56:58 2015
@@ -1,5 +1,6 @@
 #include <iostream>
 #include <string>
+#include <cstring>
 
 struct Five
 {
@@ -14,6 +15,30 @@ returnsFive()
     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";





More information about the lldb-commits mailing list