This checkin is the first step in making the lldb thread stepping mechanism more accessible from
the user level. It adds the ability to invent new stepping modes implemented by python classes,
and to view the current thread plan stack and to some extent alter it.
I haven't gotten to documentation or tests yet. But this should not cause any behavior changes
if you don't use it, so its safe to check it in now and work on it incrementally.
llvm-svn: 218642
diff --git a/lldb/source/API/SBCommandInterpreter.cpp b/lldb/source/API/SBCommandInterpreter.cpp
index e1adea7..397ee61 100644
--- a/lldb/source/API/SBCommandInterpreter.cpp
+++ b/lldb/source/API/SBCommandInterpreter.cpp
@@ -442,6 +442,17 @@
const lldb::ValueObjectSP& valobj_sp);
+extern "C" void*
+LLDBSwigPythonCreateScriptedThreadPlan (const char *python_class_name,
+ const char *session_dictionary_name,
+ const lldb::ThreadPlanSP& thread_plan_sp);
+
+extern "C" bool
+LLDBSWIGPythonCallThreadPlan (void *implementor,
+ const char *method_name,
+ Event *event_sp,
+ bool &got_error);
+
extern "C" uint32_t
LLDBSwigPython_CalculateNumChildren (void *implementor);
@@ -539,7 +550,9 @@
LLDBSWIGPythonRunScriptKeywordThread,
LLDBSWIGPythonRunScriptKeywordTarget,
LLDBSWIGPythonRunScriptKeywordFrame,
- LLDBSWIGPython_GetDynamicSetting);
+ LLDBSWIGPython_GetDynamicSetting,
+ LLDBSwigPythonCreateScriptedThreadPlan,
+ LLDBSWIGPythonCallThreadPlan);
#endif
}
}
diff --git a/lldb/source/API/SBEvent.cpp b/lldb/source/API/SBEvent.cpp
index 57a699f..c62c495 100644
--- a/lldb/source/API/SBEvent.cpp
+++ b/lldb/source/API/SBEvent.cpp
@@ -43,6 +43,12 @@
{
}
+SBEvent::SBEvent (Event *event_ptr) :
+ m_event_sp (),
+ m_opaque_ptr (event_ptr)
+{
+}
+
SBEvent::SBEvent (const SBEvent &rhs) :
m_event_sp (rhs.m_event_sp),
m_opaque_ptr (rhs.m_opaque_ptr)
diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp
index a0bfa43..390fa0d 100644
--- a/lldb/source/API/SBThread.cpp
+++ b/lldb/source/API/SBThread.cpp
@@ -41,6 +41,7 @@
#include "lldb/API/SBEvent.h"
#include "lldb/API/SBFrame.h"
#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBThreadPlan.h"
#include "lldb/API/SBValue.h"
using namespace lldb;
@@ -918,7 +919,9 @@
Thread *thread = exe_ctx.GetThreadPtr();
- ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForRunToAddress (abort_other_plans, target_addr, stop_other_threads));
+ ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForRunToAddress (abort_other_plans,
+ target_addr,
+ stop_other_threads));
// This returns an error, we should use it!
ResumeNewPlan (exe_ctx, new_plan_sp.get());
@@ -1073,6 +1076,46 @@
}
SBError
+SBThread::StepUsingScriptedThreadPlan (const char *script_class_name)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ SBError sb_error;
+
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ if (log)
+ {
+ log->Printf ("SBThread(%p)::StepUsingScriptedThreadPlan: class name: %s",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
+ script_class_name);
+ }
+
+
+ if (!exe_ctx.HasThreadScope())
+ {
+ sb_error.SetErrorString("this SBThread object is invalid");
+ return sb_error;
+ }
+
+ Thread *thread = exe_ctx.GetThreadPtr();
+ ThreadPlanSP thread_plan_sp = thread->QueueThreadPlanForStepScripted(false, script_class_name, false);
+
+ if (thread_plan_sp)
+ sb_error = ResumeNewPlan(exe_ctx, thread_plan_sp.get());
+ else
+ {
+ sb_error.SetErrorStringWithFormat("Error queuing thread plan for class: %s.", script_class_name);
+ if (log)
+ log->Printf ("SBThread(%p)::StepUsingScriptedThreadPlan: Error queuing thread plan for class: %s",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
+ script_class_name);
+ }
+
+ return sb_error;
+}
+
+SBError
SBThread::JumpToLine (lldb::SBFileSpec &file_spec, uint32_t line)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
@@ -1473,7 +1516,8 @@
const char *queue_name = new_thread_sp->GetQueueName();
if (queue_name == NULL)
queue_name = "";
- log->Printf ("SBThread(%p)::GetExtendedBacktraceThread() => new extended Thread created (%p) with queue_id 0x%" PRIx64 " queue name '%s'",
+ log->Printf ("SBThread(%p)::GetExtendedBacktraceThread() => new extended Thread "
+ "created (%p) with queue_id 0x%" PRIx64 " queue name '%s'",
static_cast<void*>(exe_ctx.GetThreadPtr()),
static_cast<void*>(new_thread_sp.get()),
new_thread_sp->GetQueueID(),
@@ -1515,3 +1559,24 @@
return thread_sp->SafeToCallFunctions();
return true;
}
+
+lldb_private::Thread *
+SBThread::operator->()
+{
+ ThreadSP thread_sp(m_opaque_sp->GetThreadSP());
+ if (thread_sp)
+ return thread_sp.get();
+ else
+ return NULL;
+}
+
+lldb_private::Thread *
+SBThread::get()
+{
+ ThreadSP thread_sp(m_opaque_sp->GetThreadSP());
+ if (thread_sp)
+ return thread_sp.get();
+ else
+ return NULL;
+}
+
diff --git a/lldb/source/API/SBThreadPlan.cpp b/lldb/source/API/SBThreadPlan.cpp
new file mode 100644
index 0000000..02b1a8d
--- /dev/null
+++ b/lldb/source/API/SBThreadPlan.cpp
@@ -0,0 +1,285 @@
+//===-- SBThread.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/lldb-python.h"
+
+#include "lldb/API/SBThread.h"
+
+#include "lldb/API/SBSymbolContext.h"
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StructuredData.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Target/SystemRuntime.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Queue.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanPython.h"
+#include "lldb/Target/ThreadPlanStepInstruction.h"
+#include "lldb/Target/ThreadPlanStepOut.h"
+#include "lldb/Target/ThreadPlanStepRange.h"
+#include "lldb/Target/ThreadPlanStepInRange.h"
+
+
+#include "lldb/API/SBAddress.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBEvent.h"
+#include "lldb/API/SBFrame.h"
+#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBThreadPlan.h"
+#include "lldb/API/SBValue.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Constructors
+//----------------------------------------------------------------------
+SBThreadPlan::SBThreadPlan ()
+{
+}
+
+SBThreadPlan::SBThreadPlan (const ThreadPlanSP& lldb_object_sp) :
+ m_opaque_sp (lldb_object_sp)
+{
+}
+
+SBThreadPlan::SBThreadPlan (const SBThreadPlan &rhs) :
+ m_opaque_sp (rhs.m_opaque_sp)
+{
+
+}
+
+SBThreadPlan::SBThreadPlan (lldb::SBThread &sb_thread, const char *class_name)
+{
+ Thread *thread = sb_thread.get();
+ if (thread)
+ m_opaque_sp.reset(new ThreadPlanPython(*thread, class_name));
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+
+const lldb::SBThreadPlan &
+SBThreadPlan::operator = (const SBThreadPlan &rhs)
+{
+ if (this != &rhs)
+ m_opaque_sp = rhs.m_opaque_sp;
+ return *this;
+}
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SBThreadPlan::~SBThreadPlan()
+{
+}
+
+lldb_private::ThreadPlan *
+SBThreadPlan::get()
+{
+ return m_opaque_sp.get();
+}
+
+bool
+SBThreadPlan::IsValid() const
+{
+ return m_opaque_sp.get() != NULL;
+}
+
+void
+SBThreadPlan::Clear ()
+{
+ m_opaque_sp.reset();
+}
+
+lldb::StopReason
+SBThreadPlan::GetStopReason()
+{
+ return eStopReasonNone;
+}
+
+size_t
+SBThreadPlan::GetStopReasonDataCount()
+{
+ return 0;
+}
+
+uint64_t
+SBThreadPlan::GetStopReasonDataAtIndex(uint32_t idx)
+{
+ return 0;
+}
+
+SBThread
+SBThreadPlan::GetThread () const
+{
+ if (m_opaque_sp)
+ {
+ return SBThread(m_opaque_sp->GetThread().shared_from_this());
+ }
+ else
+ return SBThread();
+}
+
+bool
+SBThreadPlan::GetDescription (lldb::SBStream &description) const
+{
+ if (m_opaque_sp)
+ {
+ m_opaque_sp->GetDescription(description.get(), eDescriptionLevelFull);
+ }
+ else
+ {
+ description.Printf("Empty SBThreadPlan");
+ }
+ return true;
+}
+
+void
+SBThreadPlan::SetThreadPlan (const ThreadPlanSP& lldb_object_sp)
+{
+ m_opaque_sp = lldb_object_sp;
+}
+
+void
+SBThreadPlan::SetPlanComplete (bool success)
+{
+ if (m_opaque_sp)
+ m_opaque_sp->SetPlanComplete (success);
+}
+
+bool
+SBThreadPlan::IsPlanComplete()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->IsPlanComplete();
+ else
+ return true;
+}
+
+bool
+SBThreadPlan::IsValid()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->ValidatePlan(nullptr);
+ else
+ return false;
+}
+
+ // This section allows an SBThreadPlan to push another of the common types of plans...
+ //
+ // FIXME, you should only be able to queue thread plans from inside the methods of a
+ // Scripted Thread Plan. Need a way to enforce that.
+
+SBThreadPlan
+SBThreadPlan::QueueThreadPlanForStepOverRange (SBAddress &sb_start_address,
+ lldb::addr_t size)
+{
+ if (m_opaque_sp)
+ {
+ Address *start_address = sb_start_address.get();
+ if (!start_address)
+ {
+ return SBThreadPlan();
+ }
+
+ AddressRange range (*start_address, size);
+ SymbolContext sc;
+ start_address->CalculateSymbolContext(&sc);
+ return SBThreadPlan (m_opaque_sp->GetThread().QueueThreadPlanForStepOverRange (false,
+ range,
+ sc,
+ eAllThreads));
+ }
+ else
+ {
+ return SBThreadPlan();
+ }
+}
+
+SBThreadPlan
+SBThreadPlan::QueueThreadPlanForStepInRange (SBAddress &sb_start_address,
+ lldb::addr_t size)
+{
+ if (m_opaque_sp)
+ {
+ Address *start_address = sb_start_address.get();
+ if (!start_address)
+ {
+ return SBThreadPlan();
+ }
+
+ AddressRange range (*start_address, size);
+ SymbolContext sc;
+ start_address->CalculateSymbolContext(&sc);
+ return SBThreadPlan (m_opaque_sp->GetThread().QueueThreadPlanForStepInRange (false,
+ range,
+ sc,
+ NULL,
+ eAllThreads));
+ }
+ else
+ {
+ return SBThreadPlan();
+ }
+}
+
+SBThreadPlan
+SBThreadPlan::QueueThreadPlanForStepOut (uint32_t frame_idx_to_step_to, bool first_insn)
+{
+ if (m_opaque_sp)
+ {
+ SymbolContext sc;
+ sc = m_opaque_sp->GetThread().GetStackFrameAtIndex(0)->GetSymbolContext(lldb::eSymbolContextEverything);
+ return SBThreadPlan (m_opaque_sp->GetThread().QueueThreadPlanForStepOut (false,
+ &sc,
+ first_insn,
+ false,
+ eVoteYes,
+ eVoteNoOpinion,
+ frame_idx_to_step_to));
+ }
+ else
+ {
+ return SBThreadPlan();
+ }
+}
+
+SBThreadPlan
+SBThreadPlan::QueueThreadPlanForRunToAddress (SBAddress sb_address)
+{
+ if (m_opaque_sp)
+ {
+ Address *address = sb_address.get();
+ if (!address)
+ return SBThreadPlan();
+
+ return SBThreadPlan (m_opaque_sp->GetThread().QueueThreadPlanForRunToAddress (false,
+ *address,
+ false));
+ }
+ else
+ {
+ return SBThreadPlan();
+ }
+}
+
+
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
index e7a8652..785e8f0 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -46,7 +46,108 @@
// CommandObjectThreadBacktrace
//-------------------------------------------------------------------------
-class CommandObjectThreadBacktrace : public CommandObjectParsed
+class CommandObjectIterateOverThreads : public CommandObjectParsed
+{
+public:
+ CommandObjectIterateOverThreads (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help,
+ const char *syntax,
+ uint32_t flags) :
+ CommandObjectParsed (interpreter, name, help, syntax, flags)
+ {
+ }
+
+ virtual ~CommandObjectIterateOverThreads() {}
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ result.SetStatus (m_success_return);
+
+ if (command.GetArgumentCount() == 0)
+ {
+ Thread *thread = m_exe_ctx.GetThreadPtr();
+ if (!HandleOneThread (*thread, result))
+ return false;
+ }
+ else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ uint32_t idx = 0;
+ for (ThreadSP thread_sp : process->Threads())
+ {
+ if (idx != 0 && m_add_return)
+ result.AppendMessage("");
+
+ if (!HandleOneThread(*(thread_sp.get()), result))
+ return false;
+ ++idx;
+ }
+ }
+ else
+ {
+ const size_t num_args = command.GetArgumentCount();
+ Process *process = m_exe_ctx.GetProcessPtr();
+ Mutex::Locker locker (process->GetThreadList().GetMutex());
+ std::vector<ThreadSP> thread_sps;
+
+ for (size_t i = 0; i < num_args; i++)
+ {
+ bool success;
+
+ uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx));
+
+ if (!thread_sps[i])
+ {
+ result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ }
+
+ for (uint32_t i = 0; i < num_args; i++)
+ {
+ if (!HandleOneThread (*(thread_sps[i].get()), result))
+ return false;
+
+ if (i < num_args - 1 && m_add_return)
+ result.AppendMessage("");
+ }
+ }
+ return result.Succeeded();
+ }
+
+protected:
+
+ // Override this to do whatever you need to do for one thread.
+ //
+ // If you return false, the iteration will stop, otherwise it will proceed.
+ // The result is set to m_success_return (defaults to eReturnStatusSuccessFinishResult) before the iteration,
+ // so you only need to set the return status in HandleOneThread if you want to indicate an error.
+ // If m_add_return is true, a blank line will be inserted between each of the listings (except the last one.)
+
+ virtual bool
+ HandleOneThread (Thread &thread, CommandReturnObject &result) = 0;
+
+ ReturnStatus m_success_return = eReturnStatusSuccessFinishResult;
+ bool m_add_return = true;
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadBacktrace
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadBacktrace : public CommandObjectIterateOverThreads
{
public:
@@ -134,7 +235,7 @@
};
CommandObjectThreadBacktrace (CommandInterpreter &interpreter) :
- CommandObjectParsed (interpreter,
+ CommandObjectIterateOverThreads (interpreter,
"thread backtrace",
"Show the stack for one or more threads. If no threads are specified, show the currently selected thread. Use the thread-index \"all\" to see all threads.",
NULL,
@@ -145,18 +246,6 @@
eFlagProcessMustBePaused ),
m_options(interpreter)
{
- CommandArgumentEntry arg;
- CommandArgumentData thread_idx_arg;
-
- // Define the first (and only) variant of this arg.
- thread_idx_arg.arg_type = eArgTypeThreadIndex;
- thread_idx_arg.arg_repetition = eArgRepeatStar;
-
- // There is only one variant this argument could be; put it into the argument entry.
- arg.push_back (thread_idx_arg);
-
- // Push the data for the first argument into the m_arguments vector.
- m_arguments.push_back (arg);
}
~CommandObjectThreadBacktrace()
@@ -197,106 +286,28 @@
}
virtual bool
- DoExecute (Args& command, CommandReturnObject &result)
- {
- result.SetStatus (eReturnStatusSuccessFinishResult);
+ HandleOneThread (Thread &thread, CommandReturnObject &result)
+ {
Stream &strm = result.GetOutputStream();
// Don't show source context when doing backtraces.
const uint32_t num_frames_with_source = 0;
- if (command.GetArgumentCount() == 0)
- {
- Thread *thread = m_exe_ctx.GetThreadPtr();
- // Thread::GetStatus() returns the number of frames shown.
- if (thread->GetStatus (strm,
+
+ if (!thread.GetStatus (strm,
m_options.m_start,
m_options.m_count,
num_frames_with_source))
- {
- result.SetStatus (eReturnStatusSuccessFinishResult);
- if (m_options.m_extended_backtrace)
- {
- DoExtendedBacktrace (thread, result);
- }
- }
- }
- else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0)
{
- Process *process = m_exe_ctx.GetProcessPtr();
- uint32_t idx = 0;
- for (ThreadSP thread_sp : process->Threads())
- {
- if (idx != 0)
- result.AppendMessage("");
-
- if (!thread_sp->GetStatus (strm,
- m_options.m_start,
- m_options.m_count,
- num_frames_with_source))
- {
- result.AppendErrorWithFormat ("error displaying backtrace for thread: \"0x%4.4x\"\n", idx);
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
- if (m_options.m_extended_backtrace)
- {
- DoExtendedBacktrace (thread_sp.get(), result);
- }
-
- ++idx;
- }
+ result.AppendErrorWithFormat ("error displaying backtrace for thread: \"0x%4.4x\"\n", thread.GetIndexID());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
}
- else
+ if (m_options.m_extended_backtrace)
{
- const size_t num_args = command.GetArgumentCount();
- Process *process = m_exe_ctx.GetProcessPtr();
- Mutex::Locker locker (process->GetThreadList().GetMutex());
- std::vector<ThreadSP> thread_sps;
-
- for (size_t i = 0; i < num_args; i++)
- {
- bool success;
-
- uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success);
- if (!success)
- {
- result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i));
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
-
- thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx));
-
- if (!thread_sps[i])
- {
- result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i));
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
-
- }
-
- for (uint32_t i = 0; i < num_args; i++)
- {
- if (!thread_sps[i]->GetStatus (strm,
- m_options.m_start,
- m_options.m_count,
- num_frames_with_source))
- {
- result.AppendErrorWithFormat ("error displaying backtrace for thread: \"%s\"\n", command.GetArgumentAtIndex(i));
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
- if (m_options.m_extended_backtrace)
- {
- DoExtendedBacktrace (thread_sps[i].get(), result);
- }
-
- if (i < num_args - 1)
- result.AppendMessage("");
- }
+ DoExtendedBacktrace (&thread, result);
}
- return result.Succeeded();
+
+ return true;
}
CommandOptions m_options;
@@ -379,6 +390,12 @@
break;
}
break;
+ case 'C':
+ {
+ m_class_name.clear();
+ m_class_name.assign(option_arg);
+ }
+ break;
case 'm':
{
OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values;
@@ -416,6 +433,7 @@
m_run_mode = eOnlyDuringStepping;
m_avoid_regexp.clear();
m_step_in_target.clear();
+ m_class_name.clear();
m_step_count = 1;
}
@@ -435,6 +453,7 @@
RunMode m_run_mode;
std::string m_avoid_regexp;
std::string m_step_in_target;
+ std::string m_class_name;
int32_t m_step_count;
};
@@ -520,6 +539,22 @@
}
}
+ if (m_step_type == eStepTypeScripted)
+ {
+ if (m_options.m_class_name.empty())
+ {
+ result.AppendErrorWithFormat ("empty class name for scripted step.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (!m_interpreter.GetScriptInterpreter()->CheckObjectExists(m_options.m_class_name.c_str()))
+ {
+ result.AppendErrorWithFormat ("class for scripted step: \"%s\" does not exist.", m_options.m_class_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
const bool abort_other_plans = false;
const lldb::RunMode stop_other_threads = m_options.m_run_mode;
@@ -530,7 +565,7 @@
bool_stop_other_threads = false;
else if (m_options.m_run_mode == eOnlyDuringStepping)
{
- if (m_step_type == eStepTypeOut)
+ if (m_step_type == eStepTypeOut || m_step_type == eStepTypeScripted)
bool_stop_other_threads = false;
else
bool_stop_other_threads = true;
@@ -599,6 +634,12 @@
thread->GetSelectedFrameIndex(),
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(),
+ bool_stop_other_threads);
+ }
else
{
result.AppendError ("step type is not supported");
@@ -686,10 +727,11 @@
{
{ LLDB_OPT_SET_1, false, "step-in-avoids-no-debug", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "A boolean value that sets whether stepping into functions will step over functions with no debug information."},
{ LLDB_OPT_SET_1, false, "step-out-avoids-no-debug", 'A', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "A boolean value, if true stepping out of functions will continue to step out till it hits a function with debug information."},
-{ LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 1, eArgTypeCount, "How many times to perform the stepping operation - currently only supported for step-inst and next-inst."},
-{ LLDB_OPT_SET_1, false, "run-mode", 'm', OptionParser::eRequiredArgument, NULL, g_tri_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread."},
-{ LLDB_OPT_SET_1, false, "step-over-regexp",'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in."},
-{ LLDB_OPT_SET_1, false, "step-in-target", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into."},
+{ LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 1, eArgTypeCount, "How many times to perform the stepping operation - currently only supported for step-inst and next-inst."},
+{ LLDB_OPT_SET_1, false, "run-mode", 'm', OptionParser::eRequiredArgument, NULL, g_tri_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread."},
+{ LLDB_OPT_SET_1, false, "step-over-regexp", 'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in."},
+{ LLDB_OPT_SET_1, false, "step-in-target", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into."},
+{ LLDB_OPT_SET_2, false, "python-class", 'C', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonClass, "The name of the class that will manage this step - only supported for Scripted Step."},
{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -1358,32 +1400,22 @@
// CommandObjectThreadInfo
//-------------------------------------------------------------------------
-class CommandObjectThreadInfo : public CommandObjectParsed
+class CommandObjectThreadInfo : public CommandObjectIterateOverThreads
{
public:
CommandObjectThreadInfo (CommandInterpreter &interpreter) :
- CommandObjectParsed (interpreter,
- "thread info",
- "Show an extended summary of information about thread(s) in a process.",
- "thread info",
- eFlagRequiresProcess |
- eFlagTryTargetAPILock |
- eFlagProcessMustBeLaunched |
- eFlagProcessMustBePaused),
+ CommandObjectIterateOverThreads (interpreter,
+ "thread info",
+ "Show an extended summary of information about thread(s) in a process.",
+ "thread info",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused),
m_options (interpreter)
{
- CommandArgumentEntry arg;
- CommandArgumentData thread_idx_arg;
-
- thread_idx_arg.arg_type = eArgTypeThreadIndex;
- thread_idx_arg.arg_repetition = eArgRepeatStar;
-
- // There is only one variant this argument could be; put it into the argument entry.
- arg.push_back (thread_idx_arg);
-
- // Push the data for the first argument into the m_arguments vector.
- m_arguments.push_back (arg);
+ m_add_return = false;
}
class CommandOptions : public Options
@@ -1451,81 +1483,16 @@
}
virtual bool
- DoExecute (Args& command, CommandReturnObject &result)
+ HandleOneThread (Thread &thread, CommandReturnObject &result)
{
- result.SetStatus (eReturnStatusSuccessFinishResult);
Stream &strm = result.GetOutputStream();
-
- if (command.GetArgumentCount() == 0)
+ if (!thread.GetDescription (strm, eDescriptionLevelFull, m_options.m_json))
{
- Thread *thread = m_exe_ctx.GetThreadPtr();
- if (thread->GetDescription (strm, eDescriptionLevelFull, m_options.m_json))
- {
- result.SetStatus (eReturnStatusSuccessFinishResult);
- }
+ result.AppendErrorWithFormat ("error displaying info for thread: \"%d\"\n", thread.GetIndexID());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
}
- else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0)
- {
- Process *process = m_exe_ctx.GetProcessPtr();
- uint32_t idx = 0;
- for (ThreadSP thread_sp : process->Threads())
- {
- if (idx != 0)
- result.AppendMessage("");
- if (!thread_sp->GetDescription (strm, eDescriptionLevelFull, m_options.m_json))
- {
- result.AppendErrorWithFormat ("error displaying info for thread: \"0x%4.4x\"\n", idx);
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
- ++idx;
- }
- }
- else
- {
- const size_t num_args = command.GetArgumentCount();
- Process *process = m_exe_ctx.GetProcessPtr();
- Mutex::Locker locker (process->GetThreadList().GetMutex());
- std::vector<ThreadSP> thread_sps;
-
- for (size_t i = 0; i < num_args; i++)
- {
- bool success;
-
- uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success);
- if (!success)
- {
- result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i));
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
-
- thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx));
-
- if (!thread_sps[i])
- {
- result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i));
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
-
- }
-
- for (uint32_t i = 0; i < num_args; i++)
- {
- if (!thread_sps[i]->GetDescription (strm, eDescriptionLevelFull, m_options.m_json))
- {
- result.AppendErrorWithFormat ("error displaying info for thread: \"%s\"\n", command.GetArgumentAtIndex(i));
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
-
- if (i < num_args - 1)
- result.AppendMessage("");
- }
-
- }
- return result.Succeeded();
+ return true;
}
CommandOptions m_options;
@@ -1958,6 +1925,228 @@
};
//-------------------------------------------------------------------------
+// Next are the subcommands of CommandObjectMultiwordThreadPlan
+//-------------------------------------------------------------------------
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadPlanList
+//-------------------------------------------------------------------------
+class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ // Keep default values of all options in one place: OptionParsingStarting ()
+ OptionParsingStarting ();
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'i':
+ {
+ m_internal = true;
+ }
+ break;
+ case 'v':
+ {
+ m_verbose = true;
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_verbose = false;
+ m_internal = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ bool m_verbose;
+ bool m_internal;
+ };
+
+ CommandObjectThreadPlanList (CommandInterpreter &interpreter) :
+ CommandObjectIterateOverThreads (interpreter,
+ "thread plan list",
+ "Show thread plans for one or more threads. If no threads are specified, show the "
+ "currently selected thread. Use the thread-index \"all\" to see all threads.",
+ NULL,
+ eFlagRequiresProcess |
+ eFlagRequiresThread |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_options(interpreter)
+ {
+ }
+
+ ~CommandObjectThreadPlanList ()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ HandleOneThread (Thread &thread, CommandReturnObject &result)
+ {
+ Stream &strm = result.GetOutputStream();
+ DescriptionLevel desc_level = eDescriptionLevelFull;
+ if (m_options.m_verbose)
+ desc_level = eDescriptionLevelVerbose;
+
+ thread.DumpThreadPlans (&strm, desc_level, m_options.m_internal, true);
+ return true;
+ }
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectThreadPlanList::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "verbose", 'v', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display more information about the thread plans"},
+{ LLDB_OPT_SET_1, false, "internal", 'i', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display internal as well as user thread plans"},
+{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
+};
+
+class CommandObjectThreadPlanDiscard : public CommandObjectParsed
+{
+public:
+ CommandObjectThreadPlanDiscard (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "thread plan discard",
+ "Discards thread plans up to and including the plan passed as the command argument."
+ "Only user visible plans can be discarded, use the index from \"thread plan list\""
+ " without the \"-i\" argument.",
+ NULL,
+ eFlagRequiresProcess |
+ eFlagRequiresThread |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused )
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData plan_index_arg;
+
+ // Define the first (and only) variant of this arg.
+ plan_index_arg.arg_type = eArgTypeUnsignedInteger;
+ plan_index_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (plan_index_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual ~CommandObjectThreadPlanDiscard () {}
+
+ bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ Thread *thread = m_exe_ctx.GetThreadPtr();
+ if (args.GetArgumentCount() != 1)
+ {
+ result.AppendErrorWithFormat("Too many arguments, expected one - the thread plan index - but got %zu.",
+ args.GetArgumentCount());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ bool success;
+ uint32_t thread_plan_idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), 0, 0, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat("Invalid thread index: \"%s\" - should be unsigned int.",
+ args.GetArgumentAtIndex(0));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (thread_plan_idx == 0)
+ {
+ result.AppendErrorWithFormat("You wouldn't really want me to discard the base thread plan.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (thread->DiscardUserThreadPlansUpToIndex(thread_plan_idx))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Could not find User thread plan with index %s.",
+ args.GetArgumentAtIndex(0));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordThreadPlan
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword
+{
+public:
+ CommandObjectMultiwordThreadPlan(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "plan",
+ "A set of subcommands for accessing the thread plans controlling execution control on one or more threads.",
+ "thread plan <subcommand> [<subcommand objects]")
+ {
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectThreadPlanList (interpreter)));
+ LoadSubCommand ("discard", CommandObjectSP (new CommandObjectThreadPlanDiscard (interpreter)));
+ }
+
+ virtual ~CommandObjectMultiwordThreadPlan () {}
+
+
+};
+
+//-------------------------------------------------------------------------
// CommandObjectMultiwordThread
//-------------------------------------------------------------------------
@@ -2014,6 +2203,16 @@
NULL,
eStepTypeTraceOver,
eStepScopeInstruction)));
+
+ LoadSubCommand ("step-scripted", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope (
+ interpreter,
+ "thread step-scripted",
+ "Step as instructed by the script class passed in the -C option.",
+ NULL,
+ eStepTypeScripted,
+ eStepScopeSource)));
+
+ LoadSubCommand ("plan", CommandObjectSP (new CommandObjectMultiwordThreadPlan(interpreter)));
}
CommandObjectMultiwordThread::~CommandObjectMultiwordThread ()
diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp
index 27afba2..5654e65 100644
--- a/lldb/source/Expression/ClangFunction.cpp
+++ b/lldb/source/Expression/ClangFunction.cpp
@@ -422,7 +422,7 @@
return true;
}
-ThreadPlan *
+lldb::ThreadPlanSP
ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx,
lldb::addr_t args_addr,
const EvaluateExpressionOptions &options,
@@ -447,14 +447,14 @@
lldb::addr_t args = { args_addr };
- ThreadPlan *new_plan = new ThreadPlanCallFunction (*thread,
+ lldb::ThreadPlanSP new_plan_sp (new ThreadPlanCallFunction (*thread,
wrapper_address,
ClangASTType(),
args,
- options);
- new_plan->SetIsMasterPlan(true);
- new_plan->SetOkayToDiscard (false);
- return new_plan;
+ options));
+ new_plan_sp->SetIsMasterPlan(true);
+ new_plan_sp->SetOkayToDiscard (false);
+ return new_plan_sp;
}
bool
@@ -541,10 +541,10 @@
if (log)
log->Printf("== [ClangFunction::ExecuteFunction] Executing function \"%s\" ==", m_name.c_str());
- lldb::ThreadPlanSP call_plan_sp (GetThreadPlanToCallFunction (exe_ctx,
- args_addr,
- real_options,
- errors));
+ lldb::ThreadPlanSP call_plan_sp = GetThreadPlanToCallFunction (exe_ctx,
+ args_addr,
+ real_options,
+ errors);
if (!call_plan_sp)
return lldb::eExpressionSetupError;
diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp
index 52ef4d3..dab7b55 100644
--- a/lldb/source/Expression/ClangUserExpression.cpp
+++ b/lldb/source/Expression/ClangUserExpression.cpp
@@ -885,17 +885,17 @@
args.push_back(struct_address);
- ThreadPlanCallUserExpression *user_expression_plan =
- new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(),
- wrapper_address,
- args,
- options,
- shared_ptr_to_me);
- lldb::ThreadPlanSP call_plan_sp(user_expression_plan);
+ lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(),
+ wrapper_address,
+ args,
+ options,
+ shared_ptr_to_me));
if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream))
return lldb::eExpressionSetupError;
+ ThreadPlanCallUserExpression *user_expression_plan = static_cast<ThreadPlanCallUserExpression *>(call_plan_sp.get());
+
lldb::addr_t function_stack_pointer = user_expression_plan->GetFunctionStackPointer();
function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize();
diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp
index b6c46f8..721eedb 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -131,7 +131,9 @@
SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread,
SWIGPythonScriptKeyword_Target swig_run_script_keyword_target,
SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame,
- SWIGPython_GetDynamicSetting swig_plugin_get)
+ SWIGPython_GetDynamicSetting swig_plugin_get,
+ SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script,
+ SWIGPythonCallThreadPlan swig_call_thread_plan)
{
#ifndef LLDB_DISABLE_PYTHON
ScriptInterpreterPython::InitializeInterpreter (python_swig_init_callback,
@@ -153,6 +155,8 @@
swig_run_script_keyword_thread,
swig_run_script_keyword_target,
swig_run_script_keyword_frame,
- swig_plugin_get);
+ swig_plugin_get,
+ swig_thread_plan_script,
+ swig_call_thread_plan);
#endif // #ifndef LLDB_DISABLE_PYTHON
}
diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp
index 1b24fea..945e869 100644
--- a/lldb/source/Interpreter/ScriptInterpreterPython.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp
@@ -37,6 +37,7 @@
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/PythonDataObjects.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
using namespace lldb;
using namespace lldb_private;
@@ -62,6 +63,8 @@
static ScriptInterpreter::SWIGPythonScriptKeyword_Target g_swig_run_script_keyword_target = nullptr;
static ScriptInterpreter::SWIGPythonScriptKeyword_Frame g_swig_run_script_keyword_frame = nullptr;
static ScriptInterpreter::SWIGPython_GetDynamicSetting g_swig_plugin_get = nullptr;
+static ScriptInterpreter::SWIGPythonCreateScriptedThreadPlan g_swig_thread_plan_script = nullptr;
+static ScriptInterpreter::SWIGPythonCallThreadPlan g_swig_call_thread_plan = nullptr;
static std::string
ReadPythonBacktrace (PyObject* py_backtrace);
@@ -1617,6 +1620,87 @@
}
lldb::ScriptInterpreterObjectSP
+ScriptInterpreterPython::CreateScriptedThreadPlan (const char *class_name,
+ lldb::ThreadPlanSP thread_plan_sp)
+{
+ if (class_name == nullptr || class_name[0] == '\0')
+ return lldb::ScriptInterpreterObjectSP();
+
+ if (!thread_plan_sp.get())
+ return lldb::ScriptInterpreterObjectSP();
+
+ Debugger &debugger = thread_plan_sp->GetTarget().GetDebugger();
+ ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter();
+ ScriptInterpreterPython *python_interpreter = static_cast<ScriptInterpreterPython *>(script_interpreter);
+
+ if (!script_interpreter)
+ return lldb::ScriptInterpreterObjectSP();
+
+ void* ret_val;
+
+ {
+ Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
+
+ ret_val = g_swig_thread_plan_script (class_name,
+ python_interpreter->m_dictionary_name.c_str(),
+ thread_plan_sp);
+ }
+
+ return MakeScriptObject(ret_val);
+}
+
+bool
+ScriptInterpreterPython::ScriptedThreadPlanExplainsStop (lldb::ScriptInterpreterObjectSP implementor_sp,
+ Event *event,
+ bool &script_error)
+{
+ bool explains_stop = true;
+ if (implementor_sp)
+ {
+ Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
+ explains_stop = g_swig_call_thread_plan (implementor_sp->GetObject(), "explains_stop", event, script_error);
+ if (script_error)
+ return true;
+ }
+ return explains_stop;
+}
+
+bool
+ScriptInterpreterPython::ScriptedThreadPlanShouldStop (lldb::ScriptInterpreterObjectSP implementor_sp,
+ Event *event,
+ bool &script_error)
+{
+ bool should_stop = true;
+ if (implementor_sp)
+ {
+ Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
+ should_stop = g_swig_call_thread_plan (implementor_sp->GetObject(), "should_stop", event, script_error);
+ if (script_error)
+ return true;
+ }
+ return should_stop;
+}
+
+lldb::StateType
+ScriptInterpreterPython::ScriptedThreadPlanGetRunState (lldb::ScriptInterpreterObjectSP implementor_sp,
+ bool &script_error)
+{
+ bool should_step = false;
+ if (implementor_sp)
+ {
+ Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
+ should_step = g_swig_call_thread_plan (implementor_sp->GetObject(), "should_step", NULL, script_error);
+ if (script_error)
+ should_step = true;
+ }
+ if (should_step)
+ return lldb::eStateStepping;
+ else
+ return lldb::eStateRunning;
+}
+
+
+lldb::ScriptInterpreterObjectSP
ScriptInterpreterPython::LoadPluginModule (const FileSpec& file_spec,
lldb_private::Error& error)
{
@@ -2536,7 +2620,9 @@
SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread,
SWIGPythonScriptKeyword_Target swig_run_script_keyword_target,
SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame,
- SWIGPython_GetDynamicSetting swig_plugin_get)
+ SWIGPython_GetDynamicSetting swig_plugin_get,
+ SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script,
+ SWIGPythonCallThreadPlan swig_call_thread_plan)
{
g_swig_init_callback = swig_init_callback;
g_swig_breakpoint_callback = swig_breakpoint_callback;
@@ -2558,6 +2644,8 @@
g_swig_run_script_keyword_target = swig_run_script_keyword_target;
g_swig_run_script_keyword_frame = swig_run_script_keyword_frame;
g_swig_plugin_get = swig_plugin_get;
+ g_swig_thread_plan_script = swig_thread_plan_script;
+ g_swig_call_thread_plan = swig_call_thread_plan;
}
void
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
index cdd5b46..fe364fa 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
@@ -89,10 +89,10 @@
options.SetIgnoreBreakpoints(true);
options.SetStopOthers(m_stop_others);
m_thread.CalculateExecutionContext(exc_ctx);
- m_func_sp.reset(m_impl_function->GetThreadPlanToCallFunction (exc_ctx,
- m_args_addr,
- options,
- errors));
+ m_func_sp = m_impl_function->GetThreadPlanToCallFunction (exc_ctx,
+ m_args_addr,
+ options,
+ errors);
m_func_sp->SetOkayToDiscard(true);
m_thread.QueueThreadPlan (m_func_sp, false);
}
diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
index 4a94457..7db83ae 100644
--- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
+++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -98,13 +98,11 @@
ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
lldb::addr_t args[] = { addr, length, prot_arg, flags_arg, fd, offset };
- ThreadPlanCallFunction *call_function_thread_plan
- = new ThreadPlanCallFunction (*thread,
- mmap_range.GetBaseAddress(),
- clang_void_ptr_type,
- args,
- options);
- lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
+ lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread,
+ mmap_range.GetBaseAddress(),
+ clang_void_ptr_type,
+ args,
+ options));
if (call_plan_sp)
{
StreamFile error_strm;
@@ -241,13 +239,11 @@
ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
- ThreadPlanCallFunction *call_function_thread_plan
- = new ThreadPlanCallFunction (*thread,
- *address,
- clang_void_ptr_type,
- llvm::ArrayRef<addr_t>(),
- options);
- lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
+ lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread,
+ *address,
+ clang_void_ptr_type,
+ llvm::ArrayRef<addr_t>(),
+ options));
if (call_plan_sp)
{
StreamString error_strm;
diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp
index f8ea250..30e0ffb 100644
--- a/lldb/source/Target/Thread.cpp
+++ b/lldb/source/Target/Thread.cpp
@@ -32,6 +32,7 @@
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanCallFunction.h"
#include "lldb/Target/ThreadPlanBase.h"
+#include "lldb/Target/ThreadPlanPython.h"
#include "lldb/Target/ThreadPlanStepInstruction.h"
#include "lldb/Target/ThreadPlanStepOut.h"
#include "lldb/Target/ThreadPlanStepOverBreakpoint.h"
@@ -652,17 +653,18 @@
if (cur_plan->GetKind() != ThreadPlan::eKindStepOverBreakpoint)
{
- ThreadPlanStepOverBreakpoint *step_bp_plan = new ThreadPlanStepOverBreakpoint (*this);
- if (step_bp_plan)
+ ThreadPlanSP step_bp_plan_sp (new ThreadPlanStepOverBreakpoint (*this));
+ if (step_bp_plan_sp)
{
- ThreadPlanSP step_bp_plan_sp;
- step_bp_plan->SetPrivate (true);
+ ;
+ step_bp_plan_sp->SetPrivate (true);
if (GetCurrentPlan()->RunState() != eStateStepping)
{
+ ThreadPlanStepOverBreakpoint *step_bp_plan
+ = static_cast<ThreadPlanStepOverBreakpoint *>(step_bp_plan_sp.get());
step_bp_plan->SetAutoContinue(true);
}
- step_bp_plan_sp.reset (step_bp_plan);
QueueThreadPlan (step_bp_plan_sp, false);
}
}
@@ -1290,6 +1292,36 @@
m_plan_stack[i]->SetThreadPlanTracer(tracer_sp);
}
+bool
+Thread::DiscardUserThreadPlansUpToIndex (uint32_t thread_index)
+{
+ // Count the user thread plans from the back end to get the number of the one we want
+ // to discard:
+
+ uint32_t idx = 0;
+ ThreadPlan *up_to_plan_ptr = nullptr;
+
+ for (ThreadPlanSP plan_sp : m_plan_stack)
+ {
+ if (plan_sp->GetPrivate())
+ continue;
+ if (idx == thread_index)
+ {
+ up_to_plan_ptr = plan_sp.get();
+ break;
+ }
+ else
+ idx++;
+ }
+
+ if (up_to_plan_ptr == nullptr)
+ return false;
+
+ DiscardThreadPlansUpToPlan(up_to_plan_ptr);
+ return true;
+}
+
+
void
Thread::DiscardThreadPlansUpToPlan (lldb::ThreadPlanSP &up_to_plan_sp)
{
@@ -1483,18 +1515,16 @@
LazyBool step_out_avoids_code_without_debug_info
)
{
- ThreadPlanSP thread_plan_sp;
- ThreadPlanStepInRange *plan = new ThreadPlanStepInRange (*this,
+ ThreadPlanSP thread_plan_sp (new ThreadPlanStepInRange (*this,
range,
addr_context,
stop_other_threads,
step_in_avoids_code_without_debug_info,
- step_out_avoids_code_without_debug_info);
+ step_out_avoids_code_without_debug_info));
+ ThreadPlanStepInRange *plan = static_cast<ThreadPlanStepInRange *>(thread_plan_sp.get());
if (step_in_target)
plan->SetStepInTarget(step_in_target);
-
- thread_plan_sp.reset (plan);
QueueThreadPlan (thread_plan_sp, abort_other_plans);
return thread_plan_sp;
@@ -1546,17 +1576,18 @@
uint32_t frame_idx
)
{
- ThreadPlanStepOut *new_plan = new ThreadPlanStepOut (*this,
+ ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut (*this,
addr_context,
first_insn,
stop_other_threads,
stop_vote,
run_vote,
frame_idx,
- eLazyBoolNo);
+ eLazyBoolNo));
+
+ ThreadPlanStepOut *new_plan = static_cast<ThreadPlanStepOut *>(thread_plan_sp.get());
new_plan->ClearShouldStopHereCallbacks();
- ThreadPlanSP thread_plan_sp(new_plan);
-
+
if (thread_plan_sp->ValidatePlan(NULL))
{
QueueThreadPlan (thread_plan_sp, abort_other_plans);
@@ -1602,61 +1633,105 @@
}
+lldb::ThreadPlanSP
+Thread::QueueThreadPlanForStepScripted (bool abort_other_plans,
+ const char *class_name,
+ bool stop_other_threads)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanPython (*this, class_name));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ // This seems a little funny, but I don't want to have to split up the constructor and the
+ // DidPush in the scripted plan, that seems annoying.
+ // That means the constructor has to be in DidPush.
+ // So I have to validate the plan AFTER pushing it, and then take it off again...
+ if (!thread_plan_sp->ValidatePlan(nullptr))
+ {
+ DiscardThreadPlansUpToPlan(thread_plan_sp);
+ return ThreadPlanSP();
+ }
+ else
+ return thread_plan_sp;
+
+}
+
uint32_t
Thread::GetIndexID () const
{
return m_index_id;
}
-void
-Thread::DumpThreadPlans (lldb_private::Stream *s) const
+static void
+PrintPlanElement (Stream *s, const ThreadPlanSP &plan, lldb::DescriptionLevel desc_level, int32_t elem_idx)
{
- uint32_t stack_size = m_plan_stack.size();
- int i;
- s->Indent();
- s->Printf ("Plan Stack for thread #%u: tid = 0x%4.4" PRIx64 ", stack_size = %d\n", GetIndexID(), GetID(), stack_size);
- for (i = stack_size - 1; i >= 0; i--)
- {
s->IndentMore();
s->Indent();
- s->Printf ("Element %d: ", i);
- m_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
+ s->Printf ("Element %d: ", elem_idx);
+ plan->GetDescription (s, desc_level);
s->EOL();
s->IndentLess();
+}
+
+static void
+PrintPlanStack (Stream *s, const std::vector<lldb::ThreadPlanSP> &plan_stack, lldb::DescriptionLevel desc_level, bool include_internal)
+{
+ int32_t print_idx = 0;
+ for (ThreadPlanSP plan_sp : plan_stack)
+ {
+ if (include_internal || !plan_sp->GetPrivate())
+ {
+ PrintPlanElement (s, plan_sp, desc_level, print_idx++);
+ }
}
+}
+
+void
+Thread::DumpThreadPlans (Stream *s,
+ lldb::DescriptionLevel desc_level,
+ bool include_internal,
+ bool ignore_boring_threads) const
+{
+ uint32_t stack_size = m_plan_stack.size();
+
+ if (ignore_boring_threads)
+ {
+ uint32_t stack_size = m_plan_stack.size();
+ uint32_t completed_stack_size = m_completed_plan_stack.size();
+ uint32_t discarded_stack_size = m_discarded_plan_stack.size();
+ if (stack_size == 1 && completed_stack_size == 0 && discarded_stack_size == 0)
+ {
+ s->Printf ("thread #%u: tid = 0x%4.4" PRIx64 "\n", GetIndexID(), GetID());
+ s->IndentMore();
+ s->Indent();
+ s->Printf("No active thread plans\n");
+ s->IndentLess();
+ return;
+ }
+ }
+
+ s->Indent();
+ s->Printf ("thread #%u: tid = 0x%4.4" PRIx64 ":\n", GetIndexID(), GetID());
+ s->IndentMore();
+ s->Indent();
+ s->Printf ("Active plan stack:\n");
+ PrintPlanStack (s, m_plan_stack, desc_level, include_internal);
stack_size = m_completed_plan_stack.size();
if (stack_size > 0)
{
s->Indent();
- s->Printf ("Completed Plan Stack: %d elements.\n", stack_size);
- for (i = stack_size - 1; i >= 0; i--)
- {
- s->IndentMore();
- s->Indent();
- s->Printf ("Element %d: ", i);
- m_completed_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
- s->EOL();
- s->IndentLess();
- }
+ s->Printf ("Completed Plan Stack:\n");
+ PrintPlanStack (s, m_completed_plan_stack, desc_level, include_internal);
}
stack_size = m_discarded_plan_stack.size();
if (stack_size > 0)
{
s->Indent();
- s->Printf ("Discarded Plan Stack: %d elements.\n", stack_size);
- for (i = stack_size - 1; i >= 0; i--)
- {
- s->IndentMore();
- s->Indent();
- s->Printf ("Element %d: ", i);
- m_discarded_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
- s->EOL();
- s->IndentLess();
- }
+ s->Printf ("Discarded Plan Stack:\n");
+ PrintPlanStack (s, m_discarded_plan_stack, desc_level, include_internal);
}
+ s->IndentLess();
}
TargetSP
diff --git a/lldb/source/Target/ThreadPlanPython.cpp b/lldb/source/Target/ThreadPlanPython.cpp
new file mode 100644
index 0000000..e196d81
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanPython.cpp
@@ -0,0 +1,192 @@
+//===-- ThreadPlan.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/lldb-python.h"
+
+#include "lldb/Target/ThreadPlan.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanPython.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanPython
+//----------------------------------------------------------------------
+
+ThreadPlanPython::ThreadPlanPython (Thread &thread, const char *class_name) :
+ ThreadPlan (ThreadPlan::eKindPython,
+ "Python based Thread Plan",
+ thread,
+ eVoteNoOpinion,
+ eVoteNoOpinion),
+ m_class_name (class_name)
+{
+ SetIsMasterPlan (true);
+ SetOkayToDiscard (true);
+ SetPrivate (false);
+}
+
+ThreadPlanPython::~ThreadPlanPython ()
+{
+ // FIXME, do I need to decrement the ref count on this implementation object to make it go away?
+}
+
+bool
+ThreadPlanPython::ValidatePlan (Stream *error)
+{
+ // I have to postpone setting up the implementation till after the constructor because I need to call
+ // shared_from_this, which you can't do in the constructor. So I'll do it here.
+ if (m_implementation_sp)
+ return true;
+ else
+ return false;
+}
+
+void
+ThreadPlanPython::DidPush()
+{
+ // We set up the script side in DidPush, so that it can push other plans in the constructor,
+ // and doesn't have to care about the details of DidPush.
+
+ if (!m_class_name.empty())
+ {
+ ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (script_interp)
+ {
+ m_implementation_sp = script_interp->CreateScriptedThreadPlan (m_class_name.c_str(), this->shared_from_this());
+ }
+ }
+}
+
+bool
+ThreadPlanPython::ShouldStop (Event *event_ptr)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("%s called on Python Thread Plan: %s )",
+ __PRETTY_FUNCTION__, m_class_name.c_str());
+
+ bool should_stop = true;
+ if (m_implementation_sp)
+ {
+ ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (script_interp)
+ {
+ bool script_error;
+ should_stop = script_interp->ScriptedThreadPlanShouldStop (m_implementation_sp, event_ptr, script_error);
+ if (script_error)
+ SetPlanComplete(false);
+ }
+ }
+ return should_stop;
+}
+
+bool
+ThreadPlanPython::DoPlanExplainsStop (Event *event_ptr)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("%s called on Python Thread Plan: %s )",
+ __PRETTY_FUNCTION__, m_class_name.c_str());
+
+ bool explains_stop = true;
+ if (m_implementation_sp)
+ {
+ ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (script_interp)
+ {
+ bool script_error;
+ explains_stop = script_interp->ScriptedThreadPlanExplainsStop (m_implementation_sp, event_ptr, script_error);
+ if (script_error)
+ SetPlanComplete(false);
+ }
+ }
+ return explains_stop;
+}
+
+bool
+ThreadPlanPython::MischiefManaged ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("%s called on Python Thread Plan: %s )",
+ __PRETTY_FUNCTION__, m_class_name.c_str());
+ bool mischief_managed = true;
+ if (m_implementation_sp)
+ {
+ // I don't really need mischief_managed, since it's simpler to just call SetPlanComplete in should_stop.
+ mischief_managed = IsPlanComplete();
+ if (mischief_managed)
+ m_implementation_sp.reset();
+ }
+ return mischief_managed;
+}
+
+lldb::StateType
+ThreadPlanPython::GetPlanRunState ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("%s called on Python Thread Plan: %s )",
+ __PRETTY_FUNCTION__,
+ m_class_name.c_str());
+ lldb::StateType run_state = eStateRunning;
+ if (m_implementation_sp)
+ {
+ ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (script_interp)
+ {
+ bool script_error;
+ run_state = script_interp->ScriptedThreadPlanGetRunState (m_implementation_sp, script_error);
+ }
+ }
+ return run_state;
+}
+
+// The ones below are not currently exported to Python.
+
+bool
+ThreadPlanPython::StopOthers ()
+{
+ // For now Python plans run all threads, but we should add some controls for this.
+ return false;
+}
+
+void
+ThreadPlanPython::GetDescription (Stream *s,
+ lldb::DescriptionLevel level)
+{
+ s->Printf ("Python thread plan implemented by class %s.", m_class_name.c_str());
+}
+
+bool
+ThreadPlanPython::WillStop ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("%s called on Python Thread Plan: %s )",
+ __PRETTY_FUNCTION__, m_class_name.c_str());
+ return true;
+}
diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp
index 3e9abef..1e7b045 100644
--- a/lldb/source/Target/ThreadPlanStepInRange.cpp
+++ b/lldb/source/Target/ThreadPlanStepInRange.cpp
@@ -128,17 +128,31 @@
ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
if (level == lldb::eDescriptionLevelBrief)
- s->Printf("step in");
- else
{
- s->Printf ("Stepping through range (stepping into functions): ");
- DumpRanges(s);
- const char *step_into_target = m_step_into_target.AsCString();
- if (step_into_target && step_into_target[0] != '\0')
- s->Printf (" targeting %s.", m_step_into_target.AsCString());
- else
- s->PutChar('.');
+ s->Printf("step in");
+ return;
}
+
+ s->Printf ("Stepping in");
+ bool printed_line_info = false;
+ if (m_addr_context.line_entry.IsValid())
+ {
+ s->Printf (" through line ");
+ m_addr_context.line_entry.DumpStopContext (s, false);
+ printed_line_info = true;
+ }
+
+ const char *step_into_target = m_step_into_target.AsCString();
+ if (step_into_target && step_into_target[0] != '\0')
+ s->Printf (" targeting %s", m_step_into_target.AsCString());
+
+ if (!printed_line_info || level == eDescriptionLevelVerbose)
+ {
+ s->Printf (" using ranges:");
+ DumpRanges(s);
+ }
+
+ s->PutChar('.');
}
bool
@@ -303,6 +317,7 @@
else
{
m_no_more_plans = false;
+ m_sub_plan_sp->SetPrivate(true);
return false;
}
}
diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp
index b62f557..0ded99b 100644
--- a/lldb/source/Target/ThreadPlanStepOut.cpp
+++ b/lldb/source/Target/ThreadPlanStepOut.cpp
@@ -54,7 +54,6 @@
m_return_addr (LLDB_INVALID_ADDRESS),
m_stop_others (stop_others),
m_immediate_step_from_function(NULL)
-
{
SetFlagsToDefault();
SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
@@ -90,6 +89,7 @@
frame_idx - 1,
eLazyBoolNo));
static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get())->SetShouldStopHereCallbacks(nullptr, nullptr);
+ m_step_out_to_inline_plan_sp->SetPrivate(true);
}
else
{
@@ -177,10 +177,34 @@
else if (m_step_through_inline_plan_sp)
s->Printf ("Stepping out by stepping through inlined function.");
else
- s->Printf ("Stepping out from address 0x%" PRIx64 " to return address 0x%" PRIx64 " using breakpoint site %d",
- (uint64_t)m_step_from_insn,
- (uint64_t)m_return_addr,
- m_return_bp_id);
+ {
+ s->Printf ("Stepping out from ");
+ Address tmp_address;
+ if (tmp_address.SetLoadAddress (m_step_from_insn, &GetTarget()))
+ {
+ tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, Address::DumpStyleLoadAddress);
+ }
+ else
+ {
+ s->Printf ("address 0x%" PRIx64 "", (uint64_t)m_step_from_insn);
+ }
+
+ // FIXME: find some useful way to present the m_return_id, since there may be multiple copies of the
+ // same function on the stack.
+
+ s->Printf ("returning to frame at ");
+ if (tmp_address.SetLoadAddress (m_return_addr, &GetTarget()))
+ {
+ tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, Address::DumpStyleLoadAddress);
+ }
+ else
+ {
+ s->Printf ("address 0x%" PRIx64 "", (uint64_t)m_return_addr);
+ }
+
+ if (level == eDescriptionLevelVerbose)
+ s->Printf(" using breakpoint site %d", m_return_bp_id);
+ }
}
}
@@ -474,11 +498,16 @@
inlined_sc.target_sp = GetTarget().shared_from_this();
RunMode run_mode = m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads;
const LazyBool avoid_no_debug = eLazyBoolNo;
- ThreadPlanStepOverRange *step_through_inline_plan_ptr = new ThreadPlanStepOverRange(m_thread,
- inline_range,
- inlined_sc,
- run_mode,
- avoid_no_debug);
+
+ m_step_through_inline_plan_sp.reset (new ThreadPlanStepOverRange(m_thread,
+ inline_range,
+ inlined_sc,
+ run_mode,
+ avoid_no_debug));
+ ThreadPlanStepOverRange *step_through_inline_plan_ptr
+ = static_cast<ThreadPlanStepOverRange *>(m_step_through_inline_plan_sp.get());
+ m_step_through_inline_plan_sp->SetPrivate(true);
+
step_through_inline_plan_ptr->SetOkayToDiscard(true);
StreamString errors;
if (!step_through_inline_plan_ptr->ValidatePlan(&errors))
@@ -493,7 +522,7 @@
if (inlined_block->GetRangeAtIndex (i, inline_range))
step_through_inline_plan_ptr->AddRange (inline_range);
}
- m_step_through_inline_plan_sp.reset (step_through_inline_plan_ptr);
+
if (queue_now)
m_thread.QueueThreadPlan (m_step_through_inline_plan_sp, false);
return true;
diff --git a/lldb/source/Target/ThreadPlanStepOverRange.cpp b/lldb/source/Target/ThreadPlanStepOverRange.cpp
index a4f3743..a6d65e4 100644
--- a/lldb/source/Target/ThreadPlanStepOverRange.cpp
+++ b/lldb/source/Target/ThreadPlanStepOverRange.cpp
@@ -62,12 +62,26 @@
ThreadPlanStepOverRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
if (level == lldb::eDescriptionLevelBrief)
- s->Printf("step over");
- else
{
- s->Printf ("stepping through range (stepping over functions): ");
- DumpRanges(s);
+ s->Printf("step over");
+ return;
}
+ s->Printf ("Stepping over");
+ bool printed_line_info = false;
+ if (m_addr_context.line_entry.IsValid())
+ {
+ s->Printf (" line ");
+ m_addr_context.line_entry.DumpStopContext (s, false);
+ printed_line_info = true;
+ }
+
+ if (!printed_line_info || level == eDescriptionLevelVerbose)
+ {
+ s->Printf (" using ranges: ");
+ DumpRanges(s);
+ }
+
+ s->PutChar('.');
}
void
@@ -317,11 +331,15 @@
{
new_plan_sp = CheckShouldStopHereAndQueueStepOut (frame_order);
}
-
+
if (!new_plan_sp)
m_no_more_plans = true;
else
+ {
+ // Any new plan will be an implementation plan, so mark it private:
+ new_plan_sp->SetPrivate(true);
m_no_more_plans = false;
+ }
if (!new_plan_sp)
{
diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp
index 82ca59f..adc515c 100644
--- a/lldb/source/Target/ThreadPlanStepRange.cpp
+++ b/lldb/source/Target/ThreadPlanStepRange.cpp
@@ -44,7 +44,8 @@
Thread &thread,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_others) :
+ lldb::RunMode stop_others,
+ bool given_ranges_only) :
ThreadPlan (kind, name, thread, eVoteNoOpinion, eVoteNoOpinion),
m_addr_context (addr_context),
m_address_ranges (),
@@ -53,7 +54,8 @@
m_parent_stack_id(),
m_no_more_plans (false),
m_first_run_event (true),
- m_use_fast_step(false)
+ m_use_fast_step(false),
+ m_given_ranges_only (given_ranges_only)
{
m_use_fast_step = GetTarget().GetUseFastStepping();
AddRange(range);
@@ -149,7 +151,7 @@
break;
}
- if (!ret_value)
+ if (!ret_value && !m_given_ranges_only)
{
// See if we've just stepped to another part of the same line number...
StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get();