summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Expression/IRInterpreter.h6
-rw-r--r--lldb/include/lldb/Expression/IRMemoryMap.h2
-rw-r--r--lldb/include/lldb/Target/ABI.h9
-rw-r--r--lldb/include/lldb/Target/Process.h34
-rw-r--r--lldb/include/lldb/Target/ThreadPlanCallFunction.h12
-rw-r--r--lldb/include/lldb/Target/ThreadPlanCallFunctionUsingABI.h58
-rw-r--r--lldb/lldb.xcodeproj/project.pbxproj5
-rw-r--r--lldb/source/Expression/ClangExpressionParser.cpp5
-rw-r--r--lldb/source/Expression/ClangUserExpression.cpp3
-rw-r--r--lldb/source/Expression/IRInterpreter.cpp277
-rw-r--r--lldb/source/Expression/IRMemoryMap.cpp26
-rw-r--r--lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp2
-rw-r--r--lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp2
-rw-r--r--lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp3
-rw-r--r--lldb/source/Target/CMakeLists.txt1
-rw-r--r--lldb/source/Target/Process.cpp8
-rw-r--r--lldb/source/Target/ThreadPlanCallFunction.cpp52
-rw-r--r--lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp91
-rw-r--r--lldb/test/expression_command/call-function/TestCallUserDefinedFunction.py68
-rw-r--r--lldb/test/expression_command/call-function/main.cpp25
20 files changed, 636 insertions, 53 deletions
diff --git a/lldb/include/lldb/Expression/IRInterpreter.h b/lldb/include/lldb/Expression/IRInterpreter.h
index 5defa8dd202..c314bf1099e 100644
--- a/lldb/include/lldb/Expression/IRInterpreter.h
+++ b/lldb/include/lldb/Expression/IRInterpreter.h
@@ -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
diff --git a/lldb/include/lldb/Expression/IRMemoryMap.h b/lldb/include/lldb/Expression/IRMemoryMap.h
index 0da8384c8e6..80add46ef0d 100644
--- a/lldb/include/lldb/Expression/IRMemoryMap.h
+++ b/lldb/include/lldb/Expression/IRMemoryMap.h
@@ -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();
diff --git a/lldb/include/lldb/Target/ABI.h b/lldb/include/lldb/Target/ABI.h
index cfd214d2887..89d4f6bdba6 100644
--- a/lldb/include/lldb/Target/ABI.h
+++ b/lldb/include/lldb/Target/ABI.h
@@ -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
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 6db0ca91daf..f75b3cd5683 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -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,
diff --git a/lldb/include/lldb/Target/ThreadPlanCallFunction.h b/lldb/include/lldb/Target/ThreadPlanCallFunction.h
index 12200ab7655..36e4d6e71c7 100644
--- a/lldb/include/lldb/Target/ThreadPlanCallFunction.h
+++ b/lldb/include/lldb/Target/ThreadPlanCallFunction.h
@@ -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);
};
diff --git a/lldb/include/lldb/Target/ThreadPlanCallFunctionUsingABI.h b/lldb/include/lldb/Target/ThreadPlanCallFunctionUsingABI.h
new file mode 100644
index 00000000000..83d78a5dca0
--- /dev/null
+++ b/lldb/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_
diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj
index edaadafd7da..229f424b673 100644
--- a/lldb/lldb.xcodeproj/project.pbxproj
+++ b/lldb/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 */,
diff --git a/lldb/source/Expression/ClangExpressionParser.cpp b/lldb/source/Expression/ClangExpressionParser.cpp
index 3d5350d3402..2b344b0c373 100644
--- a/lldb/source/Expression/ClangExpressionParser.cpp
+++ b/lldb/source/Expression/ClangExpressionParser.cpp
@@ -541,10 +541,11 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
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)
{
diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp
index 661bab0e4b4..0da70e2b0a7 100644
--- a/lldb/source/Expression/ClangUserExpression.cpp
+++ b/lldb/source/Expression/ClangUserExpression.cpp
@@ -891,7 +891,8 @@ ClangUserExpression::Execute (Stream &error_stream,
*m_execution_unit_sp.get(),
interpreter_error,
function_stack_bottom,
- function_stack_top);
+ function_stack_top,
+ exe_ctx);
if (!interpreter_error.Success())
{
diff --git a/lldb/source/Expression/IRInterpreter.cpp b/lldb/source/Expression/IRInterpreter.cpp
index d11bdc1671b..926d1f22b6a 100644
--- a/lldb/source/Expression/IRInterpreter.cpp
+++ b/lldb/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 @@ static const char *infinite_loop_error = "Interpreter ran for too m
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::Module &module,
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 &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 &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 &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;
diff --git a/lldb/source/Expression/IRMemoryMap.cpp b/lldb/source/Expression/IRMemoryMap.cpp
index a4fe7a96837..4733b16d5f1 100644
--- a/lldb/source/Expression/IRMemoryMap.cpp
+++ b/lldb/source/Expression/IRMemoryMap.cpp
@@ -418,6 +418,32 @@ IRMemoryMap::Free (lldb::addr_t process_address, Error &error)
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)
{
diff --git a/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp b/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
index e9e68bc0e94..69129df1f16 100644
--- a/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
+++ b/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
@@ -257,7 +257,7 @@ ABISysV_hexagon::PrepareTrivialCall ( Thread &thread,
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;
diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
index 8be3c15f32d..32f2d01f5e6 100644
--- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
+++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
@@ -182,7 +182,7 @@ DynamicLoaderDarwinKernel::CreateInstance (Process* process, bool force)
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;
diff --git a/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp b/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
index a4cdc615e02..2308129b8ca 100644
--- a/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
+++ b/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
@@ -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);
diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt
index d34aa92b223..916a2f29984 100644
--- a/lldb/source/Target/CMakeLists.txt
+++ b/lldb/source/Target/CMakeLists.txt
@@ -40,6 +40,7 @@ add_lldb_library(lldbTarget
ThreadPlan.cpp
ThreadPlanBase.cpp
ThreadPlanCallFunction.cpp
+ ThreadPlanCallFunctionUsingABI.cpp
ThreadPlanCallUserExpression.cpp
ThreadPlanPython.cpp
ThreadPlanRunToAddress.cpp
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 81ed8b540bd..3abae4fce5b 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -754,6 +754,7 @@ Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_s
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)
{
diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp
index e742ece7ec5..e7b3abd3c94 100644
--- a/lldb/source/Target/ThreadPlanCallFunction.cpp
+++ b/lldb/source/Target/ThreadPlanCallFunction.cpp
@@ -147,15 +147,16 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
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::ThreadPlanCallFunction (Thread &thread,
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 success)
{
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::RestoreThreadState()
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);
+ }
+}
diff --git a/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp b/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp
new file mode 100644
index 00000000000..53fabd2464e
--- /dev/null
+++ b/lldb/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);
+ }
+}
diff --git a/lldb/test/expression_command/call-function/TestCallUserDefinedFunction.py b/lldb/test/expression_command/call-function/TestCallUserDefinedFunction.py
new file mode 100644
index 00000000000..2aa404ee985
--- /dev/null
+++ b/lldb/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()
diff --git a/lldb/test/expression_command/call-function/main.cpp b/lldb/test/expression_command/call-function/main.cpp
index ca43c2eabe5..9b494c712bc 100644
--- a/lldb/test/expression_command/call-function/main.cpp
+++ b/lldb/test/expression_command/call-function/main.cpp
@@ -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";
OpenPOWER on IntegriCloud