mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-27 07:31:28 +00:00
Pass an SBStructuredData to scripted ThreadPlans on use.
This will allow us to write reusable scripted ThreadPlans, since you can use key/value pairs with known keys in the plan to parametrize its behavior. Differential Revision: https://reviews.llvm.org/D68366 llvm-svn: 373675
This commit is contained in:
parent
145cdad119
commit
27a14f19c8
@ -91,6 +91,8 @@ protected:
|
||||
friend class SBTraceOptions;
|
||||
friend class SBDebugger;
|
||||
friend class SBTarget;
|
||||
friend class SBThread;
|
||||
friend class SBThreadPlan;
|
||||
|
||||
StructuredDataImplUP m_impl_up;
|
||||
};
|
||||
|
@ -122,6 +122,10 @@ public:
|
||||
SBError StepUsingScriptedThreadPlan(const char *script_class_name,
|
||||
bool resume_immediately);
|
||||
|
||||
SBError StepUsingScriptedThreadPlan(const char *script_class_name,
|
||||
lldb::SBStructuredData &args_data,
|
||||
bool resume_immediately);
|
||||
|
||||
SBError JumpToLine(lldb::SBFileSpec &file_spec, uint32_t line);
|
||||
|
||||
void RunToAddress(lldb::addr_t addr);
|
||||
|
@ -28,6 +28,9 @@ public:
|
||||
|
||||
SBThreadPlan(lldb::SBThread &thread, const char *class_name);
|
||||
|
||||
SBThreadPlan(lldb::SBThread &thread, const char *class_name,
|
||||
lldb::SBStructuredData &args_data);
|
||||
|
||||
~SBThreadPlan();
|
||||
|
||||
explicit operator bool() const;
|
||||
@ -100,6 +103,9 @@ public:
|
||||
SBThreadPlan QueueThreadPlanForStepScripted(const char *script_class_name);
|
||||
SBThreadPlan QueueThreadPlanForStepScripted(const char *script_class_name,
|
||||
SBError &error);
|
||||
SBThreadPlan QueueThreadPlanForStepScripted(const char *script_class_name,
|
||||
lldb::SBStructuredData &args_data,
|
||||
SBError &error);
|
||||
|
||||
private:
|
||||
friend class SBBreakpoint;
|
||||
|
@ -208,6 +208,7 @@ public:
|
||||
|
||||
virtual StructuredData::ObjectSP
|
||||
CreateScriptedThreadPlan(const char *class_name,
|
||||
StructuredDataImpl *args_data,
|
||||
std::string &error_str,
|
||||
lldb::ThreadPlanSP thread_plan_sp) {
|
||||
return StructuredData::ObjectSP();
|
||||
|
@ -899,6 +899,7 @@ public:
|
||||
|
||||
virtual lldb::ThreadPlanSP
|
||||
QueueThreadPlanForStepScripted(bool abort_other_plans, const char *class_name,
|
||||
StructuredData::ObjectSP extra_args_sp,
|
||||
bool stop_other_threads, Status &status);
|
||||
|
||||
// Thread Plan accessors:
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "lldb/lldb-forward.h"
|
||||
|
||||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/StopInfo.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
@ -29,7 +31,8 @@ namespace lldb_private {
|
||||
|
||||
class ThreadPlanPython : public ThreadPlan {
|
||||
public:
|
||||
ThreadPlanPython(Thread &thread, const char *class_name);
|
||||
ThreadPlanPython(Thread &thread, const char *class_name,
|
||||
StructuredDataImpl *args_data);
|
||||
~ThreadPlanPython() override;
|
||||
|
||||
void GetDescription(Stream *s, lldb::DescriptionLevel level) override;
|
||||
@ -55,6 +58,10 @@ protected:
|
||||
|
||||
private:
|
||||
std::string m_class_name;
|
||||
StructuredDataImpl *m_args_data; // We own this, but the implementation
|
||||
// has to manage the UP (since that is
|
||||
// how it gets stored in the
|
||||
// SBStructuredData).
|
||||
std::string m_error_str;
|
||||
StructuredData::ObjectSP m_implementation_sp;
|
||||
bool m_did_push;
|
||||
|
@ -188,7 +188,7 @@ class HelpCommandTestCase(TestBase):
|
||||
def test_help_next_shows_options(self):
|
||||
"""Test that 'help next' shows all the options for thread step-over"""
|
||||
self.expect("help next",
|
||||
substrs=['--python-class', '--run-mode'], matching=True)
|
||||
substrs=['--step-out-avoids-no-debug', '--run-mode'], matching=True)
|
||||
|
||||
@no_debug_info_test
|
||||
def test_help_provides_alternatives(self):
|
||||
|
@ -38,18 +38,29 @@ class StepScripted(StepWithChild):
|
||||
|
||||
# This plan does a step-over until a variable changes value.
|
||||
class StepUntil(StepWithChild):
|
||||
def __init__(self, thread_plan, dict):
|
||||
def __init__(self, thread_plan, args_data, dict):
|
||||
self.frame = thread_plan.GetThread().frames[0]
|
||||
self.target = thread_plan.GetThread().GetProcess().GetTarget()
|
||||
self.value = self.frame.FindVariable("foo")
|
||||
func_entry = args_data.GetValueForKey("variable_name")
|
||||
|
||||
if not func_entry.IsValid():
|
||||
print("Did not get a valid entry for variable_name")
|
||||
func_name = func_entry.GetStringValue(100)
|
||||
|
||||
self.value = self.frame.FindVariable(func_name)
|
||||
if self.value.GetError().Fail():
|
||||
print("Failed to get foo value: %s"%(self.value.GetError().GetCString()))
|
||||
else:
|
||||
print("'foo' value: %d"%(self.value.GetValueAsUnsigned()))
|
||||
|
||||
StepWithChild.__init__(self, thread_plan)
|
||||
|
||||
|
||||
def queue_child_thread_plan(self):
|
||||
le = self.frame.GetLineEntry()
|
||||
start_addr = le.GetStartAddress()
|
||||
start = start_addr.GetLoadAddress(self.target)
|
||||
end = le.GetEndAddress().GetLoadAddress(self.target)
|
||||
print("Stepping from 0x%x to 0x%x (0x%x)"%(start, end, end - start))
|
||||
return self.thread_plan.QueueThreadPlanForStepOverRange(start_addr,
|
||||
end - start)
|
||||
|
||||
|
@ -63,7 +63,14 @@ class StepScriptedTestCase(TestBase):
|
||||
self.assertEqual(stop_id, process.GetStopID(), "Process didn't run")
|
||||
|
||||
def test_checking_variable(self):
|
||||
"""Test that we can call SBValue API's from a scripted thread plan"""
|
||||
"""Test that we can call SBValue API's from a scripted thread plan - using SBAPI's to step"""
|
||||
self.do_test_checking_variable(False)
|
||||
|
||||
def test_checking_variable_cli(self):
|
||||
"""Test that we can call SBValue API's from a scripted thread plan - using cli to step"""
|
||||
self.do_test_checking_variable(True)
|
||||
|
||||
def do_test_checking_variable(self, use_cli):
|
||||
self.build()
|
||||
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self,
|
||||
"Set a breakpoint here",
|
||||
@ -75,8 +82,21 @@ class StepScriptedTestCase(TestBase):
|
||||
self.assertTrue(foo_val.GetError().Success(), "Got the foo variable")
|
||||
self.assertEqual(foo_val.GetValueAsUnsigned(), 10, "foo starts at 10")
|
||||
|
||||
err = thread.StepUsingScriptedThreadPlan("Steps.StepUntil")
|
||||
self.assertTrue(err.Success(), err.GetCString())
|
||||
if use_cli:
|
||||
result = lldb.SBCommandReturnObject()
|
||||
self.dbg.GetCommandInterpreter().HandleCommand(
|
||||
"thread step-scripted -C Steps.StepUntil -k variable_name -v foo",
|
||||
result)
|
||||
self.assertTrue(result.Succeeded())
|
||||
else:
|
||||
args_data = lldb.SBStructuredData()
|
||||
data = lldb.SBStream()
|
||||
data.Print('{"variable_name" : "foo"}')
|
||||
error = args_data.SetFromJSON(data)
|
||||
self.assertTrue(error.Success(), "Made the args_data correctly")
|
||||
|
||||
err = thread.StepUsingScriptedThreadPlan("Steps.StepUntil", args_data, True)
|
||||
self.assertTrue(err.Success(), err.GetCString())
|
||||
|
||||
# We should not have exited:
|
||||
self.assertEqual(process.GetState(), lldb.eStateStopped, "We are stopped")
|
||||
|
@ -250,6 +250,7 @@ LLDBSwigPythonCreateScriptedThreadPlan
|
||||
(
|
||||
const char *python_class_name,
|
||||
const char *session_dictionary_name,
|
||||
lldb_private::StructuredDataImpl *args_impl,
|
||||
std::string &error_string,
|
||||
const lldb::ThreadPlanSP& thread_plan_sp
|
||||
)
|
||||
@ -279,7 +280,23 @@ LLDBSwigPythonCreateScriptedThreadPlan
|
||||
if (!tp_arg.IsAllocated())
|
||||
Py_RETURN_NONE;
|
||||
|
||||
PythonObject result = pfunc(tp_arg, dict);
|
||||
PythonObject result = {};
|
||||
size_t init_num_args = pfunc.GetNumInitArguments().count;
|
||||
if (init_num_args == 3) {
|
||||
if (args_impl != nullptr) {
|
||||
error_string.assign("args passed, but __init__ does not take an args dictionary");
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
result = pfunc(tp_arg, dict);
|
||||
} else if (init_num_args = 4) {
|
||||
lldb::SBStructuredData *args_value = new lldb::SBStructuredData(args_impl);
|
||||
PythonObject args_arg(PyRefType::Owned, SBTypeToSWIGWrapper(args_value));
|
||||
result = pfunc(tp_arg, args_arg, dict);
|
||||
} else {
|
||||
error_string.assign("wrong number of arguments in __init__, should be 1 or 2 (not including self & dict)");
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
// FIXME: At this point we should check that the class we found supports all the methods
|
||||
// that we need.
|
||||
|
||||
|
@ -253,6 +253,11 @@ public:
|
||||
SBError
|
||||
StepUsingScriptedThreadPlan (const char *script_class_name, bool resume_immediately);
|
||||
|
||||
SBError
|
||||
StepUsingScriptedThreadPlan(const char *script_class_name,
|
||||
lldb::SBStructuredData &args_data,
|
||||
bool resume_immediately);
|
||||
|
||||
SBError
|
||||
JumpToLine (lldb::SBFileSpec &file_spec, uint32_t line);
|
||||
|
||||
|
@ -109,6 +109,14 @@ public:
|
||||
SBThreadPlan
|
||||
QueueThreadPlanForStepScripted(const char *script_class_name);
|
||||
|
||||
SBThreadPlan
|
||||
QueueThreadPlanForStepScripted(const char *script_class_name,
|
||||
SBError &error);
|
||||
SBThreadPlan
|
||||
QueueThreadPlanForStepScripted(const char *script_class_name,
|
||||
SBStructuredData &args_data,
|
||||
SBError &error);
|
||||
|
||||
|
||||
protected:
|
||||
friend class SBBreakpoint;
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "lldb/API/SBFrame.h"
|
||||
#include "lldb/API/SBProcess.h"
|
||||
#include "lldb/API/SBStream.h"
|
||||
#include "lldb/API/SBStructuredData.h"
|
||||
#include "lldb/API/SBSymbolContext.h"
|
||||
#include "lldb/API/SBThreadCollection.h"
|
||||
#include "lldb/API/SBThreadPlan.h"
|
||||
@ -23,6 +24,7 @@
|
||||
#include "lldb/Breakpoint/BreakpointLocation.h"
|
||||
#include "lldb/Core/Debugger.h"
|
||||
#include "lldb/Core/StreamFile.h"
|
||||
#include "lldb/Core/StructuredDataImpl.h"
|
||||
#include "lldb/Core/ValueObject.h"
|
||||
#include "lldb/Interpreter/CommandInterpreter.h"
|
||||
#include "lldb/Symbol/CompileUnit.h"
|
||||
@ -965,9 +967,24 @@ SBError SBThread::StepUsingScriptedThreadPlan(const char *script_class_name) {
|
||||
}
|
||||
|
||||
SBError SBThread::StepUsingScriptedThreadPlan(const char *script_class_name,
|
||||
bool resume_immediately) {
|
||||
LLDB_RECORD_METHOD(lldb::SBError, SBThread, StepUsingScriptedThreadPlan,
|
||||
(const char *, bool), script_class_name,
|
||||
resume_immediately);
|
||||
|
||||
lldb::SBStructuredData no_data;
|
||||
return LLDB_RECORD_RESULT(
|
||||
StepUsingScriptedThreadPlan(script_class_name,
|
||||
no_data,
|
||||
resume_immediately));
|
||||
}
|
||||
|
||||
SBError SBThread::StepUsingScriptedThreadPlan(const char *script_class_name,
|
||||
SBStructuredData &args_data,
|
||||
bool resume_immediately) {
|
||||
LLDB_RECORD_METHOD(lldb::SBError, SBThread, StepUsingScriptedThreadPlan,
|
||||
(const char *, bool), script_class_name,
|
||||
(const char *, lldb::SBStructuredData &, bool),
|
||||
script_class_name, args_data,
|
||||
resume_immediately);
|
||||
|
||||
SBError error;
|
||||
@ -982,8 +999,10 @@ SBError SBThread::StepUsingScriptedThreadPlan(const char *script_class_name,
|
||||
|
||||
Thread *thread = exe_ctx.GetThreadPtr();
|
||||
Status new_plan_status;
|
||||
StructuredData::ObjectSP obj_sp = args_data.m_impl_up->GetObjectSP();
|
||||
|
||||
ThreadPlanSP new_plan_sp = thread->QueueThreadPlanForStepScripted(
|
||||
false, script_class_name, false, new_plan_status);
|
||||
false, script_class_name, obj_sp, false, new_plan_status);
|
||||
|
||||
if (new_plan_status.Fail()) {
|
||||
error.SetErrorString(new_plan_status.AsCString());
|
||||
@ -1460,6 +1479,8 @@ void RegisterMethods<SBThread>(Registry &R) {
|
||||
(const char *));
|
||||
LLDB_REGISTER_METHOD(lldb::SBError, SBThread, StepUsingScriptedThreadPlan,
|
||||
(const char *, bool));
|
||||
LLDB_REGISTER_METHOD(lldb::SBError, SBThread, StepUsingScriptedThreadPlan,
|
||||
(const char *, SBStructuredData &, bool));
|
||||
LLDB_REGISTER_METHOD(lldb::SBError, SBThread, JumpToLine,
|
||||
(lldb::SBFileSpec &, uint32_t));
|
||||
LLDB_REGISTER_METHOD(lldb::SBError, SBThread, ReturnFromFrame,
|
||||
|
@ -11,10 +11,12 @@
|
||||
|
||||
#include "lldb/API/SBFileSpec.h"
|
||||
#include "lldb/API/SBStream.h"
|
||||
#include "lldb/API/SBStructuredData.h"
|
||||
#include "lldb/API/SBSymbolContext.h"
|
||||
#include "lldb/Breakpoint/BreakpointLocation.h"
|
||||
#include "lldb/Core/Debugger.h"
|
||||
#include "lldb/Core/StreamFile.h"
|
||||
#include "lldb/Core/StructuredDataImpl.h"
|
||||
#include "lldb/Interpreter/CommandInterpreter.h"
|
||||
#include "lldb/Symbol/CompileUnit.h"
|
||||
#include "lldb/Symbol/SymbolContext.h"
|
||||
@ -67,7 +69,20 @@ SBThreadPlan::SBThreadPlan(lldb::SBThread &sb_thread, const char *class_name) {
|
||||
|
||||
Thread *thread = sb_thread.get();
|
||||
if (thread)
|
||||
m_opaque_sp = std::make_shared<ThreadPlanPython>(*thread, class_name);
|
||||
m_opaque_sp = std::make_shared<ThreadPlanPython>(*thread, class_name,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
SBThreadPlan::SBThreadPlan(lldb::SBThread &sb_thread, const char *class_name,
|
||||
lldb::SBStructuredData &args_data) {
|
||||
LLDB_RECORD_CONSTRUCTOR(SBThreadPlan, (lldb::SBThread &, const char *,
|
||||
SBStructuredData &),
|
||||
sb_thread, class_name, args_data);
|
||||
|
||||
Thread *thread = sb_thread.get();
|
||||
if (thread)
|
||||
m_opaque_sp = std::make_shared<ThreadPlanPython>(*thread, class_name,
|
||||
args_data.m_impl_up.get());
|
||||
}
|
||||
|
||||
// Assignment operator
|
||||
@ -368,9 +383,35 @@ SBThreadPlan::QueueThreadPlanForStepScripted(const char *script_class_name,
|
||||
|
||||
if (m_opaque_sp) {
|
||||
Status plan_status;
|
||||
StructuredData::ObjectSP empty_args;
|
||||
SBThreadPlan plan =
|
||||
SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepScripted(
|
||||
false, script_class_name, false, plan_status));
|
||||
false, script_class_name, empty_args, false, plan_status));
|
||||
|
||||
if (plan_status.Fail())
|
||||
error.SetErrorString(plan_status.AsCString());
|
||||
|
||||
return LLDB_RECORD_RESULT(plan);
|
||||
} else {
|
||||
return LLDB_RECORD_RESULT(SBThreadPlan());
|
||||
}
|
||||
}
|
||||
|
||||
SBThreadPlan
|
||||
SBThreadPlan::QueueThreadPlanForStepScripted(const char *script_class_name,
|
||||
lldb::SBStructuredData &args_data,
|
||||
SBError &error) {
|
||||
LLDB_RECORD_METHOD(lldb::SBThreadPlan, SBThreadPlan,
|
||||
QueueThreadPlanForStepScripted,
|
||||
(const char *, lldb::SBStructuredData &, lldb::SBError &),
|
||||
script_class_name, args_data, error);
|
||||
|
||||
if (m_opaque_sp) {
|
||||
Status plan_status;
|
||||
StructuredData::ObjectSP args_obj = args_data.m_impl_up->GetObjectSP();
|
||||
SBThreadPlan plan =
|
||||
SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepScripted(
|
||||
false, script_class_name, args_obj, false, plan_status));
|
||||
|
||||
if (plan_status.Fail())
|
||||
error.SetErrorString(plan_status.AsCString());
|
||||
@ -390,6 +431,8 @@ void RegisterMethods<SBThreadPlan>(Registry &R) {
|
||||
LLDB_REGISTER_CONSTRUCTOR(SBThreadPlan, (const lldb::ThreadPlanSP &));
|
||||
LLDB_REGISTER_CONSTRUCTOR(SBThreadPlan, (const lldb::SBThreadPlan &));
|
||||
LLDB_REGISTER_CONSTRUCTOR(SBThreadPlan, (lldb::SBThread &, const char *));
|
||||
LLDB_REGISTER_CONSTRUCTOR(SBThreadPlan, (lldb::SBThread &, const char *,
|
||||
lldb::SBStructuredData &));
|
||||
LLDB_REGISTER_METHOD(const lldb::SBThreadPlan &,
|
||||
SBThreadPlan, operator=,(const lldb::SBThreadPlan &));
|
||||
LLDB_REGISTER_METHOD_CONST(bool, SBThreadPlan, IsValid, ());
|
||||
@ -433,6 +476,10 @@ void RegisterMethods<SBThreadPlan>(Registry &R) {
|
||||
LLDB_REGISTER_METHOD(lldb::SBThreadPlan, SBThreadPlan,
|
||||
QueueThreadPlanForStepScripted,
|
||||
(const char *, lldb::SBError &));
|
||||
LLDB_REGISTER_METHOD(lldb::SBThreadPlan, SBThreadPlan,
|
||||
QueueThreadPlanForStepScripted,
|
||||
(const char *, lldb::SBStructuredData &,
|
||||
lldb::SBError &));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "lldb/Interpreter/CommandInterpreter.h"
|
||||
#include "lldb/Interpreter/CommandReturnObject.h"
|
||||
#include "lldb/Interpreter/OptionArgParser.h"
|
||||
#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"
|
||||
#include "lldb/Interpreter/Options.h"
|
||||
#include "lldb/Symbol/CompileUnit.h"
|
||||
#include "lldb/Symbol/Function.h"
|
||||
@ -401,127 +402,122 @@ static constexpr OptionEnumValues TriRunningModes() {
|
||||
#define LLDB_OPTIONS_thread_step_scope
|
||||
#include "CommandOptions.inc"
|
||||
|
||||
class ThreadStepScopeOptionGroup : public OptionGroup {
|
||||
public:
|
||||
ThreadStepScopeOptionGroup() : OptionGroup() {
|
||||
// Keep default values of all options in one place: OptionParsingStarting
|
||||
// ()
|
||||
OptionParsingStarting(nullptr);
|
||||
}
|
||||
|
||||
~ThreadStepScopeOptionGroup() override = default;
|
||||
|
||||
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
||||
return llvm::makeArrayRef(g_thread_step_scope_options);
|
||||
}
|
||||
|
||||
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
|
||||
ExecutionContext *execution_context) override {
|
||||
Status error;
|
||||
const int short_option
|
||||
= g_thread_step_scope_options[option_idx].short_option;
|
||||
|
||||
switch (short_option) {
|
||||
case 'a': {
|
||||
bool success;
|
||||
bool avoid_no_debug =
|
||||
OptionArgParser::ToBoolean(option_arg, true, &success);
|
||||
if (!success)
|
||||
error.SetErrorStringWithFormat(
|
||||
"invalid boolean value for option '%c'", short_option);
|
||||
else {
|
||||
m_step_in_avoid_no_debug =
|
||||
avoid_no_debug ? eLazyBoolYes : eLazyBoolNo;
|
||||
}
|
||||
} break;
|
||||
|
||||
case 'A': {
|
||||
bool success;
|
||||
bool avoid_no_debug =
|
||||
OptionArgParser::ToBoolean(option_arg, true, &success);
|
||||
if (!success)
|
||||
error.SetErrorStringWithFormat(
|
||||
"invalid boolean value for option '%c'", short_option);
|
||||
else {
|
||||
m_step_out_avoid_no_debug =
|
||||
avoid_no_debug ? eLazyBoolYes : eLazyBoolNo;
|
||||
}
|
||||
} break;
|
||||
|
||||
case 'c':
|
||||
if (option_arg.getAsInteger(0, m_step_count))
|
||||
error.SetErrorStringWithFormat("invalid step count '%s'",
|
||||
option_arg.str().c_str());
|
||||
break;
|
||||
|
||||
case 'm': {
|
||||
auto enum_values = GetDefinitions()[option_idx].enum_values;
|
||||
m_run_mode = (lldb::RunMode)OptionArgParser::ToOptionEnum(
|
||||
option_arg, enum_values, eOnlyDuringStepping, error);
|
||||
} break;
|
||||
|
||||
case 'e':
|
||||
if (option_arg == "block") {
|
||||
m_end_line_is_block_end = true;
|
||||
break;
|
||||
}
|
||||
if (option_arg.getAsInteger(0, m_end_line))
|
||||
error.SetErrorStringWithFormat("invalid end line number '%s'",
|
||||
option_arg.str().c_str());
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
m_avoid_regexp.clear();
|
||||
m_avoid_regexp.assign(option_arg);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
m_step_in_target.clear();
|
||||
m_step_in_target.assign(option_arg);
|
||||
break;
|
||||
|
||||
default:
|
||||
llvm_unreachable("Unimplemented option");
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
||||
m_step_in_avoid_no_debug = eLazyBoolCalculate;
|
||||
m_step_out_avoid_no_debug = eLazyBoolCalculate;
|
||||
m_run_mode = eOnlyDuringStepping;
|
||||
|
||||
// Check if we are in Non-Stop mode
|
||||
TargetSP target_sp =
|
||||
execution_context ? execution_context->GetTargetSP() : TargetSP();
|
||||
if (target_sp && target_sp->GetNonStopModeEnabled())
|
||||
m_run_mode = eOnlyThisThread;
|
||||
|
||||
m_avoid_regexp.clear();
|
||||
m_step_in_target.clear();
|
||||
m_step_count = 1;
|
||||
m_end_line = LLDB_INVALID_LINE_NUMBER;
|
||||
m_end_line_is_block_end = false;
|
||||
}
|
||||
|
||||
// Instance variables to hold the values for command options.
|
||||
LazyBool m_step_in_avoid_no_debug;
|
||||
LazyBool m_step_out_avoid_no_debug;
|
||||
RunMode m_run_mode;
|
||||
std::string m_avoid_regexp;
|
||||
std::string m_step_in_target;
|
||||
uint32_t m_step_count;
|
||||
uint32_t m_end_line;
|
||||
bool m_end_line_is_block_end;
|
||||
};
|
||||
|
||||
class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed {
|
||||
public:
|
||||
class CommandOptions : public Options {
|
||||
public:
|
||||
CommandOptions() : Options() {
|
||||
// Keep default values of all options in one place: OptionParsingStarting
|
||||
// ()
|
||||
OptionParsingStarting(nullptr);
|
||||
}
|
||||
|
||||
~CommandOptions() override = default;
|
||||
|
||||
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
|
||||
ExecutionContext *execution_context) override {
|
||||
Status error;
|
||||
const int short_option = m_getopt_table[option_idx].val;
|
||||
|
||||
switch (short_option) {
|
||||
case 'a': {
|
||||
bool success;
|
||||
bool avoid_no_debug =
|
||||
OptionArgParser::ToBoolean(option_arg, true, &success);
|
||||
if (!success)
|
||||
error.SetErrorStringWithFormat(
|
||||
"invalid boolean value for option '%c'", short_option);
|
||||
else {
|
||||
m_step_in_avoid_no_debug =
|
||||
avoid_no_debug ? eLazyBoolYes : eLazyBoolNo;
|
||||
}
|
||||
} break;
|
||||
|
||||
case 'A': {
|
||||
bool success;
|
||||
bool avoid_no_debug =
|
||||
OptionArgParser::ToBoolean(option_arg, true, &success);
|
||||
if (!success)
|
||||
error.SetErrorStringWithFormat(
|
||||
"invalid boolean value for option '%c'", short_option);
|
||||
else {
|
||||
m_step_out_avoid_no_debug =
|
||||
avoid_no_debug ? eLazyBoolYes : eLazyBoolNo;
|
||||
}
|
||||
} break;
|
||||
|
||||
case 'c':
|
||||
if (option_arg.getAsInteger(0, m_step_count))
|
||||
error.SetErrorStringWithFormat("invalid step count '%s'",
|
||||
option_arg.str().c_str());
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
m_class_name.clear();
|
||||
m_class_name.assign(option_arg);
|
||||
break;
|
||||
|
||||
case 'm': {
|
||||
auto enum_values = GetDefinitions()[option_idx].enum_values;
|
||||
m_run_mode = (lldb::RunMode)OptionArgParser::ToOptionEnum(
|
||||
option_arg, enum_values, eOnlyDuringStepping, error);
|
||||
} break;
|
||||
|
||||
case 'e':
|
||||
if (option_arg == "block") {
|
||||
m_end_line_is_block_end = true;
|
||||
break;
|
||||
}
|
||||
if (option_arg.getAsInteger(0, m_end_line))
|
||||
error.SetErrorStringWithFormat("invalid end line number '%s'",
|
||||
option_arg.str().c_str());
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
m_avoid_regexp.clear();
|
||||
m_avoid_regexp.assign(option_arg);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
m_step_in_target.clear();
|
||||
m_step_in_target.assign(option_arg);
|
||||
break;
|
||||
|
||||
default:
|
||||
llvm_unreachable("Unimplemented option");
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
||||
m_step_in_avoid_no_debug = eLazyBoolCalculate;
|
||||
m_step_out_avoid_no_debug = eLazyBoolCalculate;
|
||||
m_run_mode = eOnlyDuringStepping;
|
||||
|
||||
// Check if we are in Non-Stop mode
|
||||
TargetSP target_sp =
|
||||
execution_context ? execution_context->GetTargetSP() : TargetSP();
|
||||
if (target_sp && target_sp->GetNonStopModeEnabled())
|
||||
m_run_mode = eOnlyThisThread;
|
||||
|
||||
m_avoid_regexp.clear();
|
||||
m_step_in_target.clear();
|
||||
m_class_name.clear();
|
||||
m_step_count = 1;
|
||||
m_end_line = LLDB_INVALID_LINE_NUMBER;
|
||||
m_end_line_is_block_end = false;
|
||||
}
|
||||
|
||||
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
||||
return llvm::makeArrayRef(g_thread_step_scope_options);
|
||||
}
|
||||
|
||||
// Instance variables to hold the values for command options.
|
||||
LazyBool m_step_in_avoid_no_debug;
|
||||
LazyBool m_step_out_avoid_no_debug;
|
||||
RunMode m_run_mode;
|
||||
std::string m_avoid_regexp;
|
||||
std::string m_step_in_target;
|
||||
std::string m_class_name;
|
||||
uint32_t m_step_count;
|
||||
uint32_t m_end_line;
|
||||
bool m_end_line_is_block_end;
|
||||
};
|
||||
|
||||
CommandObjectThreadStepWithTypeAndScope(CommandInterpreter &interpreter,
|
||||
const char *name, const char *help,
|
||||
@ -533,7 +529,8 @@ public:
|
||||
eCommandTryTargetAPILock |
|
||||
eCommandProcessMustBeLaunched |
|
||||
eCommandProcessMustBePaused),
|
||||
m_step_type(step_type), m_step_scope(step_scope), m_options() {
|
||||
m_step_type(step_type), m_step_scope(step_scope), m_options(),
|
||||
m_class_options("scripted step", 'C') {
|
||||
CommandArgumentEntry arg;
|
||||
CommandArgumentData thread_id_arg;
|
||||
|
||||
@ -547,11 +544,19 @@ public:
|
||||
|
||||
// Push the data for the first argument into the m_arguments vector.
|
||||
m_arguments.push_back(arg);
|
||||
|
||||
if (step_type == eStepTypeScripted) {
|
||||
m_all_options.Append(&m_class_options, LLDB_OPT_SET_1, LLDB_OPT_SET_1);
|
||||
}
|
||||
m_all_options.Append(&m_options);
|
||||
m_all_options.Finalize();
|
||||
}
|
||||
|
||||
~CommandObjectThreadStepWithTypeAndScope() override = default;
|
||||
|
||||
Options *GetOptions() override { return &m_options; }
|
||||
Options *GetOptions() override {
|
||||
return &m_all_options;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool DoExecute(Args &command, CommandReturnObject &result) override {
|
||||
@ -591,15 +596,15 @@ protected:
|
||||
}
|
||||
|
||||
if (m_step_type == eStepTypeScripted) {
|
||||
if (m_options.m_class_name.empty()) {
|
||||
if (m_class_options.GetClassName().empty()) {
|
||||
result.AppendErrorWithFormat("empty class name for scripted step.");
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
} else if (!GetDebugger().GetScriptInterpreter()->CheckObjectExists(
|
||||
m_options.m_class_name.c_str())) {
|
||||
m_class_options.GetClassName().c_str())) {
|
||||
result.AppendErrorWithFormat(
|
||||
"class for scripted step: \"%s\" does not exist.",
|
||||
m_options.m_class_name.c_str());
|
||||
m_class_options.GetClassName().c_str());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
@ -715,7 +720,8 @@ protected:
|
||||
m_options.m_step_out_avoid_no_debug);
|
||||
} else if (m_step_type == eStepTypeScripted) {
|
||||
new_plan_sp = thread->QueueThreadPlanForStepScripted(
|
||||
abort_other_plans, m_options.m_class_name.c_str(),
|
||||
abort_other_plans, m_class_options.GetClassName().c_str(),
|
||||
m_class_options.GetStructuredData(),
|
||||
bool_stop_other_threads, new_plan_status);
|
||||
} else {
|
||||
result.AppendError("step type is not supported");
|
||||
@ -783,7 +789,9 @@ protected:
|
||||
protected:
|
||||
StepType m_step_type;
|
||||
StepScope m_step_scope;
|
||||
CommandOptions m_options;
|
||||
ThreadStepScopeOptionGroup m_options;
|
||||
OptionGroupPythonClassWithDict m_class_options;
|
||||
OptionGroupOptions m_all_options;
|
||||
};
|
||||
|
||||
// CommandObjectThreadContinue
|
||||
@ -2060,7 +2068,11 @@ CommandObjectMultiwordThread::CommandObjectMultiwordThread(
|
||||
"step-scripted",
|
||||
CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
|
||||
interpreter, "thread step-scripted",
|
||||
"Step as instructed by the script class passed in the -C option.",
|
||||
"Step as instructed by the script class passed in the -C option. "
|
||||
"You can also specify a dictionary of key (-k) and value (-v) pairs "
|
||||
"that will be used to populate an SBStructuredData Dictionary, which "
|
||||
"will be passed to the constructor of the class implementing the "
|
||||
"scripted step. See the Python Reference for more details.",
|
||||
nullptr, eStepTypeScripted, eStepScopeSource)));
|
||||
|
||||
LoadSubCommand("plan", CommandObjectSP(new CommandObjectMultiwordThreadPlan(
|
||||
|
@ -887,6 +887,23 @@ void PythonCallable::Reset(PyRefType type, PyObject *py_obj) {
|
||||
PythonObject::Reset(PyRefType::Borrowed, result.get());
|
||||
}
|
||||
|
||||
PythonCallable::ArgInfo PythonCallable::GetNumInitArguments() const {
|
||||
ArgInfo result = {0, false, false, false};
|
||||
if (!IsValid())
|
||||
return result;
|
||||
PyObject *py_func_obj = m_py_obj;
|
||||
if (!PyClass_Check(m_py_obj))
|
||||
return result;
|
||||
|
||||
PythonObject __init__ = GetAttributeValue("__init__");
|
||||
if (__init__.IsValid() ) {
|
||||
auto __init_callable__ = __init__.AsType<PythonCallable>();
|
||||
if (__init_callable__.IsValid())
|
||||
return __init_callable__.GetNumArguments();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
PythonCallable::ArgInfo PythonCallable::GetNumArguments() const {
|
||||
ArgInfo result = {0, false, false, false};
|
||||
if (!IsValid())
|
||||
|
@ -438,6 +438,10 @@ public:
|
||||
void Reset(PyRefType type, PyObject *py_obj) override;
|
||||
|
||||
ArgInfo GetNumArguments() const;
|
||||
|
||||
// If the callable is a Py_Class, then find the number of arguments
|
||||
// of the __init__ method.
|
||||
ArgInfo GetNumInitArguments() const;
|
||||
|
||||
PythonObject operator()();
|
||||
|
||||
|
@ -97,6 +97,7 @@ LLDBSwigPythonCreateCommandObject(const char *python_class_name,
|
||||
|
||||
extern "C" void *LLDBSwigPythonCreateScriptedThreadPlan(
|
||||
const char *python_class_name, const char *session_dictionary_name,
|
||||
StructuredDataImpl *args_data,
|
||||
std::string &error_string,
|
||||
const lldb::ThreadPlanSP &thread_plan_sp);
|
||||
|
||||
@ -1845,7 +1846,8 @@ StructuredData::DictionarySP ScriptInterpreterPythonImpl::OSPlugin_CreateThread(
|
||||
}
|
||||
|
||||
StructuredData::ObjectSP ScriptInterpreterPythonImpl::CreateScriptedThreadPlan(
|
||||
const char *class_name, std::string &error_str,
|
||||
const char *class_name, StructuredDataImpl *args_data,
|
||||
std::string &error_str,
|
||||
lldb::ThreadPlanSP thread_plan_sp) {
|
||||
if (class_name == nullptr || class_name[0] == '\0')
|
||||
return StructuredData::ObjectSP();
|
||||
@ -1868,7 +1870,7 @@ StructuredData::ObjectSP ScriptInterpreterPythonImpl::CreateScriptedThreadPlan(
|
||||
Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
|
||||
ret_val = LLDBSwigPythonCreateScriptedThreadPlan(
|
||||
class_name, python_interpreter->m_dictionary_name.c_str(),
|
||||
error_str, thread_plan_sp);
|
||||
args_data, error_str, thread_plan_sp);
|
||||
if (!ret_val)
|
||||
return {};
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ public:
|
||||
|
||||
StructuredData::ObjectSP
|
||||
CreateScriptedThreadPlan(const char *class_name,
|
||||
StructuredDataImpl *args_data,
|
||||
std::string &error_str,
|
||||
lldb::ThreadPlanSP thread_plan) override;
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "lldb/Core/Debugger.h"
|
||||
#include "lldb/Core/FormatEntity.h"
|
||||
#include "lldb/Core/Module.h"
|
||||
#include "lldb/Core/StructuredDataImpl.h"
|
||||
#include "lldb/Core/ValueObject.h"
|
||||
#include "lldb/Host/Host.h"
|
||||
#include "lldb/Interpreter/OptionValueFileSpecList.h"
|
||||
@ -1482,9 +1483,18 @@ ThreadPlanSP Thread::QueueThreadPlanForStepUntil(
|
||||
}
|
||||
|
||||
lldb::ThreadPlanSP Thread::QueueThreadPlanForStepScripted(
|
||||
bool abort_other_plans, const char *class_name, bool stop_other_threads,
|
||||
bool abort_other_plans, const char *class_name,
|
||||
StructuredData::ObjectSP extra_args_sp, bool stop_other_threads,
|
||||
Status &status) {
|
||||
ThreadPlanSP thread_plan_sp(new ThreadPlanPython(*this, class_name));
|
||||
|
||||
StructuredDataImpl *extra_args_impl = nullptr;
|
||||
if (extra_args_sp) {
|
||||
extra_args_impl = new StructuredDataImpl();
|
||||
extra_args_impl->SetObjectSP(extra_args_sp);
|
||||
}
|
||||
|
||||
ThreadPlanSP thread_plan_sp(new ThreadPlanPython(*this, class_name,
|
||||
extra_args_impl));
|
||||
|
||||
status = QueueThreadPlan(thread_plan_sp, abort_other_plans);
|
||||
return thread_plan_sp;
|
||||
|
@ -25,10 +25,11 @@ using namespace lldb_private;
|
||||
|
||||
// ThreadPlanPython
|
||||
|
||||
ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name)
|
||||
ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name,
|
||||
StructuredDataImpl *args_data)
|
||||
: ThreadPlan(ThreadPlan::eKindPython, "Python based Thread Plan", thread,
|
||||
eVoteNoOpinion, eVoteNoOpinion),
|
||||
m_class_name(class_name), m_did_push(false) {
|
||||
m_class_name(class_name), m_args_data(args_data), m_did_push(false) {
|
||||
SetIsMasterPlan(true);
|
||||
SetOkayToDiscard(true);
|
||||
SetPrivate(false);
|
||||
@ -65,7 +66,8 @@ void ThreadPlanPython::DidPush() {
|
||||
.GetScriptInterpreter();
|
||||
if (script_interp) {
|
||||
m_implementation_sp = script_interp->CreateScriptedThreadPlan(
|
||||
m_class_name.c_str(), m_error_str, this->shared_from_this());
|
||||
m_class_name.c_str(), m_args_data, m_error_str,
|
||||
this->shared_from_this());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,6 +95,7 @@ LLDBSwigPythonCreateCommandObject(const char *python_class_name,
|
||||
|
||||
extern "C" void *LLDBSwigPythonCreateScriptedThreadPlan(
|
||||
const char *python_class_name, const char *session_dictionary_name,
|
||||
StructuredDataImpl *args_data,
|
||||
std::string &error_string,
|
||||
const lldb::ThreadPlanSP &thread_plan_sp) {
|
||||
return nullptr;
|
||||
|
Loading…
Reference in New Issue
Block a user