summaryrefslogtreecommitdiffstats
path: root/lldb/source/Target
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2010-06-08 16:52:24 +0000
committerChris Lattner <sabre@nondot.org>2010-06-08 16:52:24 +0000
commit30fdc8d841c9d24ac5f3d452b6ece84ee0ac991c (patch)
treef70013106f6a461a14abcd71c65f48a95a2979a6 /lldb/source/Target
parent312c4c799da215b337f790fda330f70c4aa757cf (diff)
downloadbcm5719-llvm-30fdc8d841c9d24ac5f3d452b6ece84ee0ac991c.tar.gz
bcm5719-llvm-30fdc8d841c9d24ac5f3d452b6ece84ee0ac991c.zip
Initial checkin of lldb code from internal Apple repo.
llvm-svn: 105619
Diffstat (limited to 'lldb/source/Target')
-rw-r--r--lldb/source/Target/ABI.cpp47
-rw-r--r--lldb/source/Target/ExecutionContext.cpp107
-rw-r--r--lldb/source/Target/ObjCObjectPrinter.cpp120
-rw-r--r--lldb/source/Target/PathMappingList.cpp125
-rw-r--r--lldb/source/Target/Process.cpp1876
-rw-r--r--lldb/source/Target/RegisterContext.cpp238
-rw-r--r--lldb/source/Target/StackFrame.cpp393
-rw-r--r--lldb/source/Target/StackFrameList.cpp135
-rw-r--r--lldb/source/Target/StackID.cpp110
-rw-r--r--lldb/source/Target/Target.cpp707
-rw-r--r--lldb/source/Target/TargetList.cpp342
-rw-r--r--lldb/source/Target/Thread.cpp1121
-rw-r--r--lldb/source/Target/ThreadList.cpp460
-rw-r--r--lldb/source/Target/ThreadPlan.cpp185
-rw-r--r--lldb/source/Target/ThreadPlanBase.cpp202
-rw-r--r--lldb/source/Target/ThreadPlanCallFunction.cpp250
-rw-r--r--lldb/source/Target/ThreadPlanContinue.cpp120
-rw-r--r--lldb/source/Target/ThreadPlanRunToAddress.cpp176
-rw-r--r--lldb/source/Target/ThreadPlanShouldStopHere.cpp53
-rw-r--r--lldb/source/Target/ThreadPlanStepInRange.cpp154
-rw-r--r--lldb/source/Target/ThreadPlanStepInstruction.cpp191
-rw-r--r--lldb/source/Target/ThreadPlanStepOut.cpp228
-rw-r--r--lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp130
-rw-r--r--lldb/source/Target/ThreadPlanStepOverRange.cpp119
-rw-r--r--lldb/source/Target/ThreadPlanStepRange.cpp263
-rw-r--r--lldb/source/Target/ThreadPlanStepThrough.cpp137
-rw-r--r--lldb/source/Target/ThreadPlanStepUntil.cpp360
-rw-r--r--lldb/source/Target/UnixSignals.cpp310
28 files changed, 8659 insertions, 0 deletions
diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp
new file mode 100644
index 00000000000..20d35e3dbb0
--- /dev/null
+++ b/lldb/source/Target/ABI.cpp
@@ -0,0 +1,47 @@
+//===-- ABI.cpp -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/ABI.h"
+#include "lldb/Core/PluginManager.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ABI*
+ABI::FindPlugin (const ConstString &triple)
+{
+ std::auto_ptr<ABI> abi_ap;
+ ABICreateInstance create_callback;
+
+ for (uint32_t idx = 0;
+ (create_callback = PluginManager::GetABICreateCallbackAtIndex(idx)) != NULL;
+ ++idx)
+ {
+ abi_ap.reset (create_callback(triple));
+
+ if (abi_ap.get())
+ return abi_ap.release();
+ }
+
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+ABI::ABI()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ABI::~ABI()
+{
+}
diff --git a/lldb/source/Target/ExecutionContext.cpp b/lldb/source/Target/ExecutionContext.cpp
new file mode 100644
index 00000000000..e79f8c243ef
--- /dev/null
+++ b/lldb/source/Target/ExecutionContext.cpp
@@ -0,0 +1,107 @@
+//===-- ExecutionContext.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//
+
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb_private;
+
+ExecutionContext::ExecutionContext() :
+ target (NULL),
+ process (NULL),
+ thread (NULL),
+ frame (NULL)
+{
+}
+
+ExecutionContext::ExecutionContext (Target* t, bool fill_current_process_thread_frame) :
+ target (t),
+ process (NULL),
+ thread (NULL),
+ frame (NULL)
+{
+ if (t && fill_current_process_thread_frame)
+ {
+ process = t->GetProcessSP().get();
+ if (process)
+ {
+ thread = process->GetThreadList().GetCurrentThread().get();
+ if (thread)
+ frame = thread->GetCurrentFrame().get();
+ }
+ }
+}
+
+ExecutionContext::ExecutionContext(Process* p, Thread *t, StackFrame *f) :
+ target (p ? &p->GetTarget() : NULL),
+ process (p),
+ thread (t),
+ frame (f)
+{
+}
+
+ExecutionContext::ExecutionContext (ExecutionContextScope *exe_scope_ptr)
+{
+ if (exe_scope_ptr)
+ exe_scope_ptr->Calculate (*this);
+ else
+ {
+ target = NULL;
+ process = NULL;
+ thread = NULL;
+ frame = NULL;
+ }
+}
+
+ExecutionContext::ExecutionContext (ExecutionContextScope &exe_scope_ref)
+{
+ exe_scope_ref.Calculate (*this);
+}
+
+void
+ExecutionContext::Clear()
+{
+ target = NULL;
+ process = NULL;
+ thread = NULL;
+ frame = NULL;
+}
+
+
+RegisterContext *
+ExecutionContext::GetRegisterContext () const
+{
+ if (frame)
+ return frame->GetRegisterContext();
+ else if (thread)
+ return thread->GetRegisterContext();
+ return NULL;
+}
+
+ExecutionContextScope *
+ExecutionContext::GetBestExecutionContextScope () const
+{
+ if (frame)
+ return frame;
+ if (thread)
+ return thread;
+ if (process)
+ return process;
+ return target;
+}
diff --git a/lldb/source/Target/ObjCObjectPrinter.cpp b/lldb/source/Target/ObjCObjectPrinter.cpp
new file mode 100644
index 00000000000..81c73aa9581
--- /dev/null
+++ b/lldb/source/Target/ObjCObjectPrinter.cpp
@@ -0,0 +1,120 @@
+//===-- ObjCObjectPrinter.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/StreamString.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "ObjCObjectPrinter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ObjCObjectPrinter constructor
+//----------------------------------------------------------------------
+ObjCObjectPrinter::ObjCObjectPrinter (Process &process) :
+ m_process(process)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ObjCObjectPrinter::~ObjCObjectPrinter ()
+{
+}
+
+bool
+ObjCObjectPrinter::PrintObject (ConstString &str, Value &object_ptr, ExecutionContext &exe_ctx)
+{
+ if (!exe_ctx.process)
+ return false;
+
+ const Address *function_address = GetPrintForDebuggerAddr();
+
+ if (!function_address)
+ return false;
+
+ const char *target_triple = exe_ctx.process->GetTargetTriple().GetCString();
+ ClangASTContext *ast_context = exe_ctx.target->GetScratchClangASTContext();
+
+ void *return_qualtype = ast_context->GetCStringType(true);
+ Value ret;
+ ret.SetContext(Value::eContextTypeOpaqueClangQualType, return_qualtype);
+
+ ValueList arg_value_list;
+ arg_value_list.PushValue(object_ptr);
+
+ ClangFunction func(target_triple, ast_context, return_qualtype, *function_address, arg_value_list);
+ StreamString error_stream;
+
+ lldb::addr_t wrapper_struct_addr = LLDB_INVALID_ADDRESS;
+ func.InsertFunction(exe_ctx, wrapper_struct_addr, error_stream);
+ // FIXME: Check result of ExecuteFunction.
+ func.ExecuteFunction(exe_ctx, &wrapper_struct_addr, error_stream, true, 1000, true, ret);
+
+ addr_t result_ptr = ret.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+
+ // poor man's strcpy
+
+ size_t len = 0;
+ bool keep_reading = true;
+ Error error;
+ while (keep_reading)
+ {
+ char byte;
+
+ if (exe_ctx.process->ReadMemory(result_ptr + len, &byte, 1, error) != 1)
+ return false;
+
+ if (byte == '\0')
+ keep_reading = false;
+ else
+ ++len;
+ }
+
+ char desc[len + 1];
+
+ if (exe_ctx.process->ReadMemory(result_ptr, &desc[0], len + 1, error) != len + 1)
+ return false;
+
+ str.SetCString(desc);
+
+ return true;
+}
+
+Address *
+ObjCObjectPrinter::GetPrintForDebuggerAddr()
+{
+ if (!m_PrintForDebugger_addr.get())
+ {
+ ModuleList &modules = m_process.GetTarget().GetImages();
+
+ SymbolContextList contexts;
+ SymbolContext context;
+
+ if((!modules.FindSymbolsWithNameAndType(ConstString ("_NSPrintForDebugger"), eSymbolTypeCode, contexts)) &&
+ (!modules.FindSymbolsWithNameAndType(ConstString ("_CFPrintForDebugger"), eSymbolTypeCode, contexts)))
+ return NULL;
+
+ contexts.GetContextAtIndex(0, context);
+
+ m_PrintForDebugger_addr.reset(new Address(context.symbol->GetValue()));
+ }
+
+ return m_PrintForDebugger_addr.get();
+}
+
diff --git a/lldb/source/Target/PathMappingList.cpp b/lldb/source/Target/PathMappingList.cpp
new file mode 100644
index 00000000000..02ca0671ca0
--- /dev/null
+++ b/lldb/source/Target/PathMappingList.cpp
@@ -0,0 +1,125 @@
+//===-- PathMappingList.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+// Project includes
+#include "PathMappingList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// PathMappingList constructor
+//----------------------------------------------------------------------
+PathMappingList::PathMappingList
+(
+ ChangedCallback callback,
+ void *callback_baton
+) :
+ m_pairs (),
+ m_callback (callback),
+ m_callback_baton (callback_baton)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+PathMappingList::~PathMappingList ()
+{
+}
+
+void
+PathMappingList::Append (const ConstString &path,
+ const ConstString &replacement,
+ bool notify)
+{
+ m_pairs.push_back(pair(path, replacement));
+ if (notify && m_callback)
+ m_callback (*this, m_callback_baton);
+}
+
+void
+PathMappingList::Insert (const ConstString &path,
+ const ConstString &replacement,
+ uint32_t index,
+ bool notify)
+{
+ iterator insert_iter;
+ if (index >= m_pairs.size())
+ insert_iter = m_pairs.end();
+ else
+ insert_iter = m_pairs.begin() + index;
+ m_pairs.insert(insert_iter, pair(path, replacement));
+ if (notify && m_callback)
+ m_callback (*this, m_callback_baton);
+}
+
+bool
+PathMappingList::Remove (off_t index, bool notify)
+{
+ if (index >= m_pairs.size())
+ return false;
+
+ iterator iter = m_pairs.begin() + index;
+ m_pairs.erase(iter);
+ if (notify && m_callback)
+ m_callback (*this, m_callback_baton);
+ return true;
+}
+
+void
+PathMappingList::Dump (Stream *s)
+{
+ unsigned int numPairs = m_pairs.size();
+ unsigned int index;
+
+ for (index = 0; index < numPairs; ++index)
+ {
+ s->Printf("[%d] \"%s\" -> \"%s\"\n",
+ index, m_pairs[index].first.GetCString(), m_pairs[index].second.GetCString());
+ }
+}
+
+void
+PathMappingList::Clear (bool notify)
+{
+ m_pairs.clear();
+ if (notify && m_callback)
+ m_callback (*this, m_callback_baton);
+}
+
+size_t
+PathMappingList::GetSize ()
+{
+ return m_pairs.size();
+}
+
+bool
+PathMappingList::RemapPath (const ConstString &path, ConstString &new_path)
+{
+ const_iterator pos, end = m_pairs.end();
+ for (pos = m_pairs.begin(); pos != end; ++pos)
+ {
+ const size_t prefixLen = pos->first.GetLength();
+
+ if (::strncmp (pos->first.GetCString(), path.GetCString(), prefixLen) == 0)
+ {
+ std::string new_path_str (pos->second.GetCString());
+ new_path_str.append(path.GetCString() + prefixLen);
+ new_path.SetCString(new_path_str.c_str());
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
new file mode 100644
index 00000000000..9a6ab0c83e8
--- /dev/null
+++ b/lldb/source/Target/Process.cpp
@@ -0,0 +1,1876 @@
+//===-- Process.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/Process.h"
+
+#include "lldb/lldb-private-log.h"
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/TargetList.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Process*
+Process::FindPlugin (Target &target, const char *plugin_name, Listener &listener)
+{
+ ProcessCreateInstance create_callback = NULL;
+ if (plugin_name)
+ {
+ create_callback = PluginManager::GetProcessCreateCallbackForPluginName (plugin_name);
+ if (create_callback)
+ {
+ std::auto_ptr<Process> debugger_ap(create_callback(target, listener));
+ if (debugger_ap->CanDebug(target))
+ return debugger_ap.release();
+ }
+ }
+ else
+ {
+ for (uint32_t idx = 0; create_callback = PluginManager::GetProcessCreateCallbackAtIndex(idx); ++idx)
+ {
+ create_callback = PluginManager::GetProcessCreateCallbackAtIndex (idx);
+ if (create_callback)
+ {
+ std::auto_ptr<Process> debugger_ap(create_callback(target, listener));
+ if (debugger_ap->CanDebug(target))
+ return debugger_ap.release();
+ }
+ }
+ }
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Process constructor
+//----------------------------------------------------------------------
+Process::Process(Target &target, Listener &listener) :
+ UserID (LLDB_INVALID_PROCESS_ID),
+ Broadcaster ("Process"),
+ m_target (target),
+ m_section_load_info (),
+ m_public_state (eStateUnloaded),
+ m_private_state (eStateUnloaded),
+ m_private_state_broadcaster ("lldb.process.internal_state_broadcaster"),
+ m_private_state_control_broadcaster ("lldb.process.internal_state_control_broadcaster"),
+ m_private_state_listener ("lldb.process.internal_state_listener"),
+ m_private_state_control_wait(),
+ m_private_state_thread (LLDB_INVALID_HOST_THREAD),
+ m_stop_id (0),
+ m_thread_index_id (0),
+ m_exit_status (-1),
+ m_exit_string (),
+ m_thread_list (this),
+ m_notifications (),
+ m_listener(listener),
+ m_unix_signals (),
+ m_objc_object_printer(*this)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT);
+ if (log)
+ log->Printf ("%p Process::Process()", this);
+
+ listener.StartListeningForEvents (this,
+ eBroadcastBitStateChanged |
+ eBroadcastBitInterrupt |
+ eBroadcastBitSTDOUT |
+ eBroadcastBitSTDERR);
+
+ m_private_state_listener.StartListeningForEvents(&m_private_state_broadcaster,
+ eBroadcastBitStateChanged);
+
+ m_private_state_listener.StartListeningForEvents(&m_private_state_control_broadcaster,
+ eBroadcastInternalStateControlStop |
+ eBroadcastInternalStateControlPause |
+ eBroadcastInternalStateControlResume);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Process::~Process()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT);
+ if (log)
+ log->Printf ("%p Process::~Process()", this);
+ StopPrivateStateThread();
+}
+
+void
+Process::Finalize()
+{
+ // Do any cleanup needed prior to being destructed... Subclasses
+ // that override this method should call this superclass method as well.
+}
+
+void
+Process::RegisterNotificationCallbacks (const Notifications& callbacks)
+{
+ m_notifications.push_back(callbacks);
+ if (callbacks.initialize != NULL)
+ callbacks.initialize (callbacks.baton, this);
+}
+
+bool
+Process::UnregisterNotificationCallbacks(const Notifications& callbacks)
+{
+ std::vector<Notifications>::iterator pos, end = m_notifications.end();
+ for (pos = m_notifications.begin(); pos != end; ++pos)
+ {
+ if (pos->baton == callbacks.baton &&
+ pos->initialize == callbacks.initialize &&
+ pos->process_state_changed == callbacks.process_state_changed)
+ {
+ m_notifications.erase(pos);
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+Process::SynchronouslyNotifyStateChanged (StateType state)
+{
+ std::vector<Notifications>::iterator notification_pos, notification_end = m_notifications.end();
+ for (notification_pos = m_notifications.begin(); notification_pos != notification_end; ++notification_pos)
+ {
+ if (notification_pos->process_state_changed)
+ notification_pos->process_state_changed (notification_pos->baton, this, state);
+ }
+}
+
+// FIXME: We need to do some work on events before the general Listener sees them.
+// For instance if we are continuing from a breakpoint, we need to ensure that we do
+// the little "insert real insn, step & stop" trick. But we can't do that when the
+// event is delivered by the broadcaster - since that is done on the thread that is
+// waiting for new events, so if we needed more than one event for our handling, we would
+// stall. So instead we do it when we fetch the event off of the queue.
+//
+
+StateType
+Process::GetNextEvent (EventSP &event_sp)
+{
+ StateType state = eStateInvalid;
+
+ if (m_listener.GetNextEventForBroadcaster (this, event_sp) && event_sp)
+ state = Process::ProcessEventData::GetStateFromEvent (event_sp.get());
+
+ return state;
+}
+
+
+StateType
+Process::WaitForProcessToStop (const TimeValue *timeout)
+{
+ StateType match_states[] = { eStateStopped, eStateCrashed, eStateDetached, eStateExited, eStateUnloaded };
+ return WaitForState (timeout, match_states, sizeof(match_states) / sizeof(StateType));
+}
+
+
+StateType
+Process::WaitForState
+(
+ const TimeValue *timeout,
+ const StateType *match_states, const uint32_t num_match_states
+)
+{
+ EventSP event_sp;
+ uint32_t i;
+ StateType state = eStateUnloaded;
+ while (state != eStateInvalid)
+ {
+ state = WaitForStateChangedEvents (timeout, event_sp);
+
+ for (i=0; i<num_match_states; ++i)
+ {
+ if (match_states[i] == state)
+ return state;
+ }
+ }
+ return state;
+}
+
+StateType
+Process::WaitForStateChangedEvents (const TimeValue *timeout, EventSP &event_sp)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+
+ if (log)
+ log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout);
+
+ StateType state = eStateInvalid;
+ if (m_listener.WaitForEventForBroadcasterWithType(timeout,
+ this,
+ eBroadcastBitStateChanged,
+ event_sp))
+ state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+
+ if (log)
+ log->Printf ("Process::%s (timeout = %p, event_sp) => %s",
+ __FUNCTION__,
+ timeout,
+ StateAsCString(state));
+ return state;
+}
+
+Event *
+Process::PeekAtStateChangedEvents ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+
+ if (log)
+ log->Printf ("Process::%s...", __FUNCTION__);
+
+ Event *event_ptr;
+ event_ptr = m_listener.PeekAtNextEventForBroadcasterWithType(this,
+ eBroadcastBitStateChanged);
+ if (log)
+ {
+ if (event_ptr)
+ {
+ log->Printf ("Process::%s (event_ptr) => %s",
+ __FUNCTION__,
+ StateAsCString(ProcessEventData::GetStateFromEvent (event_ptr)));
+ }
+ else
+ {
+ log->Printf ("Process::%s no events found",
+ __FUNCTION__);
+ }
+ }
+ return event_ptr;
+}
+
+StateType
+Process::WaitForStateChangedEventsPrivate (const TimeValue *timeout, EventSP &event_sp)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+
+ if (log)
+ log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout);
+
+ StateType state = eStateInvalid;
+ if (m_private_state_listener.WaitForEventForBroadcasterWithType(timeout,
+ &m_private_state_broadcaster,
+ eBroadcastBitStateChanged,
+ event_sp))
+ state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+
+ // This is a bit of a hack, but when we wait here we could very well return
+ // to the command-line, and that could disable the log, which would render the
+ // log we got above invalid.
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+ if (log)
+ log->Printf ("Process::%s (timeout = %p, event_sp) => %s", __FUNCTION__, timeout, StateAsCString(state));
+ return state;
+}
+
+bool
+Process::WaitForEventsPrivate (const TimeValue *timeout, EventSP &event_sp, bool control_only)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+
+ if (log)
+ log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout);
+
+ if (control_only)
+ return m_private_state_listener.WaitForEventForBroadcaster(timeout, &m_private_state_control_broadcaster, event_sp);
+ else
+ return m_private_state_listener.WaitForEvent(timeout, event_sp);
+}
+
+bool
+Process::IsRunning () const
+{
+ return StateIsRunningState (m_public_state.GetValue());
+}
+
+int
+Process::GetExitStatus ()
+{
+ if (m_public_state.GetValue() == eStateExited)
+ return m_exit_status;
+ return -1;
+}
+
+const char *
+Process::GetExitDescription ()
+{
+ if (m_public_state.GetValue() == eStateExited && !m_exit_string.empty())
+ return m_exit_string.c_str();
+ return NULL;
+}
+
+void
+Process::SetExitStatus (int status, const char *cstr)
+{
+ m_exit_status = status;
+ if (cstr)
+ m_exit_string = cstr;
+ else
+ m_exit_string.clear();
+
+ SetPrivateState (eStateExited);
+}
+
+// This static callback can be used to watch for local child processes on
+// the current host. The the child process exits, the process will be
+// found in the global target list (we want to be completely sure that the
+// lldb_private::Process doesn't go away before we can deliver the signal.
+bool
+Process::SetProcessExitStatus
+(
+ void *callback_baton,
+ lldb::pid_t pid,
+ int signo, // Zero for no signal
+ int exit_status // Exit value of process if signal is zero
+)
+{
+ if (signo == 0 || exit_status)
+ {
+ TargetSP target_sp(Debugger::GetSharedInstance().GetTargetList().FindTargetWithProcessID (pid));
+ if (target_sp)
+ {
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ if (process_sp)
+ {
+ const char *signal_cstr = NULL;
+ if (signo)
+ signal_cstr = process_sp->GetUnixSignals().GetSignalAsCString (signo);
+
+ process_sp->SetExitStatus (exit_status, signal_cstr);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+
+uint32_t
+Process::GetNextThreadIndexID ()
+{
+ return ++m_thread_index_id;
+}
+
+StateType
+Process::GetState()
+{
+ // If any other threads access this we will need a mutex for it
+ return m_public_state.GetValue ();
+}
+
+void
+Process::SetPublicState (StateType new_state)
+{
+ Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE);
+ if (log)
+ log->Printf("Process::SetPublicState (%s)", StateAsCString(new_state));
+ m_public_state.SetValue (new_state);
+}
+
+StateType
+Process::GetPrivateState ()
+{
+ return m_private_state.GetValue();
+}
+
+void
+Process::SetPrivateState (StateType new_state)
+{
+ Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE);
+ bool state_changed = false;
+
+ if (log)
+ log->Printf("Process::SetPrivateState (%s)", StateAsCString(new_state));
+
+ Mutex::Locker locker(m_private_state.GetMutex());
+
+ const StateType old_state = m_private_state.GetValueNoLock ();
+ state_changed = old_state != new_state;
+ if (state_changed)
+ {
+ m_private_state.SetValueNoLock (new_state);
+ if (StateIsStoppedState(new_state))
+ {
+ m_stop_id++;
+ if (log)
+ log->Printf("Process::SetPrivateState (%s) stop_id = %u", StateAsCString(new_state), m_stop_id);
+ }
+ // Use our target to get a shared pointer to ourselves...
+ m_private_state_broadcaster.BroadcastEvent (eBroadcastBitStateChanged, new ProcessEventData (GetTarget().GetProcessSP(), new_state));
+ }
+ else
+ {
+ if (log)
+ log->Printf("Process::SetPrivateState (%s) state didn't change. Ignoring...", StateAsCString(new_state), StateAsCString(old_state));
+ }
+}
+
+
+uint32_t
+Process::GetStopID() const
+{
+ return m_stop_id;
+}
+
+addr_t
+Process::GetImageInfoAddress()
+{
+ return LLDB_INVALID_ADDRESS;
+}
+
+DynamicLoader *
+Process::GetDynamicLoader()
+{
+ return NULL;
+}
+
+const ABI *
+Process::GetABI()
+{
+ ConstString& triple = m_target_triple;
+
+ if (triple.IsEmpty())
+ return NULL;
+
+ if (m_abi_sp.get() == NULL)
+ {
+ m_abi_sp.reset(ABI::FindPlugin(triple));
+ }
+
+ return m_abi_sp.get();
+}
+
+BreakpointSiteList &
+Process::GetBreakpointSiteList()
+{
+ return m_breakpoint_site_list;
+}
+
+const BreakpointSiteList &
+Process::GetBreakpointSiteList() const
+{
+ return m_breakpoint_site_list;
+}
+
+
+void
+Process::DisableAllBreakpointSites ()
+{
+ m_breakpoint_site_list.SetEnabledForAll (false);
+}
+
+Error
+Process::ClearBreakpointSiteByID (lldb::user_id_t break_id)
+{
+ Error error (DisableBreakpointSiteByID (break_id));
+
+ if (error.Success())
+ m_breakpoint_site_list.Remove(break_id);
+
+ return error;
+}
+
+Error
+Process::DisableBreakpointSiteByID (lldb::user_id_t break_id)
+{
+ Error error;
+ BreakpointSiteSP bp_site_sp = m_breakpoint_site_list.FindByID (break_id);
+ if (bp_site_sp)
+ {
+ if (bp_site_sp->IsEnabled())
+ error = DisableBreakpoint (bp_site_sp.get());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("invalid breakpoint site ID: %i", break_id);
+ }
+
+ return error;
+}
+
+Error
+Process::EnableBreakpointSiteByID (lldb::user_id_t break_id)
+{
+ Error error;
+ BreakpointSiteSP bp_site_sp = m_breakpoint_site_list.FindByID (break_id);
+ if (bp_site_sp)
+ {
+ if (!bp_site_sp->IsEnabled())
+ error = EnableBreakpoint (bp_site_sp.get());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("invalid breakpoint site ID: %i", break_id);
+ }
+ return error;
+}
+
+lldb::user_id_t
+Process::CreateBreakpointSite (BreakpointLocationSP &owner, bool use_hardware)
+{
+ const addr_t load_addr = owner->GetAddress().GetLoadAddress (this);
+ if (load_addr != LLDB_INVALID_ADDRESS)
+ {
+ BreakpointSiteSP bp_site_sp;
+
+ // Look up this breakpoint site. If it exists, then add this new owner, otherwise
+ // create a new breakpoint site and add it.
+
+ bp_site_sp = m_breakpoint_site_list.FindByAddress (load_addr);
+
+ if (bp_site_sp)
+ {
+ bp_site_sp->AddOwner (owner);
+ owner->SetBreakpointSite (bp_site_sp);
+ return bp_site_sp->GetID();
+ }
+ else
+ {
+ bp_site_sp.reset (new BreakpointSite (&m_breakpoint_site_list, owner, load_addr, LLDB_INVALID_THREAD_ID, use_hardware));
+ if (bp_site_sp)
+ {
+ if (EnableBreakpoint (bp_site_sp.get()).Success())
+ {
+ owner->SetBreakpointSite (bp_site_sp);
+ return m_breakpoint_site_list.Add (bp_site_sp);
+ }
+ }
+ }
+ }
+ // We failed to enable the breakpoint
+ return LLDB_INVALID_BREAK_ID;
+
+}
+
+void
+Process::RemoveOwnerFromBreakpointSite (lldb::user_id_t owner_id, lldb::user_id_t owner_loc_id, BreakpointSiteSP &bp_site_sp)
+{
+ uint32_t num_owners = bp_site_sp->RemoveOwner (owner_id, owner_loc_id);
+ if (num_owners == 0)
+ {
+ DisableBreakpoint(bp_site_sp.get());
+ m_breakpoint_site_list.RemoveByAddress(bp_site_sp->GetLoadAddress());
+ }
+}
+
+
+size_t
+Process::RemoveBreakpointOpcodesFromBuffer (addr_t bp_addr, size_t size, uint8_t *buf) const
+{
+ size_t bytes_removed = 0;
+ addr_t intersect_addr;
+ size_t intersect_size;
+ size_t opcode_offset;
+ size_t idx;
+ BreakpointSiteSP bp;
+
+ for (idx = 0; (bp = m_breakpoint_site_list.GetByIndex(idx)) != NULL; ++idx)
+ {
+ if (bp->GetType() == BreakpointSite::eSoftware)
+ {
+ if (bp->IntersectsRange(bp_addr, size, &intersect_addr, &intersect_size, &opcode_offset))
+ {
+ assert(bp_addr <= intersect_addr && intersect_addr < bp_addr + size);
+ assert(bp_addr < intersect_addr + intersect_size && intersect_addr + intersect_size <= bp_addr + size);
+ assert(opcode_offset + intersect_size <= bp->GetByteSize());
+ size_t buf_offset = intersect_addr - bp_addr;
+ ::memcpy(buf + buf_offset, bp->GetSavedOpcodeBytes() + opcode_offset, intersect_size);
+ }
+ }
+ }
+ return bytes_removed;
+}
+
+
+Error
+Process::EnableSoftwareBreakpoint (BreakpointSite *bp_site)
+{
+ Error error;
+ assert (bp_site != NULL);
+ Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+ const addr_t bp_addr = bp_site->GetLoadAddress();
+ if (log)
+ log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%llx", bp_site->GetID(), (uint64_t)bp_addr);
+ if (bp_site->IsEnabled())
+ {
+ if (log)
+ log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%llx -- already enabled", bp_site->GetID(), (uint64_t)bp_addr);
+ return error;
+ }
+
+ if (bp_addr == LLDB_INVALID_ADDRESS)
+ {
+ error.SetErrorString("BreakpointSite contains an invalid load address.");
+ return error;
+ }
+ // Ask the lldb::Process subclass to fill in the correct software breakpoint
+ // trap for the breakpoint site
+ const size_t bp_opcode_size = GetSoftwareBreakpointTrapOpcode(bp_site);
+
+ if (bp_opcode_size == 0)
+ {
+ error.SetErrorStringWithFormat ("Process::GetSoftwareBreakpointTrapOpcode() returned zero, unable to get breakpoint trap for address 0x%llx.\n", bp_addr);
+ }
+ else
+ {
+ const uint8_t * const bp_opcode_bytes = bp_site->GetTrapOpcodeBytes();
+
+ if (bp_opcode_bytes == NULL)
+ {
+ error.SetErrorString ("BreakpointSite doesn't contain a valid breakpoint trap opcode.");
+ return error;
+ }
+
+ // Save the original opcode by reading it
+ if (DoReadMemory(bp_addr, bp_site->GetSavedOpcodeBytes(), bp_opcode_size, error) == bp_opcode_size)
+ {
+ // Write a software breakpoint in place of the original opcode
+ if (DoWriteMemory(bp_addr, bp_opcode_bytes, bp_opcode_size, error) == bp_opcode_size)
+ {
+ uint8_t verify_bp_opcode_bytes[64];
+ if (DoReadMemory(bp_addr, verify_bp_opcode_bytes, bp_opcode_size, error) == bp_opcode_size)
+ {
+ if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, bp_opcode_size) == 0)
+ {
+ bp_site->SetEnabled(true);
+ bp_site->SetType (BreakpointSite::eSoftware);
+ if (log)
+ log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%llx -- SUCCESS",
+ bp_site->GetID(),
+ (uint64_t)bp_addr);
+ }
+ else
+ error.SetErrorString("Failed to verify the breakpoint trap in memory.");
+ }
+ else
+ error.SetErrorString("Unable to read memory to verify breakpoint trap.");
+ }
+ else
+ error.SetErrorString("Unable to write breakpoint trap to memory.");
+ }
+ else
+ error.SetErrorString("Unable to read memory at breakpoint address.");
+ }
+ if (log)
+ log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%llx -- FAILED: %s",
+ bp_site->GetID(),
+ (uint64_t)bp_addr,
+ error.AsCString());
+ return error;
+}
+
+Error
+Process::DisableSoftwareBreakpoint (BreakpointSite *bp_site)
+{
+ Error error;
+ assert (bp_site != NULL);
+ Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+ addr_t bp_addr = bp_site->GetLoadAddress();
+ lldb::user_id_t breakID = bp_site->GetID();
+ if (log)
+ log->Printf ("ProcessMacOSX::DisableBreakpoint (breakID = %d) addr = 0x%llx", breakID, (uint64_t)bp_addr);
+
+ if (bp_site->IsHardware())
+ {
+ error.SetErrorString("Breakpoint site is a hardware breakpoint.");
+ }
+ else if (bp_site->IsEnabled())
+ {
+ const size_t break_op_size = bp_site->GetByteSize();
+ const uint8_t * const break_op = bp_site->GetTrapOpcodeBytes();
+ if (break_op_size > 0)
+ {
+ // Clear a software breakoint instruction
+ uint8_t curr_break_op[break_op_size];
+ bool break_op_found = false;
+
+ // Read the breakpoint opcode
+ if (DoReadMemory (bp_addr, curr_break_op, break_op_size, error) == break_op_size)
+ {
+ bool verify = false;
+ // Make sure we have the a breakpoint opcode exists at this address
+ if (::memcmp (curr_break_op, break_op, break_op_size) == 0)
+ {
+ break_op_found = true;
+ // We found a valid breakpoint opcode at this address, now restore
+ // the saved opcode.
+ if (DoWriteMemory (bp_addr, bp_site->GetSavedOpcodeBytes(), break_op_size, error) == break_op_size)
+ {
+ verify = true;
+ }
+ else
+ error.SetErrorString("Memory write failed when restoring original opcode.");
+ }
+ else
+ {
+ error.SetErrorString("Original breakpoint trap is no longer in memory.");
+ // Set verify to true and so we can check if the original opcode has already been restored
+ verify = true;
+ }
+
+ if (verify)
+ {
+ uint8_t verify_opcode[break_op_size];
+ // Verify that our original opcode made it back to the inferior
+ if (DoReadMemory (bp_addr, verify_opcode, break_op_size, error) == break_op_size)
+ {
+ // compare the memory we just read with the original opcode
+ if (::memcmp (bp_site->GetSavedOpcodeBytes(), verify_opcode, break_op_size) == 0)
+ {
+ // SUCCESS
+ bp_site->SetEnabled(false);
+ if (log)
+ log->Printf ("Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x%llx -- SUCCESS", bp_site->GetID(), (uint64_t)bp_addr);
+ return error;
+ }
+ else
+ {
+ if (break_op_found)
+ error.SetErrorString("Failed to restore original opcode.");
+ }
+ }
+ else
+ error.SetErrorString("Failed to read memory to verify that breakpoint trap was restored.");
+ }
+ }
+ else
+ error.SetErrorString("Unable to read memory that should contain the breakpoint trap.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x%llx -- already disabled", bp_site->GetID(), (uint64_t)bp_addr);
+ return error;
+ }
+
+ if (log)
+ log->Printf ("Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x%llx -- FAILED: %s",
+ bp_site->GetID(),
+ (uint64_t)bp_addr,
+ error.AsCString());
+ return error;
+
+}
+
+
+size_t
+Process::ReadMemory (addr_t addr, void *buf, size_t size, Error &error)
+{
+ if (buf == NULL || size == 0)
+ return 0;
+
+ size_t bytes_read = 0;
+ uint8_t *bytes = (uint8_t *)buf;
+
+ while (bytes_read < size)
+ {
+ const size_t curr_size = size - bytes_read;
+ const size_t curr_bytes_read = DoReadMemory (addr + bytes_read,
+ bytes + bytes_read,
+ curr_size,
+ error);
+ bytes_read += curr_bytes_read;
+ if (curr_bytes_read == curr_size || curr_bytes_read == 0)
+ break;
+ }
+
+ // Replace any software breakpoint opcodes that fall into this range back
+ // into "buf" before we return
+ if (bytes_read > 0)
+ RemoveBreakpointOpcodesFromBuffer (addr, bytes_read, (uint8_t *)buf);
+ return bytes_read;
+}
+
+size_t
+Process::WriteMemoryPrivate (addr_t addr, const void *buf, size_t size, Error &error)
+{
+ size_t bytes_written = 0;
+ const uint8_t *bytes = (const uint8_t *)buf;
+
+ while (bytes_written < size)
+ {
+ const size_t curr_size = size - bytes_written;
+ const size_t curr_bytes_written = DoWriteMemory (addr + bytes_written,
+ bytes + bytes_written,
+ curr_size,
+ error);
+ bytes_written += curr_bytes_written;
+ if (curr_bytes_written == curr_size || curr_bytes_written == 0)
+ break;
+ }
+ return bytes_written;
+}
+
+size_t
+Process::WriteMemory (addr_t addr, const void *buf, size_t size, Error &error)
+{
+ if (buf == NULL || size == 0)
+ return 0;
+ // We need to write any data that would go where any current software traps
+ // (enabled software breakpoints) any software traps (breakpoints) that we
+ // may have placed in our tasks memory.
+
+ BreakpointSiteList::collection::const_iterator iter = m_breakpoint_site_list.GetMap()->lower_bound (addr);
+ BreakpointSiteList::collection::const_iterator end = m_breakpoint_site_list.GetMap()->end();
+
+ if (iter == end || iter->second->GetLoadAddress() > addr + size)
+ return DoWriteMemory(addr, buf, size, error);
+
+ BreakpointSiteList::collection::const_iterator pos;
+ size_t bytes_written = 0;
+ addr_t intersect_addr;
+ size_t intersect_size;
+ size_t opcode_offset;
+ const uint8_t *ubuf = (const uint8_t *)buf;
+
+ for (pos = iter; pos != end; ++pos)
+ {
+ BreakpointSiteSP bp;
+ bp = pos->second;
+
+ assert(bp->IntersectsRange(addr, size, &intersect_addr, &intersect_size, &opcode_offset));
+ assert(addr <= intersect_addr && intersect_addr < addr + size);
+ assert(addr < intersect_addr + intersect_size && intersect_addr + intersect_size <= addr + size);
+ assert(opcode_offset + intersect_size <= bp->GetByteSize());
+
+ // Check for bytes before this breakpoint
+ const addr_t curr_addr = addr + bytes_written;
+ if (intersect_addr > curr_addr)
+ {
+ // There are some bytes before this breakpoint that we need to
+ // just write to memory
+ size_t curr_size = intersect_addr - curr_addr;
+ size_t curr_bytes_written = WriteMemoryPrivate (curr_addr,
+ ubuf + bytes_written,
+ curr_size,
+ error);
+ bytes_written += curr_bytes_written;
+ if (curr_bytes_written != curr_size)
+ {
+ // We weren't able to write all of the requested bytes, we
+ // are done looping and will return the number of bytes that
+ // we have written so far.
+ break;
+ }
+ }
+
+ // Now write any bytes that would cover up any software breakpoints
+ // directly into the breakpoint opcode buffer
+ ::memcpy(bp->GetSavedOpcodeBytes() + opcode_offset, ubuf + bytes_written, intersect_size);
+ bytes_written += intersect_size;
+ }
+
+ // Write any remaining bytes after the last breakpoint if we have any left
+ if (bytes_written < size)
+ bytes_written += WriteMemoryPrivate (addr + bytes_written,
+ ubuf + bytes_written,
+ size - bytes_written,
+ error);
+
+ return bytes_written;
+}
+
+addr_t
+Process::AllocateMemory(size_t size, uint32_t permissions, Error &error)
+{
+ // Fixme: we should track the blocks we've allocated, and clean them up...
+ // We could even do our own allocator here if that ends up being more efficient.
+ return DoAllocateMemory (size, permissions, error);
+}
+
+Error
+Process::DeallocateMemory (addr_t ptr)
+{
+ return DoDeallocateMemory (ptr);
+}
+
+
+Error
+Process::EnableWatchpoint (WatchpointLocation *watchpoint)
+{
+ Error error;
+ error.SetErrorString("watchpoints are not supported");
+ return error;
+}
+
+Error
+Process::DisableWatchpoint (WatchpointLocation *watchpoint)
+{
+ Error error;
+ error.SetErrorString("watchpoints are not supported");
+ return error;
+}
+
+StateType
+Process::WaitForProcessStopPrivate (const TimeValue *timeout, EventSP &event_sp)
+{
+ StateType state;
+ // Now wait for the process to launch and return control to us, and then
+ // call DidLaunch:
+ while (1)
+ {
+ // FIXME: Might want to put a timeout in here:
+ state = WaitForStateChangedEventsPrivate (NULL, event_sp);
+ if (state == eStateStopped || state == eStateCrashed || state == eStateExited)
+ break;
+ else
+ HandlePrivateEvent (event_sp);
+ }
+ return state;
+}
+
+Error
+Process::Launch
+(
+ char const *argv[],
+ char const *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path
+)
+{
+ Error error;
+ m_target_triple.Clear();
+ m_abi_sp.reset();
+
+ Module *exe_module = m_target.GetExecutableModule().get();
+ if (exe_module)
+ {
+ char exec_file_path[PATH_MAX];
+ exe_module->GetFileSpec().GetPath(exec_file_path, sizeof(exec_file_path));
+ if (exe_module->GetFileSpec().Exists())
+ {
+ error = WillLaunch (exe_module);
+ if (error.Success())
+ {
+ // The args coming in should not contain the application name, the
+ // lldb_private::Process class will add this in case the executable
+ // gets resolved to a different file than was given on the command
+ // line (like when an applicaiton bundle is specified and will
+ // resolve to the contained exectuable file, or the file given was
+ // a symlink or other file system link that resolves to a different
+ // file).
+
+ // Get the resolved exectuable path
+
+ // Make a new argument vector
+ std::vector<const char *> exec_path_plus_argv;
+ // Append the resolved executable path
+ exec_path_plus_argv.push_back (exec_file_path);
+
+ // Push all args if there are any
+ if (argv)
+ {
+ for (int i = 0; argv[i]; ++i)
+ exec_path_plus_argv.push_back(argv[i]);
+ }
+
+ // Push a NULL to terminate the args.
+ exec_path_plus_argv.push_back(NULL);
+
+ // Now launch using these arguments.
+ error = DoLaunch (exe_module, exec_path_plus_argv.data(), envp, stdin_path, stdout_path, stderr_path);
+
+ if (error.Fail())
+ {
+ if (GetID() != LLDB_INVALID_PROCESS_ID)
+ {
+ SetID (LLDB_INVALID_PROCESS_ID);
+ const char *error_string = error.AsCString();
+ if (error_string == NULL)
+ error_string = "launch failed";
+ SetExitStatus (-1, error_string);
+ }
+ }
+ else
+ {
+ EventSP event_sp;
+ StateType state = WaitForProcessStopPrivate(NULL, event_sp);
+
+ if (state == eStateStopped || state == eStateCrashed)
+ {
+ DidLaunch ();
+
+ // This delays passing the stopped event to listeners till DidLaunch gets
+ // a chance to complete...
+ HandlePrivateEvent (event_sp);
+ StartPrivateStateThread ();
+ }
+ else if (state == eStateExited)
+ {
+ // We exited while trying to launch somehow. Don't call DidLaunch as that's
+ // not likely to work, and return an invalid pid.
+ HandlePrivateEvent (event_sp);
+ }
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("File doesn't exist: '%s'.\n", exec_file_path);
+ }
+ }
+ return error;
+}
+
+Error
+Process::CompleteAttach ()
+{
+ Error error;
+ EventSP event_sp;
+ StateType state = WaitForProcessStopPrivate(NULL, event_sp);
+ if (state == eStateStopped || state == eStateCrashed)
+ {
+ DidAttach ();
+
+ // This delays passing the stopped event to listeners till DidLaunch gets
+ // a chance to complete...
+ HandlePrivateEvent(event_sp);
+ StartPrivateStateThread();
+ }
+ else
+ {
+ // We exited while trying to launch somehow. Don't call DidLaunch as that's
+ // not likely to work, and return an invalid pid.
+ if (state == eStateExited)
+ HandlePrivateEvent (event_sp);
+ error.SetErrorStringWithFormat("invalid state after attach: %s",
+ lldb_private::StateAsCString(state));
+ }
+ return error;
+}
+
+Error
+Process::Attach (lldb::pid_t attach_pid)
+{
+
+ m_target_triple.Clear();
+ m_abi_sp.reset();
+
+ Error error(WillAttach (attach_pid));
+ if (error.Success())
+ {
+ error = DoAttach (attach_pid);
+ if (error.Success())
+ {
+ error = CompleteAttach();
+ }
+ else
+ {
+ if (GetID() != LLDB_INVALID_PROCESS_ID)
+ {
+ SetID (LLDB_INVALID_PROCESS_ID);
+ const char *error_string = error.AsCString();
+ if (error_string == NULL)
+ error_string = "attach failed";
+
+ SetExitStatus(-1, error_string);
+ }
+ }
+ }
+ return error;
+}
+
+Error
+Process::Attach (const char *process_name, bool wait_for_launch)
+{
+ m_target_triple.Clear();
+ m_abi_sp.reset();
+
+ Error error (WillAttach (process_name, wait_for_launch));
+ if (error.Success())
+ {
+ StartPrivateStateThread();
+ error = DoAttach (process_name, wait_for_launch);
+ if (error.Fail())
+ {
+ if (GetID() != LLDB_INVALID_PROCESS_ID)
+ {
+ SetID (LLDB_INVALID_PROCESS_ID);
+ const char *error_string = error.AsCString();
+ if (error_string == NULL)
+ error_string = "attach failed";
+
+ SetExitStatus(-1, error_string);
+ }
+ }
+ else
+ {
+ error = CompleteAttach();
+ }
+ }
+ return error;
+}
+
+Error
+Process::Resume ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+ if (log)
+ log->Printf("Process::Resume() m_stop_id = %u", m_stop_id);
+
+ Error error (WillResume());
+ // Tell the process it is about to resume before the thread list
+ if (error.Success())
+ {
+ // Now let the thread list know we are about to resume to it
+ // can let all of our threads know that they are about to be
+ // resumed. Threads will each be called with
+ // Thread::WillResume(StateType) where StateType contains the state
+ // that they are supposed to have when the process is resumed
+ // (suspended/running/stepping). Threads should also check
+ // their resume signal in lldb::Thread::GetResumeSignal()
+ // to see if they are suppoed to start back up with a signal.
+ if (m_thread_list.WillResume())
+ {
+ error = DoResume();
+ if (error.Success())
+ {
+ DidResume();
+ m_thread_list.DidResume();
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("thread list returned flase after WillResume");
+ }
+ }
+ return error;
+}
+
+Error
+Process::Halt ()
+{
+ Error error (WillHalt());
+
+ if (error.Success())
+ {
+ error = DoHalt();
+ if (error.Success())
+ DidHalt();
+ }
+ return error;
+}
+
+Error
+Process::Detach ()
+{
+ Error error (WillDetach());
+
+ if (error.Success())
+ {
+ DisableAllBreakpointSites();
+ error = DoDetach();
+ if (error.Success())
+ {
+ DidDetach();
+ StopPrivateStateThread();
+ }
+ }
+ return error;
+}
+
+Error
+Process::Destroy ()
+{
+ Error error (WillDestroy());
+ if (error.Success())
+ {
+ DisableAllBreakpointSites();
+ error = DoDestroy();
+ if (error.Success())
+ {
+ DidDestroy();
+ StopPrivateStateThread();
+ }
+ }
+ return error;
+}
+
+Error
+Process::Signal (int signal)
+{
+ Error error (WillSignal());
+ if (error.Success())
+ {
+ error = DoSignal(signal);
+ if (error.Success())
+ DidSignal();
+ }
+ return error;
+}
+
+UnixSignals &
+Process::GetUnixSignals ()
+{
+ return m_unix_signals;
+}
+
+Target &
+Process::GetTarget ()
+{
+ return m_target;
+}
+
+const Target &
+Process::GetTarget () const
+{
+ return m_target;
+}
+
+uint32_t
+Process::GetAddressByteSize()
+{
+ return m_target.GetArchitecture().GetAddressByteSize();
+}
+
+bool
+Process::ShouldBroadcastEvent (Event *event_ptr)
+{
+ const StateType state = Process::ProcessEventData::GetStateFromEvent (event_ptr);
+ bool return_value = true;
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS);
+
+ switch (state)
+ {
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateDetached:
+ case eStateExited:
+ case eStateUnloaded:
+ // These events indicate changes in the state of the debugging session, always report them.
+ return_value = true;
+ break;
+ case eStateInvalid:
+ // We stopped for no apparent reason, don't report it.
+ return_value = false;
+ break;
+ case eStateRunning:
+ case eStateStepping:
+ // If we've started the target running, we handle the cases where we
+ // are already running and where there is a transition from stopped to
+ // running differently.
+ // running -> running: Automatically suppress extra running events
+ // stopped -> running: Report except when there is one or more no votes
+ // and no yes votes.
+ SynchronouslyNotifyStateChanged (state);
+ switch (m_public_state.GetValue())
+ {
+ case eStateRunning:
+ case eStateStepping:
+ // We always suppress multiple runnings with no PUBLIC stop in between.
+ return_value = false;
+ break;
+ default:
+ // TODO: make this work correctly. For now always report
+ // run if we aren't running so we don't miss any runnning
+ // events. If I run the lldb/test/thread/a.out file and
+ // break at main.cpp:58, run and hit the breakpoints on
+ // multiple threads, then somehow during the stepping over
+ // of all breakpoints no run gets reported.
+ return_value = true;
+
+ // This is a transition from stop to run.
+ switch (m_thread_list.ShouldReportRun (event_ptr))
+ {
+ case eVoteYes:
+ case eVoteNoOpinion:
+ return_value = true;
+ break;
+ case eVoteNo:
+ return_value = false;
+ break;
+ }
+ break;
+ }
+ break;
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ {
+ // We've stopped. First see if we're going to restart the target.
+ // If we are going to stop, then we always broadcast the event.
+ // If we aren't going to stop, let the thread plans decide if we're going to report this event.
+ // If no thread has an opinion, we also report it.
+ if (state != eStateInvalid)
+ {
+
+ RefreshStateAfterStop ();
+
+ if (m_thread_list.ShouldStop (event_ptr) == false)
+ {
+ switch (m_thread_list.ShouldReportStop (event_ptr))
+ {
+ case eVoteYes:
+ Process::ProcessEventData::SetRestartedInEvent (event_ptr, true);
+ case eVoteNoOpinion:
+ return_value = true;
+ break;
+ case eVoteNo:
+ return_value = false;
+ break;
+ }
+
+ if (log)
+ log->Printf ("Process::ShouldBroadcastEvent (%p) Restarting process", event_ptr, StateAsCString(state));
+ Resume ();
+ }
+ else
+ {
+ return_value = true;
+ SynchronouslyNotifyStateChanged (state);
+ }
+ }
+ }
+ }
+
+ if (log)
+ log->Printf ("Process::ShouldBroadcastEvent (%p) => %s", event_ptr, StateAsCString(state), return_value ? "YES" : "NO");
+ return return_value;
+}
+
+//------------------------------------------------------------------
+// Thread Queries
+//------------------------------------------------------------------
+
+ThreadList &
+Process::GetThreadList ()
+{
+ return m_thread_list;
+}
+
+const ThreadList &
+Process::GetThreadList () const
+{
+ return m_thread_list;
+}
+
+
+bool
+Process::StartPrivateStateThread ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS);
+
+ if (log)
+ log->Printf ("Process::%s ( )", __FUNCTION__);
+
+ // Create a thread that watches our internal state and controls which
+ // events make it to clients (into the DCProcess event queue).
+ m_private_state_thread = Host::ThreadCreate ("<lldb.process.internal-state>", Process::PrivateStateThread, this, NULL);
+ return m_private_state_thread != LLDB_INVALID_HOST_THREAD;
+}
+
+void
+Process::PausePrivateStateThread ()
+{
+ ControlPrivateStateThread (eBroadcastInternalStateControlPause);
+}
+
+void
+Process::ResumePrivateStateThread ()
+{
+ ControlPrivateStateThread (eBroadcastInternalStateControlResume);
+}
+
+void
+Process::StopPrivateStateThread ()
+{
+ ControlPrivateStateThread (eBroadcastInternalStateControlStop);
+}
+
+void
+Process::ControlPrivateStateThread (uint32_t signal)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS);
+
+ assert (signal == eBroadcastInternalStateControlStop ||
+ signal == eBroadcastInternalStateControlPause ||
+ signal == eBroadcastInternalStateControlResume);
+
+ if (log)
+ log->Printf ("Process::%s ( ) - signal: %d", __FUNCTION__, signal);
+
+ // Signal the private state thread
+ if (m_private_state_thread != LLDB_INVALID_HOST_THREAD)
+ {
+ TimeValue timeout_time;
+ bool timed_out;
+
+ m_private_state_control_broadcaster.BroadcastEvent (signal, NULL);
+
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds(2);
+ m_private_state_control_wait.WaitForValueEqualTo (true, &timeout_time, &timed_out);
+ m_private_state_control_wait.SetValue (false, eBroadcastNever);
+
+ if (signal == eBroadcastInternalStateControlStop)
+ {
+ if (timed_out)
+ Host::ThreadCancel (m_private_state_thread, NULL);
+
+ thread_result_t result = NULL;
+ Host::ThreadJoin (m_private_state_thread, &result, NULL);
+ }
+ }
+}
+
+void
+Process::HandlePrivateEvent (EventSP &event_sp)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+ const StateType internal_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+ // See if we should broadcast this state to external clients?
+ const bool should_broadcast = ShouldBroadcastEvent (event_sp.get());
+ if (log)
+ log->Printf ("Process::%s (arg = %p, pid = %i) got event '%s' broadcast = %s", __FUNCTION__, this, GetID(), StateAsCString(internal_state), should_broadcast ? "yes" : "no");
+
+ if (should_broadcast)
+ {
+ if (log)
+ {
+ log->Printf ("\tChanging public state from: %s to %s", StateAsCString(GetState ()), StateAsCString (internal_state));
+ }
+ Process::ProcessEventData::SetUpdateStateOnRemoval(event_sp.get());
+ BroadcastEvent (event_sp);
+ }
+ else
+ {
+ if (log)
+ {
+ log->Printf ("\tNot changing public state with event: %s", StateAsCString (internal_state));
+ }
+ }
+}
+
+void *
+Process::PrivateStateThread (void *arg)
+{
+ Process *proc = static_cast<Process*> (arg);
+ void *result = proc->RunPrivateStateThread ();
+ proc->m_private_state_thread = LLDB_INVALID_HOST_THREAD;
+ return result;
+}
+
+void *
+Process::RunPrivateStateThread ()
+{
+ bool control_only = false;
+ m_private_state_control_wait.SetValue (false, eBroadcastNever);
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+ if (log)
+ log->Printf ("Process::%s (arg = %p, pid = %i) thread starting...", __FUNCTION__, this, GetID());
+
+ bool exit_now = false;
+ while (!exit_now)
+ {
+ EventSP event_sp;
+ WaitForEventsPrivate (NULL, event_sp, control_only);
+ if (event_sp->BroadcasterIs(&m_private_state_control_broadcaster))
+ {
+ switch (event_sp->GetType())
+ {
+ case eBroadcastInternalStateControlStop:
+ exit_now = true;
+ continue; // Go to next loop iteration so we exit without
+ break; // doing any internal state managment below
+
+ case eBroadcastInternalStateControlPause:
+ control_only = true;
+ break;
+
+ case eBroadcastInternalStateControlResume:
+ control_only = false;
+ break;
+ }
+ m_private_state_control_wait.SetValue (true, eBroadcastAlways);
+ }
+
+
+ const StateType internal_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+
+ if (internal_state != eStateInvalid)
+ {
+ HandlePrivateEvent (event_sp);
+ }
+
+ if (internal_state == eStateInvalid || internal_state == eStateExited)
+ break;
+ }
+
+ if (log)
+ log->Printf ("Process::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, this, GetID());
+
+ return NULL;
+}
+
+addr_t
+Process::GetSectionLoadAddress (const Section *section) const
+{
+ // TODO: add support for the same section having multiple load addresses
+ addr_t section_load_addr = LLDB_INVALID_ADDRESS;
+ if (m_section_load_info.GetFirstKeyForValue (section, section_load_addr))
+ return section_load_addr;
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+Process::SectionLoaded (const Section *section, addr_t load_addr)
+{
+ Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_SHLIB | LIBLLDB_LOG_VERBOSE);
+
+ if (log)
+ log->Printf ("Process::%s (section = %p (%s.%s), load_addr = 0x%16.16llx)",
+ __FUNCTION__,
+ section,
+ section->GetModule()->GetFileSpec().GetFilename().AsCString(),
+ section->GetName().AsCString(),
+ load_addr);
+
+
+ const Section *existing_section = NULL;
+ Mutex::Locker locker(m_section_load_info.GetMutex());
+
+ if (m_section_load_info.GetValueForKeyNoLock (load_addr, existing_section))
+ {
+ if (existing_section == section)
+ return false; // No change
+ }
+ m_section_load_info.SetValueForKeyNoLock (load_addr, section);
+ return true; // Changed
+}
+
+size_t
+Process::SectionUnloaded (const Section *section)
+{
+ Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_SHLIB | LIBLLDB_LOG_VERBOSE);
+
+ if (log)
+ log->Printf ("Process::%s (section = %p (%s.%s))",
+ __FUNCTION__,
+ section,
+ section->GetModule()->GetFileSpec().GetFilename().AsCString(),
+ section->GetName().AsCString());
+
+ Mutex::Locker locker(m_section_load_info.GetMutex());
+
+ size_t unload_count = 0;
+ addr_t section_load_addr;
+ while (m_section_load_info.GetFirstKeyForValueNoLock (section, section_load_addr))
+ {
+ unload_count += m_section_load_info.EraseNoLock (section_load_addr);
+ }
+ return unload_count;
+}
+
+bool
+Process::SectionUnloaded (const Section *section, addr_t load_addr)
+{
+ Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_SHLIB | LIBLLDB_LOG_VERBOSE);
+
+ if (log)
+ log->Printf ("Process::%s (section = %p (%s.%s), load_addr = 0x%16.16llx)",
+ __FUNCTION__,
+ section,
+ section->GetModule()->GetFileSpec().GetFilename().AsCString(),
+ section->GetName().AsCString(),
+ load_addr);
+
+ return m_section_load_info.Erase (load_addr) == 1;
+}
+
+
+bool
+Process::ResolveLoadAddress (addr_t load_addr, Address &so_addr) const
+{
+ addr_t section_load_addr = LLDB_INVALID_ADDRESS;
+ const Section *section = NULL;
+
+ // First find the top level section that this load address exists in
+ if (m_section_load_info.LowerBound (load_addr, section_load_addr, section, true))
+ {
+ addr_t offset = load_addr - section_load_addr;
+ if (offset < section->GetByteSize())
+ {
+ // We have found the top level section, now we need to find the
+ // deepest child section.
+ return section->ResolveContainedAddress (offset, so_addr);
+ }
+ }
+ so_addr.Clear();
+ return false;
+}
+
+//------------------------------------------------------------------
+// Process Event Data
+//------------------------------------------------------------------
+
+Process::ProcessEventData::ProcessEventData () :
+ EventData (),
+ m_process_sp (),
+ m_state (eStateInvalid),
+ m_update_state (false),
+ m_restarted (false)
+{
+}
+
+Process::ProcessEventData::ProcessEventData (const ProcessSP &process_sp, StateType state) :
+ EventData (),
+ m_process_sp (process_sp),
+ m_state (state),
+ m_update_state (false),
+ m_restarted (false)
+{
+}
+
+Process::ProcessEventData::~ProcessEventData()
+{
+}
+
+const ConstString &
+Process::ProcessEventData::GetFlavorString ()
+{
+ static ConstString g_flavor ("Process::ProcessEventData");
+ return g_flavor;
+}
+
+const ConstString &
+Process::ProcessEventData::GetFlavor () const
+{
+ return ProcessEventData::GetFlavorString ();
+}
+
+const ProcessSP &
+Process::ProcessEventData::GetProcessSP () const
+{
+ return m_process_sp;
+}
+
+StateType
+Process::ProcessEventData::GetState () const
+{
+ return m_state;
+}
+
+bool
+Process::ProcessEventData::GetRestarted () const
+{
+ return m_restarted;
+}
+
+void
+Process::ProcessEventData::SetRestarted (bool new_value)
+{
+ m_restarted = new_value;
+}
+
+void
+Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
+{
+ // This function gets called twice for each event, once when the event gets pulled
+ // off of the private process event queue, and once when it gets pulled off of
+ // the public event queue. m_update_state is used to distinguish these
+ // two cases; it is false when we're just pulling it off for private handling,
+ // and we don't want to do the breakpoint command handling then.
+
+ if (!m_update_state)
+ return;
+
+ m_process_sp->SetPublicState (m_state);
+
+ // If we're stopped and haven't restarted, then do the breakpoint commands here:
+ if (m_state == eStateStopped && ! m_restarted)
+ {
+ int num_threads = m_process_sp->GetThreadList().GetSize();
+ int idx;
+
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ lldb::ThreadSP thread_sp = m_process_sp->GetThreadList().GetThreadAtIndex(idx);
+
+ Thread::StopInfo stop_info;
+ if (thread_sp->GetStopInfo(&stop_info))
+ {
+ StopReason reason = stop_info.GetStopReason();
+ if (reason == eStopReasonBreakpoint)
+ {
+ BreakpointSiteSP bp_site_sp;
+ // Look up the breakpoint site in the stop info, but the breakpoint
+ // might be a temporary one that's been deleted between the time we
+ // hit the breakpoint and now, if so there's nothing to do.
+
+ bp_site_sp = m_process_sp->GetBreakpointSiteList().FindByID (stop_info.GetBreakpointSiteID());
+ if (bp_site_sp)
+ {
+ size_t num_owners = bp_site_sp->GetNumberOfOwners();
+ for (size_t j = 0; j < num_owners; j++)
+ {
+ lldb::BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(j);
+ StoppointCallbackContext context (event_ptr,
+ m_process_sp.get(),
+ thread_sp.get(),
+ thread_sp->GetStackFrameAtIndex(0).get(),
+ false);
+ bp_loc_sp->InvokeCallback (&context);
+ }
+ }
+ else
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+
+ if (log)
+ log->Printf ("Process::%s could not find breakpoint site id: %d...", __FUNCTION__, stop_info.GetBreakpointSiteID());
+ }
+
+ }
+ }
+ }
+ if (m_process_sp->GetPrivateState() == eStateRunning)
+ SetRestarted(true);
+ }
+}
+
+void
+Process::ProcessEventData::Dump (Stream *s) const
+{
+ if (m_process_sp)
+ s->Printf(" process = %p (pid = %u), ", m_process_sp.get(), m_process_sp->GetID());
+
+ s->Printf("state = %s", StateAsCString(GetState()));;
+}
+
+const Process::ProcessEventData *
+Process::ProcessEventData::GetEventDataFromEvent (const Event *event_ptr)
+{
+ if (event_ptr)
+ {
+ const EventData *event_data = event_ptr->GetData();
+ if (event_data && event_data->GetFlavor() == ProcessEventData::GetFlavorString())
+ return static_cast <const ProcessEventData *> (event_ptr->GetData());
+ }
+ return NULL;
+}
+
+ProcessSP
+Process::ProcessEventData::GetProcessFromEvent (const Event *event_ptr)
+{
+ ProcessSP process_sp;
+ const ProcessEventData *data = GetEventDataFromEvent (event_ptr);
+ if (data)
+ process_sp = data->GetProcessSP();
+ return process_sp;
+}
+
+StateType
+Process::ProcessEventData::GetStateFromEvent (const Event *event_ptr)
+{
+ const ProcessEventData *data = GetEventDataFromEvent (event_ptr);
+ if (data == NULL)
+ return eStateInvalid;
+ else
+ return data->GetState();
+}
+
+bool
+Process::ProcessEventData::GetRestartedFromEvent (const Event *event_ptr)
+{
+ const ProcessEventData *data = GetEventDataFromEvent (event_ptr);
+ if (data == NULL)
+ return false;
+ else
+ return data->GetRestarted();
+}
+
+void
+Process::ProcessEventData::SetRestartedInEvent (Event *event_ptr, bool new_value)
+{
+ ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
+ if (data != NULL)
+ data->SetRestarted(new_value);
+}
+
+bool
+Process::ProcessEventData::SetUpdateStateOnRemoval (Event *event_ptr)
+{
+ ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
+ if (data)
+ {
+ data->SetUpdateStateOnRemoval();
+ return true;
+ }
+ return false;
+}
+
+void
+Process::ProcessEventData::SetUpdateStateOnRemoval()
+{
+ m_update_state = true;
+}
+
+Target *
+Process::CalculateTarget ()
+{
+ return &m_target;
+}
+
+Process *
+Process::CalculateProcess ()
+{
+ return this;
+}
+
+Thread *
+Process::CalculateThread ()
+{
+ return NULL;
+}
+
+StackFrame *
+Process::CalculateStackFrame ()
+{
+ return NULL;
+}
+
+void
+Process::Calculate (ExecutionContext &exe_ctx)
+{
+ exe_ctx.target = &m_target;
+ exe_ctx.process = this;
+ exe_ctx.thread = NULL;
+ exe_ctx.frame = NULL;
+}
+
+lldb::ProcessSP
+Process::GetSP ()
+{
+ return GetTarget().GetProcessSP();
+}
+
+ObjCObjectPrinter &
+Process::GetObjCObjectPrinter()
+{
+ return m_objc_object_printer;
+}
+
diff --git a/lldb/source/Target/RegisterContext.cpp b/lldb/source/Target/RegisterContext.cpp
new file mode 100644
index 00000000000..b1838ba477a
--- /dev/null
+++ b/lldb/source/Target/RegisterContext.cpp
@@ -0,0 +1,238 @@
+//===-- RegisterContext.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// RegisterContext constructor
+//----------------------------------------------------------------------
+RegisterContext::RegisterContext (Thread &thread, StackFrame *frame) :
+ m_thread (thread),
+ m_frame (frame)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RegisterContext::~RegisterContext()
+{
+}
+
+const RegisterInfo *
+RegisterContext::GetRegisterInfoByName (const char *reg_name, uint32_t start_idx)
+{
+ if (reg_name && reg_name[0])
+ {
+ const uint32_t num_registers = GetRegisterCount();
+ for (uint32_t reg = start_idx; reg < num_registers; ++reg)
+ {
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg);
+
+ if ((reg_info->name != NULL && ::strcasecmp (reg_info->name, reg_name) == 0) ||
+ (reg_info->alt_name != NULL && ::strcasecmp (reg_info->alt_name, reg_name) == 0))
+ {
+ return reg_info;
+ }
+ }
+ }
+ return NULL;
+}
+
+const char *
+RegisterContext::GetRegisterName (uint32_t reg)
+{
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg);
+ if (reg_info)
+ return reg_info->name;
+ return NULL;
+}
+
+uint64_t
+RegisterContext::GetPC(uint64_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+bool
+RegisterContext::SetPC(uint64_t pc)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ bool success = WriteRegisterFromUnsigned (reg, pc);
+ if (success)
+ {
+ if (m_frame)
+ m_frame->ChangePC(pc);
+ else
+ m_thread.ClearStackFrames ();
+ }
+ return success;
+}
+
+uint64_t
+RegisterContext::GetSP(uint64_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+bool
+RegisterContext::SetSP(uint64_t sp)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ return WriteRegisterFromUnsigned (reg, sp);
+}
+
+uint64_t
+RegisterContext::GetFP(uint64_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+bool
+RegisterContext::SetFP(uint64_t fp)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ return WriteRegisterFromUnsigned (reg, fp);
+}
+
+uint64_t
+RegisterContext::GetReturnAddress (uint64_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+uint64_t
+RegisterContext::GetFlags (uint64_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+
+uint64_t
+RegisterContext::ReadRegisterAsUnsigned (uint32_t reg, uint64_t fail_value)
+{
+ if (reg != LLDB_INVALID_REGNUM)
+ {
+ Scalar value;
+ if (ReadRegisterValue (reg, value))
+ return value.GetRawBits64(fail_value);
+ }
+ return fail_value;
+}
+
+bool
+RegisterContext::WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval)
+{
+ if (reg == LLDB_INVALID_REGNUM)
+ return false;
+ Scalar value(uval);
+ return WriteRegisterValue (reg, value);
+}
+
+lldb::tid_t
+RegisterContext::GetThreadID() const
+{
+ return m_thread.GetID();
+}
+
+uint32_t
+RegisterContext::NumSupportedHardwareBreakpoints ()
+{
+ return 0;
+}
+
+uint32_t
+RegisterContext::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContext::ClearHardwareBreakpoint (uint32_t hw_idx)
+{
+ return false;
+}
+
+
+uint32_t
+RegisterContext::NumSupportedHardwareWatchpoints ()
+{
+ return 0;
+}
+
+uint32_t
+RegisterContext::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
+{
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContext::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContext::HardwareSingleStep (bool enable)
+{
+ return false;
+}
+
+Target *
+RegisterContext::CalculateTarget ()
+{
+ return m_thread.CalculateTarget();
+}
+
+
+Process *
+RegisterContext::CalculateProcess ()
+{
+ return m_thread.CalculateProcess ();
+}
+
+Thread *
+RegisterContext::CalculateThread ()
+{
+ return &m_thread;
+}
+
+StackFrame *
+RegisterContext::CalculateStackFrame ()
+{
+ return m_frame;
+}
+
+void
+RegisterContext::Calculate (ExecutionContext &exe_ctx)
+{
+ if (m_frame)
+ m_frame->Calculate (exe_ctx);
+ else
+ m_thread.Calculate (exe_ctx);
+}
+
+
+
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
new file mode 100644
index 00000000000..cb832951661
--- /dev/null
+++ b/lldb/source/Target/StackFrame.cpp
@@ -0,0 +1,393 @@
+//===-- StackFrame.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/StackFrame.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// The first bits in the flags are reserved for the SymbolContext::Scope bits
+// so we know if we have tried to look up information in our internal symbol
+// context (m_sc) already.
+#define RESOLVED_PC_SO_ADDR (uint32_t(eSymbolContextEverything + 1))
+#define RESOLVED_FRAME_ID (RESOLVED_PC_SO_ADDR << 1)
+#define GOT_FRAME_BASE (RESOLVED_FRAME_ID << 1)
+#define FRAME_IS_OBSOLETE (GOT_FRAME_BASE << 1)
+#define RESOLVED_VARIABLES (FRAME_IS_OBSOLETE << 1)
+
+StackFrame::StackFrame (lldb::user_id_t frame_idx, Thread &thread, lldb::addr_t cfa, lldb::addr_t pc, const SymbolContext *sc_ptr) :
+ UserID (frame_idx),
+ m_thread (thread),
+ m_reg_context_sp(),
+ m_id(cfa),
+ m_pc(NULL, pc),
+ m_sc(),
+ m_flags(),
+ m_frame_base(),
+ m_frame_base_error(),
+ m_variable_list_sp (),
+ m_value_object_list ()
+{
+ if (sc_ptr != NULL)
+ m_sc = *sc_ptr;
+}
+
+StackFrame::StackFrame (lldb::user_id_t frame_idx, Thread &thread, RegisterContextSP &reg_context_sp, lldb::addr_t cfa, lldb::addr_t pc, const SymbolContext *sc_ptr) :
+ UserID (frame_idx),
+ m_thread (thread),
+ m_reg_context_sp(reg_context_sp),
+ m_id(cfa),
+ m_pc(NULL, pc),
+ m_sc(),
+ m_flags(),
+ m_frame_base(),
+ m_frame_base_error(),
+ m_variable_list_sp (),
+ m_value_object_list ()
+{
+ if (sc_ptr != NULL)
+ m_sc = *sc_ptr;
+}
+
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+StackFrame::~StackFrame()
+{
+}
+
+StackID&
+StackFrame::GetStackID()
+{
+ // Make sure we have resolved our stack ID's address range before we give
+ // it out to any external clients
+ if (m_id.GetStartAddress().IsValid() == 0 && m_flags.IsClear(RESOLVED_FRAME_ID))
+ {
+ m_flags.Set (RESOLVED_FRAME_ID);
+
+ // Resolve our PC to section offset if we haven't alreday done so
+ // and if we don't have a module. The resolved address section will
+ // contain the module to which it belongs.
+ if (!m_sc.module_sp && m_flags.IsClear(RESOLVED_PC_SO_ADDR))
+ GetPC();
+
+ const uint32_t resolve_scope = eSymbolContextModule |
+ eSymbolContextCompUnit |
+ eSymbolContextFunction;
+
+ if (m_sc.module_sp)
+ {
+ if (m_sc.module_sp->ResolveSymbolContextForAddress (GetPC(), resolve_scope, m_sc) & eSymbolContextFunction)
+ {
+ assert (m_sc.function);
+ m_id.SetStartAddress(m_sc.function->GetAddressRange().GetBaseAddress());
+ }
+ else if (m_sc.module_sp->ResolveSymbolContextForAddress (GetPC(), resolve_scope, m_sc) & eSymbolContextSymbol)
+ {
+ assert (m_sc.symbol);
+ AddressRange *symbol_range_ptr = m_sc.symbol->GetAddressRangePtr();
+ if (symbol_range_ptr)
+ m_id.SetStartAddress(symbol_range_ptr->GetBaseAddress());
+ }
+ }
+// else if (m_sc.target != NULL)
+// {
+// if (m_sc.target->GetImages().ResolveSymbolContextForAddress (GetPC(), resolve_scope, m_sc) & eSymbolContextFunction)
+// {
+// assert (m_sc.function);
+// m_id.GetAddressRange() = m_sc.function->GetAddressRange();
+// }
+// else if (m_sc.target->GetImages().ResolveSymbolContextForAddress (GetPC(), resolve_scope, m_sc) & eSymbolContextSymbol)
+// {
+// assert (m_sc.symbol);
+// AddressRange *symbol_range_ptr = m_sc.symbol->GetAddressRange();
+// if (symbol_range_ptr)
+// m_id.GetAddressRange() = *symbol_range_ptr;
+// }
+// }
+ }
+ return m_id;
+}
+
+Address&
+StackFrame::GetPC()
+{
+ if (m_flags.IsClear(RESOLVED_PC_SO_ADDR) && !m_pc.IsSectionOffset())
+ {
+ m_flags.Set (RESOLVED_PC_SO_ADDR);
+
+ // Resolve the PC into a temporary address because if ResolveLoadAddress
+ // fails to resolve the address, it will clear the address object...
+ Address resolved_pc;
+ if (m_thread.GetProcess().ResolveLoadAddress(m_pc.GetOffset(), resolved_pc))
+ {
+ m_pc = resolved_pc;
+ const Section *section = m_pc.GetSection();
+ if (section)
+ {
+ Module *module = section->GetModule();
+ if (module)
+ {
+ m_sc.module_sp = module->GetSP();
+ if (m_sc.module_sp)
+ m_flags.Set(eSymbolContextModule);
+ }
+ }
+ }
+ }
+ return m_pc;
+}
+
+void
+StackFrame::ChangePC (addr_t pc)
+{
+ m_pc.SetOffset(pc);
+ m_pc.SetSection(NULL);
+ m_sc.Clear();
+ m_flags.SetAllFlagBits(0);
+ m_thread.ClearStackFrames ();
+}
+
+const char *
+StackFrame::Disassemble ()
+{
+ if (m_disassembly.GetSize() == 0)
+ {
+ ExecutionContext exe_ctx;
+ Calculate(exe_ctx);
+ Disassembler::Disassemble (m_thread.GetProcess().GetTarget().GetArchitecture(),
+ exe_ctx,
+ 0,
+ m_disassembly);
+ if (m_disassembly.GetSize() == 0)
+ return NULL;
+ }
+ return m_disassembly.GetData();
+}
+
+//----------------------------------------------------------------------
+// Get the symbol context if we already haven't done so by resolving the
+// PC address as much as possible. This way when we pass around a
+// StackFrame object, everyone will have as much information as
+// possible and no one will ever have to look things up manually.
+//----------------------------------------------------------------------
+const SymbolContext&
+StackFrame::GetSymbolContext (uint32_t resolve_scope)
+{
+ // Copy our internal symbol context into "sc".
+
+ if ((m_flags.GetAllFlagBits() & resolve_scope) != resolve_scope)
+ {
+ // Resolve our PC to section offset if we haven't alreday done so
+ // and if we don't have a module. The resolved address section will
+ // contain the module to which it belongs
+ if (!m_sc.module_sp && m_flags.IsClear(RESOLVED_PC_SO_ADDR))
+ GetPC();
+
+ // If this is not frame zero, then we need to subtract 1 from the PC
+ // value when doing address lookups since the PC will be on the
+ // instruction following the function call instruction...
+
+ Address lookup_addr(GetPC());
+ if (GetID() > 0 && lookup_addr.IsValid())
+ {
+ addr_t offset = lookup_addr.GetOffset();
+ if (offset > 0)
+ lookup_addr.SetOffset(offset - 1);
+ }
+
+ if (m_sc.module_sp)
+ {
+ // We have something in our stack frame symbol context, lets check
+ // if we haven't already tried to lookup one of those things. If we
+ // haven't then we will do the query.
+ if ((m_sc.comp_unit == NULL && (resolve_scope & eSymbolContextCompUnit ) && m_flags.IsClear(eSymbolContextCompUnit )) ||
+ (m_sc.function == NULL && (resolve_scope & eSymbolContextFunction ) && m_flags.IsClear(eSymbolContextFunction )) ||
+ (m_sc.block == NULL && (resolve_scope & eSymbolContextBlock ) && m_flags.IsClear(eSymbolContextBlock )) ||
+ (m_sc.symbol == NULL && (resolve_scope & eSymbolContextSymbol ) && m_flags.IsClear(eSymbolContextSymbol )) ||
+ (!m_sc.line_entry.IsValid() && (resolve_scope & eSymbolContextLineEntry) && m_flags.IsClear(eSymbolContextLineEntry )))
+ {
+ // We might be resolving less information than what is already
+ // in our current symbol context so resolve into a temporary
+ // symbol context "sc" so we don't clear out data we have
+ // already found in "m_sc"
+ SymbolContext sc;
+ // Set flags that indicate what we have tried to resolve
+ const uint32_t resolved = m_sc.module_sp->ResolveSymbolContextForAddress (lookup_addr, resolve_scope, sc);
+ if (resolved & eSymbolContextCompUnit) m_sc.comp_unit = sc.comp_unit;
+ if (resolved & eSymbolContextFunction) m_sc.function = sc.function;
+ if (resolved & eSymbolContextBlock) m_sc.block = sc.block;
+ if (resolved & eSymbolContextSymbol) m_sc.symbol = sc.symbol;
+ if (resolved & eSymbolContextLineEntry) m_sc.line_entry = sc.line_entry;
+ }
+ }
+ else
+ {
+ // If we don't have a module, then we can't have the compile unit,
+ // function, block, line entry or symbol, so we can safely call
+ // ResolveSymbolContextForAddress with our symbol context member m_sc.
+ m_thread.GetProcess().GetTarget().GetImages().ResolveSymbolContextForAddress (lookup_addr, resolve_scope, m_sc);
+ }
+
+ // If the target was requested add that:
+ if (m_sc.target_sp.get() == NULL)
+ m_sc.target_sp = CalculateProcess()->GetTarget().GetSP();
+
+ // Update our internal flags so we remember what we have tried to locate so
+ // we don't have to keep trying when more calls to this function are made.
+ m_flags.Set(resolve_scope);
+ }
+
+ // Return the symbol context with everything that was possible to resolve
+ // resolved.
+ return m_sc;
+}
+
+
+VariableList *
+StackFrame::GetVariableList ()
+{
+ if (m_flags.IsClear(RESOLVED_VARIABLES))
+ {
+ m_flags.Set(RESOLVED_VARIABLES);
+
+ GetSymbolContext(eSymbolContextFunction);
+ if (m_sc.function)
+ {
+ bool get_child_variables = true;
+ bool can_create = true;
+ m_variable_list_sp = m_sc.function->GetBlocks(can_create).GetVariableList (Block::RootID, get_child_variables, can_create);
+ }
+ }
+ return m_variable_list_sp.get();
+}
+
+
+bool
+StackFrame::GetFrameBaseValue (Scalar &frame_base, Error *error_ptr)
+{
+ if (m_flags.IsClear(GOT_FRAME_BASE))
+ {
+ if (m_sc.function)
+ {
+ m_frame_base.Clear();
+ m_frame_base_error.Clear();
+
+ m_flags.Set(GOT_FRAME_BASE);
+ ExecutionContext exe_ctx (&m_thread.GetProcess(), &m_thread, this);
+ Value expr_value;
+ if (m_sc.function->GetFrameBaseExpression().Evaluate(&exe_ctx, NULL, NULL, expr_value, &m_frame_base_error) < 0)
+ {
+ // We should really have an error if evaluate returns, but in case
+ // we don't, lets set the error to something at least.
+ if (m_frame_base_error.Success())
+ m_frame_base_error.SetErrorString("Evaluation of the frame base expression failed.");
+ }
+ else
+ {
+ m_frame_base = expr_value.ResolveValue(&exe_ctx, NULL);
+ }
+ }
+ else
+ {
+ m_frame_base_error.SetErrorString ("No function in symbol context.");
+ }
+ }
+
+ if (m_frame_base_error.Success())
+ frame_base = m_frame_base;
+
+ if (error_ptr)
+ *error_ptr = m_frame_base_error;
+ return m_frame_base_error.Success();
+}
+
+RegisterContext *
+StackFrame::GetRegisterContext ()
+{
+ if (m_reg_context_sp.get() == NULL)
+ m_reg_context_sp.reset (m_thread.CreateRegisterContextForFrame (this));
+ return m_reg_context_sp.get();
+}
+
+bool
+StackFrame::HasDebugInformation ()
+{
+ GetSymbolContext(eSymbolContextLineEntry);
+ return m_sc.line_entry.IsValid();
+}
+
+ValueObjectList &
+StackFrame::GetValueObjectList()
+{
+ return m_value_object_list;
+}
+
+
+Target *
+StackFrame::CalculateTarget ()
+{
+ return m_thread.CalculateTarget();
+}
+
+Process *
+StackFrame::CalculateProcess ()
+{
+ return m_thread.CalculateProcess();
+}
+
+Thread *
+StackFrame::CalculateThread ()
+{
+ return &m_thread;
+}
+
+StackFrame *
+StackFrame::CalculateStackFrame ()
+{
+ return this;
+}
+
+
+void
+StackFrame::Calculate (ExecutionContext &exe_ctx)
+{
+ m_thread.Calculate (exe_ctx);
+ exe_ctx.frame = this;
+}
+
+void
+StackFrame::Dump (Stream *strm, bool show_frame_index)
+{
+ if (strm == NULL)
+ return;
+
+ if (show_frame_index)
+ strm->Printf("frame #%u: ", GetID());
+ strm->Printf("pc = 0x%0*llx", m_thread.GetProcess().GetAddressByteSize() * 2, GetRegisterContext()->GetPC());
+ SymbolContext sc (GetSymbolContext(eSymbolContextEverything));
+ strm->PutCString(", where = ");
+ sc.DumpStopContext(strm, &m_thread.GetProcess(), GetPC());
+}
+
diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp
new file mode 100644
index 00000000000..8615f714673
--- /dev/null
+++ b/lldb/source/Target/StackFrameList.cpp
@@ -0,0 +1,135 @@
+//===-- StackFrameList.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/StackFrameList.h"
+#include "lldb/Target/StackFrame.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// StackFrameList constructor
+//----------------------------------------------------------------------
+StackFrameList::StackFrameList() :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_frames (),
+ m_current_frame_idx (0)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+StackFrameList::~StackFrameList()
+{
+}
+
+
+uint32_t
+StackFrameList::GetNumFrames() const
+{
+ Mutex::Locker locker (m_mutex);
+ return m_frames.size();
+}
+
+// After we have determined the number of frames, we can set the count here
+// and have the frame info be generated on demand.
+void
+StackFrameList::SetNumFrames(uint32_t count)
+{
+ Mutex::Locker locker (m_mutex);
+ return m_frames.resize(count);
+}
+
+StackFrameSP
+StackFrameList::GetFrameAtIndex (uint32_t idx) const
+{
+ StackFrameSP frame_sp;
+ {
+ Mutex::Locker locker (m_mutex);
+ if (idx < m_frames.size())
+ frame_sp = m_frames[idx];
+ }
+ return frame_sp;
+}
+
+bool
+StackFrameList::SetFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp)
+{
+ Mutex::Locker locker (m_mutex);
+ if (idx >= m_frames.size())
+ m_frames.resize(idx + 1);
+ // Make sure allocation succeeded by checking bounds again
+ if (idx < m_frames.size())
+ {
+ m_frames[idx] = frame_sp;
+ return true;
+ }
+ return false; // resize failed, out of memory?
+}
+
+uint32_t
+StackFrameList::GetCurrentFrameIndex () const
+{
+ Mutex::Locker locker (m_mutex);
+ return m_current_frame_idx;
+}
+
+
+uint32_t
+StackFrameList::SetCurrentFrame (lldb_private::StackFrame *frame)
+{
+ Mutex::Locker locker (m_mutex);
+ const_iterator pos,
+ begin = m_frames.begin(),
+ end = m_frames.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (pos->get() == frame)
+ {
+ m_current_frame_idx = std::distance (begin, pos);
+ return m_current_frame_idx;
+ }
+ }
+ m_current_frame_idx = 0;
+ return m_current_frame_idx;
+}
+
+// Mark a stack frame as the current frame using the frame index
+void
+StackFrameList::SetCurrentFrameByIndex (uint32_t idx)
+{
+ Mutex::Locker locker (m_mutex);
+ m_current_frame_idx = idx;
+}
+
+// The thread has been run, reset the number stack frames to zero so we can
+// determine how many frames we have lazily.
+void
+StackFrameList::Clear ()
+{
+ Mutex::Locker locker (m_mutex);
+ m_frames.clear();
+}
+
+void
+StackFrameList::InvalidateFrames (uint32_t start_idx)
+{
+ Mutex::Locker locker (m_mutex);
+ size_t num_frames = m_frames.size();
+ while (start_idx < num_frames)
+ {
+ m_frames[start_idx].reset();
+ ++start_idx;
+ }
+}
diff --git a/lldb/source/Target/StackID.cpp b/lldb/source/Target/StackID.cpp
new file mode 100644
index 00000000000..6f903aed6da
--- /dev/null
+++ b/lldb/source/Target/StackID.cpp
@@ -0,0 +1,110 @@
+//===-- StackID.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/StackID.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// StackID constructor
+//----------------------------------------------------------------------
+StackID::StackID() :
+ m_start_address(),
+ m_cfa()
+{
+}
+
+//----------------------------------------------------------------------
+// StackID constructor with args
+//----------------------------------------------------------------------
+StackID::StackID (const Address& start_address, lldb::addr_t cfa) :
+ m_start_address (start_address),
+ m_cfa (cfa)
+{
+}
+
+StackID::StackID (lldb::addr_t cfa) :
+ m_start_address (),
+ m_cfa (cfa)
+{
+}
+
+//----------------------------------------------------------------------
+// StackID copy constructor
+//----------------------------------------------------------------------
+StackID::StackID(const StackID& rhs) :
+ m_start_address (rhs.m_start_address),
+ m_cfa (rhs.m_cfa)
+{
+}
+
+//----------------------------------------------------------------------
+// StackID assignment operator
+//----------------------------------------------------------------------
+const StackID&
+StackID::operator=(const StackID& rhs)
+{
+ if (this != &rhs)
+ {
+ m_start_address = rhs.m_start_address;
+ m_cfa = rhs.m_cfa;
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+StackID::~StackID()
+{
+}
+
+
+const Address&
+StackID::GetStartAddress() const
+{
+ return m_start_address;
+}
+
+void
+StackID::SetStartAddress(const Address& start_address)
+{
+ m_start_address = start_address;
+}
+
+lldb::addr_t
+StackID::GetCallFrameAddress() const
+{
+ return m_cfa;
+}
+
+
+bool
+lldb_private::operator== (const StackID& lhs, const StackID& rhs)
+{
+ return lhs.GetCallFrameAddress() == rhs.GetCallFrameAddress() && lhs.GetStartAddress() == rhs.GetStartAddress();
+}
+
+bool
+lldb_private::operator!= (const StackID& lhs, const StackID& rhs)
+{
+ return lhs.GetCallFrameAddress() != rhs.GetCallFrameAddress() || lhs.GetStartAddress() != rhs.GetStartAddress();
+}
+
+bool
+lldb_private::operator< (const StackID& lhs, const StackID& rhs)
+{
+ return lhs.GetCallFrameAddress() < rhs.GetCallFrameAddress();
+}
+
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
new file mode 100644
index 00000000000..48f2ea70fd0
--- /dev/null
+++ b/lldb/source/Target/Target.cpp
@@ -0,0 +1,707 @@
+//===-- Target.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/Target.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointResolver.h"
+#include "lldb/Breakpoint/BreakpointResolverAddress.h"
+#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
+#include "lldb/Breakpoint/BreakpointResolverName.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Host.h"
+#include "lldb/lldb-private-log.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Core/Debugger.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Target constructor
+//----------------------------------------------------------------------
+Target::Target() :
+ Broadcaster("Target"),
+ m_images(),
+ m_breakpoint_list (false),
+ m_internal_breakpoint_list (true),
+ m_process_sp(),
+ m_triple(),
+ m_search_filter_sp(),
+ m_image_search_paths (ImageSearchPathsChanged, this),
+ m_scratch_ast_context_ap(NULL)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT);
+ if (log)
+ log->Printf ("%p Target::Target()", this);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Target::~Target()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT);
+ if (log)
+ log->Printf ("%p Target::~Target()", this);
+ DeleteCurrentProcess ();
+}
+
+void
+Target::Dump (Stream *s)
+{
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ s->PutCString("Target\n");
+ s->IndentMore();
+ m_images.Dump(s);
+ m_breakpoint_list.Dump(s);
+ m_internal_breakpoint_list.Dump(s);
+// if (m_process_sp.get())
+// m_process_sp->Dump(s);
+ s->IndentLess();
+}
+
+void
+Target::DeleteCurrentProcess ()
+{
+ if (m_process_sp.get())
+ {
+ if (m_process_sp->IsAlive())
+ m_process_sp->Destroy();
+ else
+ m_process_sp->Finalize();
+
+ // Do any cleanup of the target we need to do between process instances.
+ // NB It is better to do this before destroying the process in case the
+ // clean up needs some help from the process.
+ m_breakpoint_list.ClearAllBreakpointSites();
+ m_internal_breakpoint_list.ClearAllBreakpointSites();
+ m_process_sp.reset();
+ }
+}
+
+const lldb::ProcessSP &
+Target::CreateProcess (Listener &listener, const char *plugin_name)
+{
+ DeleteCurrentProcess ();
+ m_process_sp.reset(Process::FindPlugin(*this, plugin_name, listener));
+ return m_process_sp;
+}
+
+const lldb::ProcessSP &
+Target::GetProcessSP () const
+{
+ return m_process_sp;
+}
+
+lldb::TargetSP
+Target::GetSP()
+{
+ return Debugger::GetSharedInstance().GetTargetList().GetTargetSP(this);
+}
+
+BreakpointList &
+Target::GetBreakpointList(bool internal)
+{
+ if (internal)
+ return m_internal_breakpoint_list;
+ else
+ return m_breakpoint_list;
+}
+
+const BreakpointList &
+Target::GetBreakpointList(bool internal) const
+{
+ if (internal)
+ return m_internal_breakpoint_list;
+ else
+ return m_breakpoint_list;
+}
+
+BreakpointSP
+Target::GetBreakpointByID (break_id_t break_id)
+{
+ BreakpointSP bp_sp;
+
+ if (LLDB_BREAK_ID_IS_INTERNAL (break_id))
+ bp_sp = m_internal_breakpoint_list.FindBreakpointByID (break_id);
+ else
+ bp_sp = m_breakpoint_list.FindBreakpointByID (break_id);
+
+ return bp_sp;
+}
+
+BreakpointSP
+Target::CreateBreakpoint (const FileSpec *containingModule, const FileSpec &file, uint32_t line_no, bool check_inlines, bool internal)
+{
+ SearchFilterSP filter_sp(GetSearchFilterForModule (containingModule));
+ BreakpointResolverSP resolver_sp(new BreakpointResolverFileLine (NULL, file, line_no, check_inlines));
+ return CreateBreakpoint (filter_sp, resolver_sp, internal);
+}
+
+
+BreakpointSP
+Target::CreateBreakpoint (lldb::addr_t load_addr, bool internal)
+{
+ BreakpointSP bp_sp;
+ Address so_addr;
+ // Attempt to resolve our load address if possible, though it is ok if
+ // it doesn't resolve to section/offset.
+
+ Process *process = GetProcessSP().get();
+ if (process && process->ResolveLoadAddress(load_addr, so_addr))
+ bp_sp = CreateBreakpoint(so_addr, internal);
+ return bp_sp;
+}
+
+BreakpointSP
+Target::CreateBreakpoint (Address &addr, bool internal)
+{
+ TargetSP target_sp = this->GetSP();
+ SearchFilterSP filter_sp(new SearchFilter (target_sp));
+ BreakpointResolverSP resolver_sp (new BreakpointResolverAddress (NULL, addr));
+ return CreateBreakpoint (filter_sp, resolver_sp, internal);
+}
+
+BreakpointSP
+Target::CreateBreakpoint (FileSpec *containingModule, const char *func_name, bool internal)
+{
+ SearchFilterSP filter_sp(GetSearchFilterForModule (containingModule));
+ BreakpointResolverSP resolver_sp (new BreakpointResolverName (NULL, func_name));
+ return CreateBreakpoint (filter_sp, resolver_sp, internal);
+}
+
+
+SearchFilterSP
+Target::GetSearchFilterForModule (const FileSpec *containingModule)
+{
+ SearchFilterSP filter_sp;
+ lldb::TargetSP target_sp = this->GetSP();
+ if (containingModule != NULL)
+ {
+ // TODO: We should look into sharing module based search filters
+ // across many breakpoints like we do for the simple target based one
+ filter_sp.reset (new SearchFilterByModule (target_sp, *containingModule));
+ }
+ else
+ {
+ if (m_search_filter_sp.get() == NULL)
+ m_search_filter_sp.reset (new SearchFilter (target_sp));
+ filter_sp = m_search_filter_sp;
+ }
+ return filter_sp;
+}
+
+BreakpointSP
+Target::CreateBreakpoint (FileSpec *containingModule, RegularExpression &func_regex, bool internal)
+{
+ SearchFilterSP filter_sp(GetSearchFilterForModule (containingModule));
+ BreakpointResolverSP resolver_sp(new BreakpointResolverName (NULL, func_regex));
+
+ return CreateBreakpoint (filter_sp, resolver_sp, internal);
+}
+
+BreakpointSP
+Target::CreateBreakpoint (SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool internal)
+{
+ BreakpointSP bp_sp;
+ if (filter_sp && resolver_sp)
+ {
+ bp_sp.reset(new Breakpoint (*this, filter_sp, resolver_sp));
+ resolver_sp->SetBreakpoint (bp_sp.get());
+
+ if (internal)
+ m_internal_breakpoint_list.Add (bp_sp);
+ else
+ m_breakpoint_list.Add (bp_sp);
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+ if (log)
+ {
+ StreamString s;
+ bp_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
+ log->Printf ("Target::%s (internal = %s) => break_id = %s\n", __FUNCTION__, internal ? "yes" : "no", s.GetData());
+ }
+
+ // Broadcast the breakpoint creation event.
+ if (!internal && EventTypeHasListeners(eBroadcastBitBreakpointChanged))
+ {
+ BroadcastEvent (eBroadcastBitBreakpointChanged,
+ new Breakpoint::BreakpointEventData (Breakpoint::BreakpointEventData::eBreakpointAdded, bp_sp));
+ }
+
+ bp_sp->ResolveBreakpoint();
+ }
+ return bp_sp;
+}
+
+void
+Target::RemoveAllBreakpoints (bool internal_also)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+ if (log)
+ log->Printf ("Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no");
+
+ m_breakpoint_list.RemoveAll();
+ if (internal_also)
+ m_internal_breakpoint_list.RemoveAll();
+}
+
+void
+Target::DisableAllBreakpoints (bool internal_also)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+ if (log)
+ log->Printf ("Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no");
+
+ m_breakpoint_list.SetEnabledAll (false);
+ if (internal_also)
+ m_internal_breakpoint_list.SetEnabledAll (false);
+}
+
+void
+Target::EnableAllBreakpoints (bool internal_also)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+ if (log)
+ log->Printf ("Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no");
+
+ m_breakpoint_list.SetEnabledAll (true);
+ if (internal_also)
+ m_internal_breakpoint_list.SetEnabledAll (true);
+}
+
+bool
+Target::RemoveBreakpointByID (break_id_t break_id)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+ if (log)
+ log->Printf ("Target::%s (break_id = %i, internal = %s)\n", __FUNCTION__, break_id, LLDB_BREAK_ID_IS_INTERNAL (break_id) ? "yes" : "no");
+
+ if (DisableBreakpointByID (break_id))
+ {
+ if (LLDB_BREAK_ID_IS_INTERNAL (break_id))
+ m_internal_breakpoint_list.Remove(break_id);
+ else
+ m_breakpoint_list.Remove(break_id);
+ return true;
+ }
+ return false;
+}
+
+bool
+Target::DisableBreakpointByID (break_id_t break_id)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+ if (log)
+ log->Printf ("Target::%s (break_id = %i, internal = %s)\n", __FUNCTION__, break_id, LLDB_BREAK_ID_IS_INTERNAL (break_id) ? "yes" : "no");
+
+ BreakpointSP bp_sp;
+
+ if (LLDB_BREAK_ID_IS_INTERNAL (break_id))
+ bp_sp = m_internal_breakpoint_list.FindBreakpointByID (break_id);
+ else
+ bp_sp = m_breakpoint_list.FindBreakpointByID (break_id);
+ if (bp_sp)
+ {
+ bp_sp->SetEnabled (false);
+ return true;
+ }
+ return false;
+}
+
+bool
+Target::EnableBreakpointByID (break_id_t break_id)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+ if (log)
+ log->Printf ("Target::%s (break_id = %i, internal = %s)\n",
+ __FUNCTION__,
+ break_id,
+ LLDB_BREAK_ID_IS_INTERNAL (break_id) ? "yes" : "no");
+
+ BreakpointSP bp_sp;
+
+ if (LLDB_BREAK_ID_IS_INTERNAL (break_id))
+ bp_sp = m_internal_breakpoint_list.FindBreakpointByID (break_id);
+ else
+ bp_sp = m_breakpoint_list.FindBreakpointByID (break_id);
+
+ if (bp_sp)
+ {
+ bp_sp->SetEnabled (true);
+ return true;
+ }
+ return false;
+}
+
+ModuleSP
+Target::GetExecutableModule ()
+{
+ ModuleSP executable_sp;
+ if (m_images.GetSize() > 0)
+ executable_sp = m_images.GetModuleAtIndex(0);
+ return executable_sp;
+}
+
+void
+Target::SetExecutableModule (ModuleSP& executable_sp, bool get_dependent_files)
+{
+ m_images.Clear();
+ m_scratch_ast_context_ap.reset();
+
+ if (executable_sp.get())
+ {
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "Target::SetExecutableModule (executable = '%s/%s')",
+ executable_sp->GetFileSpec().GetDirectory().AsCString(),
+ executable_sp->GetFileSpec().GetFilename().AsCString());
+
+ m_images.Append(executable_sp); // The first image is our exectuable file
+
+ ArchSpec exe_arch = executable_sp->GetArchitecture();
+ FileSpecList dependent_files;
+ ObjectFile * executable_objfile = executable_sp->GetObjectFile();
+ if (executable_objfile == NULL)
+ {
+
+ FileSpec bundle_executable(executable_sp->GetFileSpec());
+ if (Host::ResolveExecutableInBundle (&bundle_executable))
+ {
+ ModuleSP bundle_exe_module_sp(GetSharedModule(bundle_executable,
+ exe_arch));
+ SetExecutableModule (bundle_exe_module_sp, get_dependent_files);
+ if (bundle_exe_module_sp->GetObjectFile() != NULL)
+ executable_sp = bundle_exe_module_sp;
+ return;
+ }
+ }
+
+ if (executable_objfile)
+ {
+ executable_objfile->GetDependentModules(dependent_files);
+ for (uint32_t i=0; i<dependent_files.GetSize(); i++)
+ {
+ ModuleSP image_module_sp(GetSharedModule(dependent_files.GetFileSpecPointerAtIndex(i),
+ exe_arch));
+ if (image_module_sp.get())
+ {
+ //image_module_sp->Dump(&s);// REMOVE THIS, DEBUG ONLY
+ ObjectFile *objfile = image_module_sp->GetObjectFile();
+ if (objfile)
+ objfile->GetDependentModules(dependent_files);
+ }
+ }
+ }
+
+ // Now see if we know the target triple, and if so, create our scratch AST context:
+ ConstString target_triple;
+ if (GetTargetTriple(target_triple))
+ {
+ m_scratch_ast_context_ap.reset (new ClangASTContext(target_triple.GetCString()));
+ }
+ }
+}
+
+
+ModuleList&
+Target::GetImages ()
+{
+ return m_images;
+}
+
+ArchSpec
+Target::GetArchitecture () const
+{
+ ArchSpec arch;
+ if (m_images.GetSize() > 0)
+ {
+ Module *exe_module = m_images.GetModulePointerAtIndex(0);
+ if (exe_module)
+ arch = exe_module->GetArchitecture();
+ }
+ return arch;
+}
+
+
+
+bool
+Target::GetTargetTriple(ConstString &triple)
+{
+ triple.Clear();
+
+ if (m_triple)
+ {
+ triple = m_triple;
+ }
+ else
+ {
+ Module *exe_module = GetExecutableModule().get();
+ if (exe_module)
+ {
+ ObjectFile *objfile = exe_module->GetObjectFile();
+ if (objfile)
+ {
+ objfile->GetTargetTriple(m_triple);
+ triple = m_triple;
+ }
+ }
+ }
+ return !triple.IsEmpty();
+}
+
+void
+Target::ModuleAdded (ModuleSP &module_sp)
+{
+ // A module is being added to this target for the first time
+ ModuleList module_list;
+ module_list.Append(module_sp);
+ ModulesDidLoad (module_list);
+}
+
+void
+Target::ModuleUpdated (ModuleSP &old_module_sp, ModuleSP &new_module_sp)
+{
+ // A module is being added to this target for the first time
+ ModuleList module_list;
+ module_list.Append (old_module_sp);
+ ModulesDidUnload (module_list);
+ module_list.Clear ();
+ module_list.Append (new_module_sp);
+ ModulesDidLoad (module_list);
+}
+
+void
+Target::ModulesDidLoad (ModuleList &module_list)
+{
+ m_breakpoint_list.UpdateBreakpoints (module_list, true);
+ // TODO: make event data that packages up the module_list
+ BroadcastEvent (eBroadcastBitModulesLoaded, NULL);
+}
+
+void
+Target::ModulesDidUnload (ModuleList &module_list)
+{
+ m_breakpoint_list.UpdateBreakpoints (module_list, false);
+ // TODO: make event data that packages up the module_list
+ BroadcastEvent (eBroadcastBitModulesUnloaded, NULL);
+}
+
+size_t
+Target::ReadMemory
+(
+ lldb::AddressType addr_type,
+ lldb::addr_t addr,
+ void *dst,
+ size_t dst_len,
+ Error &error,
+ ObjectFile* objfile
+)
+{
+ size_t bytes_read = 0;
+ error.Clear();
+ switch (addr_type)
+ {
+ case eAddressTypeFile:
+ if (objfile)
+ {
+ if (m_process_sp.get())
+ {
+ // If we have an execution context with a process, lets try and
+ // resolve the file address in "objfile" and read it from the
+ // process
+ Address so_addr(addr, objfile->GetSectionList());
+ lldb::addr_t load_addr = so_addr.GetLoadAddress(m_process_sp.get());
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ {
+ if (objfile->GetFileSpec())
+ error.SetErrorStringWithFormat("0x%llx can't be resolved, %s in not currently loaded.\n", addr, objfile->GetFileSpec().GetFilename().AsCString());
+ else
+ error.SetErrorStringWithFormat("0x%llx can't be resolved.\n", addr, objfile->GetFileSpec().GetFilename().AsCString());
+ }
+ else
+ {
+ bytes_read = m_process_sp->ReadMemory(load_addr, dst, dst_len, error);
+ if (bytes_read != dst_len)
+ {
+ if (error.Success())
+ {
+ if (bytes_read == 0)
+ error.SetErrorStringWithFormat("Read memory from 0x%llx failed.\n", load_addr);
+ else
+ error.SetErrorStringWithFormat("Only %zu of %zu bytes were read from memory at 0x%llx.\n", bytes_read, dst_len, load_addr);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Try and read the file based address from the object file's
+ // section data.
+ }
+ }
+ break;
+
+ case eAddressTypeLoad:
+ if (m_process_sp.get())
+ {
+ bytes_read = m_process_sp->ReadMemory(addr, dst, dst_len, error);
+ if (bytes_read != dst_len)
+ {
+ if (error.Success())
+ {
+ if (bytes_read == 0)
+ error.SetErrorStringWithFormat("Read memory from 0x%llx failed.\n", addr);
+ else
+ error.SetErrorStringWithFormat("Only %zu of %zu bytes were read from memory at 0x%llx.\n", bytes_read, dst_len, addr);
+ }
+ }
+ }
+ else
+ error.SetErrorStringWithFormat("Need valid process to read load address.\n");
+ break;
+
+ case eAddressTypeHost:
+ // The address is an address in this process, so just copy it
+ ::memcpy (dst, (uint8_t*)NULL + addr, dst_len);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("Unsupported lldb::AddressType value (%i).\n", addr_type);
+ break;
+ }
+ return bytes_read;
+}
+
+
+ModuleSP
+Target::GetSharedModule
+(
+ const FileSpec& file_spec,
+ const ArchSpec& arch,
+ const UUID *uuid_ptr,
+ const ConstString *object_name,
+ off_t object_offset,
+ Error *error_ptr
+)
+{
+ // Don't pass in the UUID so we can tell if we have a stale value in our list
+ ModuleSP old_module_sp; // This will get filled in if we have a new version of the library
+ bool did_create_module = false;
+ ModuleSP module_sp;
+
+ // If there are image search path entries, try to use them first to acquire a suitable image.
+
+ Error error;
+
+ if (m_image_search_paths.GetSize())
+ {
+ FileSpec transformed_spec;
+ if (m_image_search_paths.RemapPath (file_spec.GetDirectory(), transformed_spec.GetDirectory()))
+ {
+ transformed_spec.GetFilename() = file_spec.GetFilename();
+ error = ModuleList::GetSharedModule (transformed_spec, arch, uuid_ptr, object_name, object_offset, module_sp, &old_module_sp, &did_create_module);
+ }
+ }
+
+ // If a module hasn't been found yet, use the unmodified path.
+
+ if (!module_sp)
+ {
+ error = (ModuleList::GetSharedModule (file_spec, arch, uuid_ptr, object_name, object_offset, module_sp, &old_module_sp, &did_create_module));
+ }
+
+ if (module_sp)
+ {
+ m_images.Append (module_sp);
+ if (did_create_module)
+ {
+ if (old_module_sp && m_images.GetIndexForModule (old_module_sp.get()) != LLDB_INVALID_INDEX32)
+ ModuleUpdated(old_module_sp, module_sp);
+ else
+ ModuleAdded(module_sp);
+ }
+ }
+ if (error_ptr)
+ *error_ptr = error;
+ return module_sp;
+}
+
+
+Target *
+Target::CalculateTarget ()
+{
+ return this;
+}
+
+Process *
+Target::CalculateProcess ()
+{
+ return NULL;
+}
+
+Thread *
+Target::CalculateThread ()
+{
+ return NULL;
+}
+
+StackFrame *
+Target::CalculateStackFrame ()
+{
+ return NULL;
+}
+
+void
+Target::Calculate (ExecutionContext &exe_ctx)
+{
+ exe_ctx.target = this;
+ exe_ctx.process = NULL; // Do NOT fill in process...
+ exe_ctx.thread = NULL;
+ exe_ctx.frame = NULL;
+}
+
+PathMappingList &
+Target::GetImageSearchPathList ()
+{
+ return m_image_search_paths;
+}
+
+void
+Target::ImageSearchPathsChanged
+(
+ const PathMappingList &path_list,
+ void *baton
+)
+{
+ Target *target = (Target *)baton;
+ if (target->m_images.GetSize() > 1)
+ {
+ ModuleSP exe_module_sp (target->GetExecutableModule());
+ if (exe_module_sp)
+ {
+ target->m_images.Clear();
+ target->SetExecutableModule (exe_module_sp, true);
+ }
+ }
+}
+
+ClangASTContext *
+Target::GetScratchClangASTContext()
+{
+ return m_scratch_ast_context_ap.get();
+}
diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp
new file mode 100644
index 00000000000..d92940003d6
--- /dev/null
+++ b/lldb/source/Target/TargetList.cpp
@@ -0,0 +1,342 @@
+//===-- TargetList.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/TargetList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+//----------------------------------------------------------------------
+// TargetList constructor
+//----------------------------------------------------------------------
+TargetList::TargetList() :
+ Broadcaster("TargetList"),
+ m_target_list(),
+ m_target_list_mutex (Mutex::eMutexTypeRecursive),
+ m_current_target_idx (0)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+TargetList::~TargetList()
+{
+ Mutex::Locker locker(m_target_list_mutex);
+ m_target_list.clear();
+}
+
+Error
+TargetList::CreateTarget
+(
+ const FileSpec& file,
+ const ArchSpec& arch,
+ const UUID *uuid_ptr,
+ bool get_dependent_files,
+ TargetSP &target_sp
+)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "TargetList::CreateTarget (file = '%s/%s', arch = '%s', uuid = %p)",
+ file.GetDirectory().AsCString(),
+ file.GetFilename().AsCString(),
+ arch.AsCString(),
+ uuid_ptr);
+ ModuleSP exe_module_sp;
+ FileSpec resolved_file(file);
+ if (!Host::ResolveExecutableInBundle (&resolved_file))
+ resolved_file = file;
+
+ Error error = ModuleList::GetSharedModule(resolved_file,
+ arch,
+ uuid_ptr,
+ NULL,
+ 0,
+ exe_module_sp,
+ NULL,
+ NULL);
+ if (exe_module_sp)
+ {
+ target_sp.reset(new Target);
+ target_sp->SetExecutableModule (exe_module_sp, get_dependent_files);
+
+ if (target_sp.get())
+ {
+ Mutex::Locker locker(m_target_list_mutex);
+ m_current_target_idx = m_target_list.size();
+ m_target_list.push_back(target_sp);
+ }
+
+// target_sp.reset(new Target);
+// // Let the target resolve any funky bundle paths before we try and get
+// // the object file...
+// target_sp->SetExecutableModule (exe_module_sp, get_dependent_files);
+// if (exe_module_sp->GetObjectFile() == NULL)
+// {
+// error.SetErrorStringWithFormat("%s%s%s: doesn't contain architecture %s",
+// file.GetDirectory().AsCString(),
+// file.GetDirectory() ? "/" : "",
+// file.GetFilename().AsCString(),
+// arch.AsCString());
+// }
+// else
+// {
+// if (target_sp.get())
+// {
+// error.Clear();
+// Mutex::Locker locker(m_target_list_mutex);
+// m_current_target_idx = m_target_list.size();
+// m_target_list.push_back(target_sp);
+// }
+// }
+ }
+ else
+ {
+ target_sp.reset();
+ }
+
+ return error;
+}
+
+bool
+TargetList::DeleteTarget (TargetSP &target_sp)
+{
+ Mutex::Locker locker(m_target_list_mutex);
+ collection::iterator pos, end = m_target_list.end();
+
+ for (pos = m_target_list.begin(); pos != end; ++pos)
+ {
+ if (pos->get() == target_sp.get())
+ {
+ m_target_list.erase(pos);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+TargetSP
+TargetList::FindTargetWithExecutableAndArchitecture
+(
+ const FileSpec &exe_file_spec,
+ const ArchSpec *exe_arch_ptr
+) const
+{
+ Mutex::Locker locker (m_target_list_mutex);
+ TargetSP target_sp;
+ bool full_match = exe_file_spec.GetDirectory();
+
+ collection::const_iterator pos, end = m_target_list.end();
+ for (pos = m_target_list.begin(); pos != end; ++pos)
+ {
+ ModuleSP module_sp ((*pos)->GetExecutableModule());
+
+ if (module_sp)
+ {
+ if (FileSpec::Equal (exe_file_spec, module_sp->GetFileSpec(), full_match))
+ {
+ if (exe_arch_ptr)
+ {
+ if (*exe_arch_ptr != module_sp->GetArchitecture())
+ continue;
+ }
+ target_sp = *pos;
+ break;
+ }
+ }
+ }
+ return target_sp;
+}
+
+TargetSP
+TargetList::FindTargetWithProcessID (lldb::pid_t pid) const
+{
+ Mutex::Locker locker(m_target_list_mutex);
+ TargetSP target_sp;
+ collection::const_iterator pos, end = m_target_list.end();
+ for (pos = m_target_list.begin(); pos != end; ++pos)
+ {
+ Process* process = (*pos)->GetProcessSP().get();
+ if (process && process->GetID() == pid)
+ {
+ target_sp = *pos;
+ break;
+ }
+ }
+ return target_sp;
+}
+
+
+TargetSP
+TargetList::FindTargetWithProcess (Process *process) const
+{
+ TargetSP target_sp;
+ if (process)
+ {
+ Mutex::Locker locker(m_target_list_mutex);
+ collection::const_iterator pos, end = m_target_list.end();
+ for (pos = m_target_list.begin(); pos != end; ++pos)
+ {
+ if (process == (*pos)->GetProcessSP().get())
+ {
+ target_sp = *pos;
+ break;
+ }
+ }
+ }
+ return target_sp;
+}
+
+TargetSP
+TargetList::GetTargetSP (Target *target) const
+{
+ TargetSP target_sp;
+ if (target)
+ {
+ Mutex::Locker locker(m_target_list_mutex);
+ collection::const_iterator pos, end = m_target_list.end();
+ for (pos = m_target_list.begin(); pos != end; ++pos)
+ {
+ if (target == (*pos).get())
+ {
+ target_sp = *pos;
+ break;
+ }
+ }
+ }
+ return target_sp;
+}
+
+uint32_t
+TargetList::SendAsyncInterrupt (lldb::pid_t pid)
+{
+ uint32_t num_async_interrupts_sent = 0;
+
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ TargetSP target_sp(FindTargetWithProcessID (pid));
+ if (target_sp.get())
+ {
+ Process* process = target_sp->GetProcessSP().get();
+ if (process)
+ {
+ process->BroadcastEvent (Process::eBroadcastBitInterrupt, NULL);
+ ++num_async_interrupts_sent;
+ }
+ }
+ }
+ else
+ {
+ // We don't have a valid pid to broadcast to, so broadcast to the target
+ // list's async broadcaster...
+ BroadcastEvent (Process::eBroadcastBitInterrupt, NULL);
+ }
+
+ return num_async_interrupts_sent;
+}
+
+uint32_t
+TargetList::SignalIfRunning (lldb::pid_t pid, int signo)
+{
+ uint32_t num_signals_sent = 0;
+ Process *process = NULL;
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ // Signal all processes with signal
+ Mutex::Locker locker(m_target_list_mutex);
+ collection::iterator pos, end = m_target_list.end();
+ for (pos = m_target_list.begin(); pos != end; ++pos)
+ {
+ process = (*pos)->GetProcessSP().get();
+ if (process)
+ {
+ if (process->IsAlive())
+ {
+ ++num_signals_sent;
+ process->Signal (signo);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Signal a specific process with signal
+ TargetSP target_sp(FindTargetWithProcessID (pid));
+ if (target_sp.get())
+ {
+ process = target_sp->GetProcessSP().get();
+ if (process)
+ {
+ if (process->IsAlive())
+ {
+ ++num_signals_sent;
+ process->Signal (signo);
+ }
+ }
+ }
+ }
+ return num_signals_sent;
+}
+
+int
+TargetList::GetNumTargets () const
+{
+ Mutex::Locker locker (m_target_list_mutex);
+ return m_target_list.size();
+}
+
+lldb::TargetSP
+TargetList::GetTargetAtIndex (uint32_t idx) const
+{
+ TargetSP target_sp;
+ Mutex::Locker locker (m_target_list_mutex);
+ if (idx < m_target_list.size())
+ target_sp = m_target_list[idx];
+ return target_sp;
+}
+
+uint32_t
+TargetList::SetCurrentTarget (Target* target)
+{
+ Mutex::Locker locker (m_target_list_mutex);
+ collection::const_iterator pos,
+ begin = m_target_list.begin(),
+ end = m_target_list.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (pos->get() == target)
+ {
+ m_current_target_idx = std::distance (begin, pos);
+ return m_current_target_idx;
+ }
+ }
+ m_current_target_idx = 0;
+ return m_current_target_idx;
+}
+
+lldb::TargetSP
+TargetList::GetCurrentTarget ()
+{
+ Mutex::Locker locker (m_target_list_mutex);
+ if (m_current_target_idx >= m_target_list.size())
+ m_current_target_idx = 0;
+ return GetTargetAtIndex (m_current_target_idx);
+}
diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp
new file mode 100644
index 00000000000..2f852cc3eae
--- /dev/null
+++ b/lldb/source/Target/Thread.cpp
@@ -0,0 +1,1121 @@
+//===-- Thread.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-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Target/ThreadPlanContinue.h"
+#include "lldb/Target/ThreadPlanBase.h"
+#include "lldb/Target/ThreadPlanStepInstruction.h"
+#include "lldb/Target/ThreadPlanStepOut.h"
+#include "lldb/Target/ThreadPlanStepOverBreakpoint.h"
+#include "lldb/Target/ThreadPlanStepThrough.h"
+#include "lldb/Target/ThreadPlanStepInRange.h"
+#include "lldb/Target/ThreadPlanStepOverRange.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Target/ThreadPlanStepUntil.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Thread::Thread (Process &process, lldb::tid_t tid) :
+ UserID (tid),
+ m_index_id (process.GetNextThreadIndexID ()),
+ m_reg_context_sp (),
+ m_process (process),
+ m_state (eStateUnloaded),
+ m_plan_stack (),
+ m_immediate_plan_stack(),
+ m_completed_plan_stack(),
+ m_state_mutex (Mutex::eMutexTypeRecursive),
+ m_frames (),
+ m_current_frame_idx (0),
+ m_resume_signal (LLDB_INVALID_SIGNAL_NUMBER),
+ m_resume_state (eStateRunning)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT);
+ if (log)
+ log->Printf ("%p Thread::Thread(tid = 0x%4.4x)", this, GetID());
+
+ QueueFundamentalPlan(true);
+}
+
+
+Thread::~Thread()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT);
+ if (log)
+ log->Printf ("%p Thread::~Thread(tid = 0x%4.4x)", this, GetID());
+}
+
+int
+Thread::GetResumeSignal () const
+{
+ return m_resume_signal;
+}
+
+void
+Thread::SetResumeSignal (int signal)
+{
+ m_resume_signal = signal;
+}
+
+StateType
+Thread::GetResumeState () const
+{
+ return m_resume_state;
+}
+
+void
+Thread::SetResumeState (StateType state)
+{
+ m_resume_state = state;
+}
+
+Thread::StopInfo::StopInfo(Thread *thread) :
+ m_reason (eStopReasonInvalid),
+ m_description (),
+ m_thread (thread),
+ m_details ()
+{
+ m_description[0] = '\0';
+}
+
+Thread::StopInfo::~StopInfo()
+{
+}
+
+
+void
+Thread::StopInfo::Clear()
+{
+ m_reason = eStopReasonInvalid;
+ m_completed_plan_sp.reset();
+ m_description[0] = '\0';
+ ::bzero (&m_details, sizeof(m_details));
+}
+
+StopReason
+Thread::StopInfo::GetStopReason() const
+{
+ return m_reason;
+}
+
+const char *
+Thread::StopInfo::GetStopDescription() const
+{
+ if (m_description[0])
+ return m_description;
+ return NULL;
+}
+
+void
+Thread::StopInfo::SetStopDescription(const char *desc)
+{
+ if (desc && desc[0])
+ {
+ ::snprintf (m_description, sizeof(m_description), "%s", desc);
+ }
+ else
+ {
+ m_description[0] = '\0';
+ }
+}
+
+void
+Thread::StopInfo::SetThread (Thread* thread)
+{
+ m_thread = thread;
+}
+
+Thread *
+Thread::StopInfo::GetThread ()
+{
+ return m_thread;
+}
+
+lldb::user_id_t
+Thread::StopInfo::GetBreakpointSiteID() const
+{
+ if (m_reason == eStopReasonBreakpoint)
+ return m_details.breakpoint.bp_site_id;
+ return LLDB_INVALID_BREAK_ID;
+}
+
+void
+Thread::StopInfo::SetStopReasonWithBreakpointSiteID (lldb::user_id_t bp_site_id)
+{
+ m_reason = eStopReasonBreakpoint;
+ m_details.breakpoint.bp_site_id = bp_site_id;
+}
+
+lldb::user_id_t
+Thread::StopInfo::GetWatchpointID() const
+{
+ if (m_reason == eStopReasonWatchpoint)
+ return m_details.watchpoint.watch_id;
+ return LLDB_INVALID_WATCH_ID;
+}
+
+void
+Thread::StopInfo::SetStopReasonWithWatchpointID (lldb::user_id_t watch_id)
+{
+ m_reason = eStopReasonWatchpoint;
+ m_details.watchpoint.watch_id = watch_id;
+}
+
+
+int
+Thread::StopInfo::GetSignal() const
+{
+ if (m_reason == eStopReasonSignal)
+ return m_details.signal.signo;
+ return 0;
+}
+
+lldb::user_id_t
+Thread::StopInfo::GetPlanID() const
+{
+ if (m_reason == eStopReasonPlanComplete)
+ return m_completed_plan_sp->GetID();
+ return LLDB_INVALID_UID;
+}
+
+void
+Thread::StopInfo::SetStopReasonWithSignal (int signo)
+{
+ m_reason = eStopReasonSignal;
+ m_details.signal.signo = signo;
+}
+
+void
+Thread::StopInfo::SetStopReasonToTrace ()
+{
+ m_reason = eStopReasonTrace;
+}
+
+uint32_t
+Thread::StopInfo::GetExceptionType() const
+{
+ if (m_reason == eStopReasonException)
+ return m_details.exception.type;
+ return 0;
+}
+
+size_t
+Thread::StopInfo::GetExceptionDataCount() const
+{
+ if (m_reason == eStopReasonException)
+ return m_details.exception.data_count;
+ return 0;
+}
+
+void
+Thread::StopInfo::SetStopReasonWithException (uint32_t exc_type, size_t exc_data_count)
+{
+ m_reason = eStopReasonException;
+ m_details.exception.type = exc_type;
+ m_details.exception.data_count = exc_data_count;
+}
+
+void
+Thread::StopInfo::SetStopReasonWithPlan (ThreadPlanSP &thread_plan_sp)
+{
+ m_reason = eStopReasonPlanComplete;
+ m_completed_plan_sp = thread_plan_sp;
+}
+
+void
+Thread::StopInfo::SetStopReasonToNone ()
+{
+ Clear();
+ m_reason = eStopReasonNone;
+}
+
+lldb::addr_t
+Thread::StopInfo::GetExceptionDataAtIndex (uint32_t idx) const
+{
+ if (m_reason == eStopReasonException && idx < m_details.exception.data_count)
+ return m_details.exception.data[idx];
+ return 0;
+
+}
+
+
+bool
+Thread::StopInfo::SetExceptionDataAtIndex (uint32_t idx, lldb::addr_t data)
+{
+ if (m_reason == eStopReasonException && idx < m_details.exception.data_count)
+ {
+ m_details.exception.data[idx] = data;
+ return true;
+ }
+ return false;
+}
+
+void
+Thread::StopInfo::Dump (Stream *s) const
+{
+ if (m_description[0])
+ s->Printf("%s", m_description);
+ else
+ {
+ switch (m_reason)
+ {
+ case eStopReasonInvalid:
+ s->PutCString("invalid");
+ break;
+
+ case eStopReasonNone:
+ s->PutCString("none");
+ break;
+
+ case eStopReasonTrace:
+ s->PutCString("trace");
+ break;
+
+ case eStopReasonBreakpoint:
+ {
+ bool no_details = true;
+ s->PutCString ("breakpoint ");
+ if (m_thread)
+ {
+ BreakpointSiteSP bp_site_sp = m_thread->GetProcess().GetBreakpointSiteList().FindByID(m_details.breakpoint.bp_site_id);
+ if (bp_site_sp)
+ {
+ bp_site_sp->GetDescription(s, lldb::eDescriptionLevelBrief);
+ no_details = false;
+ }
+ }
+
+ if (no_details)
+ s->Printf ("site id: %d", m_details.breakpoint.bp_site_id);
+ }
+ break;
+
+ case eStopReasonWatchpoint:
+ s->Printf("watchpoint (site id = %u)", m_details.watchpoint.watch_id);
+ break;
+
+ case eStopReasonSignal:
+ {
+ s->Printf("signal: signo = %i", m_details.signal.signo);
+ const char * signal_name = m_thread->GetProcess().GetUnixSignals().GetSignalAsCString (m_details.signal.signo);
+ if (signal_name)
+ s->Printf(" (%s)", signal_name);
+ }
+ break;
+
+ case eStopReasonException:
+ {
+ s->Printf("exception: type = 0x%8.8x, data_count = %zu", m_details.exception.type, m_details.exception.data_count);
+ uint32_t i;
+ for (i=0; i<m_details.exception.data_count; ++i)
+ {
+ s->Printf(", data[%u] = 0x%8.8llx", i, m_details.exception.data[i]);
+ }
+ }
+ break;
+
+ case eStopReasonPlanComplete:
+ {
+ m_completed_plan_sp->GetDescription (s, lldb::eDescriptionLevelBrief);
+ }
+ break;
+ }
+ }
+}
+
+bool
+Thread::GetStopInfo (Thread::StopInfo *stop_info)
+{
+ stop_info->SetThread(this);
+ ThreadPlanSP completed_plan = GetCompletedPlan();
+ if (completed_plan != NULL)
+ {
+ stop_info->Clear ();
+ stop_info->SetStopReasonWithPlan (completed_plan);
+ return true;
+ }
+ else
+ return GetRawStopReason (stop_info);
+}
+
+bool
+Thread::ThreadStoppedForAReason (void)
+{
+ Thread::StopInfo stop_info;
+ stop_info.SetThread(this);
+ if (GetRawStopReason (&stop_info))
+ {
+ StopReason reason = stop_info.GetStopReason();
+ if (reason == eStopReasonInvalid || reason == eStopReasonNone)
+ return false;
+ else
+ return true;
+ }
+ else
+ return false;
+}
+
+StateType
+Thread::GetState() const
+{
+ // If any other threads access this we will need a mutex for it
+ Mutex::Locker locker(m_state_mutex);
+ return m_state;
+}
+
+void
+Thread::SetState(StateType state)
+{
+ Mutex::Locker locker(m_state_mutex);
+ m_state = state;
+}
+
+void
+Thread::WillStop()
+{
+ ThreadPlan *current_plan = GetCurrentPlan();
+
+ // FIXME: I may decide to disallow threads with no plans. In which
+ // case this should go to an assert.
+
+ if (!current_plan)
+ return;
+
+ current_plan->WillStop();
+}
+
+void
+Thread::SetupForResume ()
+{
+ if (GetResumeState() != eStateSuspended)
+ {
+
+ // If we're at a breakpoint push the step-over breakpoint plan. Do this before
+ // telling the current plan it will resume, since we might change what the current
+ // plan is.
+
+ lldb::addr_t pc = GetRegisterContext()->GetPC();
+ BreakpointSiteSP bp_site_sp = GetProcess().GetBreakpointSiteList().FindByAddress(pc);
+ if (bp_site_sp && bp_site_sp->IsEnabled())
+ {
+ // Note, don't assume there's a ThreadPlanStepOverBreakpoint, the target may not require anything
+ // special to step over a breakpoint.
+
+ ThreadPlan *cur_plan = GetCurrentPlan();
+ ThreadPlanStepOverBreakpoint *step_over_bp = dynamic_cast<ThreadPlanStepOverBreakpoint *> (cur_plan);
+ if (step_over_bp == NULL)
+ {
+
+ ThreadPlanSP step_bp_plan_sp (new ThreadPlanStepOverBreakpoint (*this));
+ if (step_bp_plan_sp)
+ {
+ if (GetCurrentPlan()->RunState() != eStateStepping)
+ {
+ ThreadPlanSP continue_plan_sp (new ThreadPlanContinue(*this, false, eVoteNo, eVoteNoOpinion));
+ continue_plan_sp->SetPrivate (true);
+ QueueThreadPlan (continue_plan_sp, false);
+ }
+ step_bp_plan_sp->SetPrivate (true);
+ QueueThreadPlan (step_bp_plan_sp, false);
+ }
+ }
+ }
+ }
+}
+
+bool
+Thread::WillResume (StateType resume_state)
+{
+ // At this point clear the completed plan stack.
+ m_completed_plan_stack.clear();
+ m_discarded_plan_stack.clear();
+
+ // If this thread stopped with a signal, work out what its resume state should
+ // be. Note if the thread resume state is already set, then don't override it,
+ // the user must have asked us to resume with some other signal.
+
+ if (GetResumeSignal() == LLDB_INVALID_SIGNAL_NUMBER)
+ {
+ Thread::StopInfo stop_info;
+ GetRawStopReason(&stop_info);
+
+ StopReason reason = stop_info.GetStopReason();
+ if (reason == eStopReasonSignal)
+ {
+ UnixSignals &signals = GetProcess().GetUnixSignals();
+ int32_t signo = stop_info.GetSignal();
+ if (!signals.GetShouldSuppress(signo))
+ {
+ SetResumeSignal(signo);
+ }
+ }
+ }
+
+ // Tell all the plans that we are about to resume in case they need to clear any state.
+ // We distinguish between the plan on the top of the stack and the lower
+ // plans in case a plan needs to do any special business before it runs.
+
+ ThreadPlan *plan_ptr = GetCurrentPlan();
+ plan_ptr->WillResume(resume_state, true);
+
+ while ((plan_ptr = GetPreviousPlan(plan_ptr)) != NULL)
+ {
+ plan_ptr->WillResume (resume_state, false);
+ }
+ return true;
+}
+
+void
+Thread::DidResume ()
+{
+ SetResumeSignal (LLDB_INVALID_SIGNAL_NUMBER);
+}
+
+bool
+Thread::ShouldStop (Event* event_ptr)
+{
+ ThreadPlan *current_plan = GetCurrentPlan();
+ bool should_stop = true;
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ {
+ StreamString s;
+ DumpThreadPlans(&s);
+ log->PutCString (s.GetData());
+ }
+
+ if (current_plan->PlanExplainsStop())
+ {
+ while (1)
+ {
+ should_stop = current_plan->ShouldStop(event_ptr);
+ if (current_plan->MischiefManaged())
+ {
+ if (should_stop)
+ current_plan->WillStop();
+
+ // If a Master Plan wants to stop, and wants to stick on the stack, we let it.
+ // Otherwise, see if the plan's parent wants to stop.
+
+ if (should_stop && current_plan->IsMasterPlan() && !current_plan->OkayToDiscard())
+ {
+ PopPlan();
+ break;
+ }
+ else
+ {
+
+ PopPlan();
+
+ current_plan = GetCurrentPlan();
+ if (current_plan == NULL)
+ {
+ break;
+ }
+ }
+
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ // If the current plan doesn't explain the stop, then, find one that
+ // does and let it handle the situation.
+ ThreadPlan *plan_ptr = current_plan;
+ while ((plan_ptr = GetPreviousPlan(plan_ptr)) != NULL)
+ {
+ if (plan_ptr->PlanExplainsStop())
+ {
+ should_stop = plan_ptr->ShouldStop (event_ptr);
+ break;
+ }
+
+ }
+ }
+
+ return should_stop;
+}
+
+Vote
+Thread::ShouldReportStop (Event* event_ptr)
+{
+ StateType thread_state = GetResumeState ();
+ if (thread_state == eStateSuspended
+ || thread_state == eStateInvalid)
+ return eVoteNoOpinion;
+
+ if (m_completed_plan_stack.size() > 0)
+ {
+ // Don't use GetCompletedPlan here, since that suppresses private plans.
+ return m_completed_plan_stack.back()->ShouldReportStop (event_ptr);
+ }
+ else
+ return GetCurrentPlan()->ShouldReportStop (event_ptr);
+}
+
+Vote
+Thread::ShouldReportRun (Event* event_ptr)
+{
+ StateType thread_state = GetResumeState ();
+ if (thread_state == eStateSuspended
+ || thread_state == eStateInvalid)
+ return eVoteNoOpinion;
+
+ if (m_completed_plan_stack.size() > 0)
+ {
+ // Don't use GetCompletedPlan here, since that suppresses private plans.
+ return m_completed_plan_stack.back()->ShouldReportRun (event_ptr);
+ }
+ else
+ return GetCurrentPlan()->ShouldReportRun (event_ptr);
+}
+
+void
+Thread::PushPlan (ThreadPlanSP &thread_plan_sp)
+{
+ if (thread_plan_sp)
+ {
+ if (thread_plan_sp->IsImmediate())
+ m_immediate_plan_stack.push_back (thread_plan_sp);
+ else
+ m_plan_stack.push_back (thread_plan_sp);
+
+ thread_plan_sp->DidPush();
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ {
+ StreamString s;
+ thread_plan_sp->GetDescription (&s, lldb::eDescriptionLevelFull);
+ log->Printf("Pushing plan: \"%s\" for thread: %d immediate: %s.",
+ s.GetData(),
+ thread_plan_sp->GetThread().GetID(),
+ thread_plan_sp->IsImmediate() ? "true" : "false");
+ }
+ }
+}
+
+void
+Thread::PopPlan ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+
+ if (!m_immediate_plan_stack.empty())
+ {
+ ThreadPlanSP &plan = m_immediate_plan_stack.back();
+ if (log)
+ {
+ log->Printf("Popping plan: \"%s\" for thread: %d immediate: true.", plan->GetName(), plan->GetThread().GetID());
+ }
+ plan->WillPop();
+ m_immediate_plan_stack.pop_back();
+ }
+ else if (m_plan_stack.empty())
+ return;
+ else
+ {
+ ThreadPlanSP &plan = m_plan_stack.back();
+ if (log)
+ {
+ log->Printf("Popping plan: \"%s\" for thread: 0x%x immediate: false.", plan->GetName(), plan->GetThread().GetID());
+ }
+ m_completed_plan_stack.push_back (plan);
+ plan->WillPop();
+ m_plan_stack.pop_back();
+ }
+}
+
+void
+Thread::DiscardPlan ()
+{
+ if (m_plan_stack.size() > 1)
+ {
+ ThreadPlanSP &plan = m_plan_stack.back();
+ m_discarded_plan_stack.push_back (plan);
+ plan->WillPop();
+ m_plan_stack.pop_back();
+ }
+}
+
+ThreadPlan *
+Thread::GetCurrentPlan ()
+{
+ if (!m_immediate_plan_stack.empty())
+ return m_immediate_plan_stack.back().get();
+ else if (m_plan_stack.empty())
+ return NULL;
+ else
+ return m_plan_stack.back().get();
+}
+
+ThreadPlanSP
+Thread::GetCompletedPlan ()
+{
+ ThreadPlanSP empty_plan_sp;
+ if (!m_completed_plan_stack.empty())
+ {
+ for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--)
+ {
+ ThreadPlanSP completed_plan_sp;
+ completed_plan_sp = m_completed_plan_stack[i];
+ if (!completed_plan_sp->GetPrivate ())
+ return completed_plan_sp;
+ }
+ }
+ return empty_plan_sp;
+}
+
+bool
+Thread::IsThreadPlanDone (ThreadPlan *plan)
+{
+ ThreadPlanSP empty_plan_sp;
+ if (!m_completed_plan_stack.empty())
+ {
+ for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--)
+ {
+ if (m_completed_plan_stack[i].get() == plan)
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+Thread::WasThreadPlanDiscarded (ThreadPlan *plan)
+{
+ ThreadPlanSP empty_plan_sp;
+ if (!m_discarded_plan_stack.empty())
+ {
+ for (int i = m_discarded_plan_stack.size() - 1; i >= 0; i--)
+ {
+ if (m_discarded_plan_stack[i].get() == plan)
+ return true;
+ }
+ }
+ return false;
+}
+
+ThreadPlan *
+Thread::GetPreviousPlan (ThreadPlan *current_plan)
+{
+ if (current_plan == NULL)
+ return NULL;
+
+ int stack_size = m_completed_plan_stack.size();
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ if (current_plan == m_completed_plan_stack[i].get())
+ return m_completed_plan_stack[i-1].get();
+ }
+
+ if (stack_size > 0 && m_completed_plan_stack[0].get() == current_plan)
+ {
+ if (m_immediate_plan_stack.size() > 0)
+ return m_immediate_plan_stack.back().get();
+ else if (m_plan_stack.size() > 0)
+ return m_plan_stack.back().get();
+ else
+ return NULL;
+ }
+
+ stack_size = m_immediate_plan_stack.size();
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ if (current_plan == m_immediate_plan_stack[i].get())
+ return m_immediate_plan_stack[i-1].get();
+ }
+ if (stack_size > 0 && m_immediate_plan_stack[0].get() == current_plan)
+ {
+ if (m_plan_stack.size() > 0)
+ return m_plan_stack.back().get();
+ else
+ return NULL;
+ }
+
+ stack_size = m_plan_stack.size();
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ if (current_plan == m_plan_stack[i].get())
+ return m_plan_stack[i-1].get();
+ }
+ return NULL;
+}
+
+void
+Thread::QueueThreadPlan (ThreadPlanSP &thread_plan_sp, bool abort_other_plans)
+{
+ if (abort_other_plans)
+ DiscardThreadPlans(true);
+
+ PushPlan (thread_plan_sp);
+}
+
+void
+Thread::DiscardThreadPlans(bool force)
+{
+ // FIXME: It is not always safe to just discard plans. Some, like the step over
+ // breakpoint trap can't be discarded in general (though you can if you plan to
+ // force a return from a function, for instance.
+ // For now I'm just not clearing immediate plans, but I need a way for plans to
+ // say they really need to be kept on, and then a way to override that. Humm...
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ {
+ log->Printf("Discarding thread plans for thread: 0x%x: force %d.", GetID(), force);
+ }
+
+ if (force)
+ {
+ int stack_size = m_plan_stack.size();
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ DiscardPlan();
+ }
+ return;
+ }
+
+ while (1)
+ {
+
+ int master_plan_idx;
+ bool discard;
+
+ // Find the first master plan, see if it wants discarding, and if yes discard up to it.
+ for (master_plan_idx = m_plan_stack.size() - 1; master_plan_idx >= 0; master_plan_idx--)
+ {
+ if (m_plan_stack[master_plan_idx]->IsMasterPlan())
+ {
+ discard = m_plan_stack[master_plan_idx]->OkayToDiscard();
+ break;
+ }
+ }
+
+ if (discard)
+ {
+ // First pop all the dependent plans:
+ for (int i = m_plan_stack.size() - 1; i > master_plan_idx; i--)
+ {
+
+ // FIXME: Do we need a finalize here, or is the rule that "PrepareForStop"
+ // for the plan leaves it in a state that it is safe to pop the plan
+ // with no more notice?
+ DiscardPlan();
+ }
+
+ // Now discard the master plan itself.
+ // The bottom-most plan never gets discarded. "OkayToDiscard" for it means
+ // discard it's dependent plans, but not it...
+ if (master_plan_idx > 0)
+ {
+ DiscardPlan();
+ }
+ }
+ else
+ {
+ // If the master plan doesn't want to get discarded, then we're done.
+ break;
+ }
+
+ }
+ // FIXME: What should we do about the immediate plans?
+}
+
+ThreadPlan *
+Thread::QueueFundamentalPlan (bool abort_other_plans)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanBase(*this));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+ThreadPlan *
+Thread::QueueThreadPlanForStepSingleInstruction (bool step_over, bool abort_other_plans, bool stop_other_threads)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanStepInstruction (*this, step_over, stop_other_threads, eVoteNoOpinion, eVoteNoOpinion));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+ThreadPlan *
+Thread::QueueThreadPlanForStepRange (bool abort_other_plans, StepType type, const AddressRange &range, const SymbolContext &addr_context, lldb::RunMode stop_other_threads)
+{
+ ThreadPlanSP thread_plan_sp;
+ if (type == eStepTypeInto)
+ thread_plan_sp.reset (new ThreadPlanStepInRange (*this, range, addr_context, stop_other_threads));
+ else
+ thread_plan_sp.reset (new ThreadPlanStepOverRange (*this, range, addr_context, stop_other_threads));
+
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+
+ThreadPlan *
+Thread::QueueThreadPlanForStepOverBreakpointPlan (bool abort_other_plans)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanStepOverBreakpoint (*this));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+ThreadPlan *
+Thread::QueueThreadPlanForStepOut (bool abort_other_plans, SymbolContext *addr_context, bool first_insn,
+ bool stop_other_threads, Vote stop_vote, Vote run_vote)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanStepOut (*this, addr_context, first_insn, stop_other_threads, stop_vote, run_vote));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+ThreadPlan *
+Thread::QueueThreadPlanForStepThrough (bool abort_other_plans, bool stop_other_threads)
+{
+ ThreadPlanSP thread_plan_sp(GetProcess().GetDynamicLoader()->GetStepThroughTrampolinePlan (*this, stop_other_threads));
+ if (thread_plan_sp.get() == NULL)
+ {
+ thread_plan_sp.reset(new ThreadPlanStepThrough (*this, stop_other_threads));
+ if (thread_plan_sp && !thread_plan_sp->ValidatePlan (NULL))
+ return false;
+ }
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+ThreadPlan *
+Thread::QueueThreadPlanForContinue (bool abort_other_plans, bool stop_other_threads, Vote stop_vote, Vote run_vote, bool immediate)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanContinue (*this, stop_other_threads, stop_vote, run_vote, immediate));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+ThreadPlan *
+Thread::QueueThreadPlanForCallFunction (bool abort_other_plans,
+ Address& function,
+ lldb::addr_t arg,
+ bool stop_other_threads,
+ bool discard_on_error)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanCallFunction (*this, function, arg, stop_other_threads, discard_on_error));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+ThreadPlan *
+Thread::QueueThreadPlanForCallFunction (bool abort_other_plans,
+ Address& function,
+ ValueList &args,
+ bool stop_other_threads,
+ bool discard_on_error)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanCallFunction (*this, function, args, stop_other_threads, discard_on_error));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+ThreadPlan *
+Thread::QueueThreadPlanForRunToAddress (bool abort_other_plans,
+ Address &target_addr,
+ bool stop_other_threads)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanRunToAddress (*this, target_addr, stop_other_threads));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+ThreadPlan *
+Thread::QueueThreadPlanForStepUntil (bool abort_other_plans,
+ lldb::addr_t *address_list,
+ size_t num_addresses,
+ bool stop_other_threads)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanStepUntil (*this, address_list, num_addresses, stop_other_threads));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+
+}
+
+uint32_t
+Thread::GetIndexID () const
+{
+ return m_index_id;
+}
+
+void
+Thread::DumpThreadPlans (lldb_private::Stream *s) const
+{
+ uint32_t stack_size = m_plan_stack.size();
+ s->Printf ("Plan Stack: %d elements.\n", stack_size);
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ s->Printf ("Element %d: ", i);
+ s->IndentMore();
+ m_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
+ s->IndentLess();
+ s->EOL();
+ }
+
+ stack_size = m_immediate_plan_stack.size();
+ s->Printf ("Immediate Plan Stack: %d elements.\n", stack_size);
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ s->Printf ("Element %d: ", i);
+ s->IndentMore();
+ m_immediate_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
+ s->IndentLess();
+ s->EOL();
+ }
+
+ stack_size = m_completed_plan_stack.size();
+ s->Printf ("Completed Plan Stack: %d elements.\n", stack_size);
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ s->Printf ("Element %d: ", i);
+ s->IndentMore();
+ m_completed_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
+ s->IndentLess();
+ s->EOL();
+ }
+
+ stack_size = m_discarded_plan_stack.size();
+ s->Printf ("Discarded Plan Stack: %d elements.\n", stack_size);
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ s->Printf ("Element %d: ", i);
+ s->IndentMore();
+ m_discarded_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
+ s->IndentLess();
+ s->EOL();
+ }
+
+}
+
+Target *
+Thread::CalculateTarget ()
+{
+ return m_process.CalculateTarget();
+}
+
+Process *
+Thread::CalculateProcess ()
+{
+ return &m_process;
+}
+
+Thread *
+Thread::CalculateThread ()
+{
+ return this;
+}
+
+StackFrame *
+Thread::CalculateStackFrame ()
+{
+ return NULL;
+}
+
+void
+Thread::Calculate (ExecutionContext &exe_ctx)
+{
+ m_process.Calculate (exe_ctx);
+ exe_ctx.thread = this;
+ exe_ctx.frame = NULL;
+}
+
+lldb::StackFrameSP
+Thread::GetCurrentFrame ()
+{
+ return GetStackFrameAtIndex (m_frames.GetCurrentFrameIndex());
+}
+
+uint32_t
+Thread::SetCurrentFrame (lldb_private::StackFrame *frame)
+{
+ return m_frames.SetCurrentFrame(frame);
+}
+
+void
+Thread::SetCurrentFrameByIndex (uint32_t frame_idx)
+{
+ m_frames.SetCurrentFrameByIndex(frame_idx);
+}
+
+void
+Thread::DumpInfo
+(
+ Stream &strm,
+ bool show_stop_reason,
+ bool show_name,
+ bool show_queue,
+ uint32_t frame_idx
+)
+{
+ strm.Printf("thread #%u: tid = 0x%4.4x", GetIndexID(), GetID());
+
+ if (frame_idx != LLDB_INVALID_INDEX32)
+ {
+ StackFrameSP frame_sp(GetStackFrameAtIndex (frame_idx));
+ if (frame_sp)
+ {
+ strm.PutCString(", ");
+ frame_sp->Dump (&strm, false);
+ }
+ }
+
+ if (show_stop_reason)
+ {
+ Thread::StopInfo thread_stop_info;
+ if (GetStopInfo(&thread_stop_info))
+ {
+ if (thread_stop_info.GetStopReason() != eStopReasonNone)
+ {
+ strm.PutCString(", stop reason = ");
+ thread_stop_info.Dump(&strm);
+ }
+ }
+ }
+
+ if (show_name)
+ {
+ const char *name = GetName();
+ if (name && name[0])
+ strm.Printf(", name = %s", name);
+ }
+
+ if (show_queue)
+ {
+ const char *queue = GetQueueName();
+ if (queue && queue[0])
+ strm.Printf(", queue = %s", queue);
+ }
+}
+
+lldb::ThreadSP
+Thread::GetSP ()
+{
+ return m_process.GetThreadList().GetThreadSPForThreadPtr(this);
+}
diff --git a/lldb/source/Target/ThreadList.cpp b/lldb/source/Target/ThreadList.cpp
new file mode 100644
index 00000000000..6bc22712d10
--- /dev/null
+++ b/lldb/source/Target/ThreadList.cpp
@@ -0,0 +1,460 @@
+//===-- ThreadList.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <stdlib.h>
+
+#include <algorithm>
+
+#include "lldb/Target/ThreadList.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ThreadList::ThreadList (Process *process) :
+ m_process (process),
+ m_stop_id (0),
+ m_threads(),
+ m_threads_mutex (Mutex::eMutexTypeRecursive),
+ m_current_tid (LLDB_INVALID_THREAD_ID)
+{
+}
+
+ThreadList::ThreadList (const ThreadList &rhs) :
+ m_process (),
+ m_stop_id (),
+ m_threads (),
+ m_threads_mutex (Mutex::eMutexTypeRecursive),
+ m_current_tid ()
+{
+ // Use the assignment operator since it uses the mutex
+ *this = rhs;
+}
+
+const ThreadList&
+ThreadList::operator = (const ThreadList& rhs)
+{
+ if (this != &rhs)
+ {
+ // Lock both mutexes to make sure neither side changes anyone on us
+ // while the assignement occurs
+ Mutex::Locker locker_this(m_threads_mutex);
+ Mutex::Locker locker_rhs(rhs.m_threads_mutex);
+ m_process = rhs.m_process;
+ m_stop_id = rhs.m_stop_id;
+ m_threads = rhs.m_threads;
+ m_current_tid = rhs.m_current_tid;
+ }
+ return *this;
+}
+
+
+ThreadList::~ThreadList()
+{
+}
+
+
+uint32_t
+ThreadList::GetStopID () const
+{
+ return m_stop_id;
+}
+
+void
+ThreadList::SetStopID (uint32_t stop_id)
+{
+ m_stop_id = stop_id;
+}
+
+
+void
+ThreadList::AddThread (ThreadSP &thread_sp)
+{
+ Mutex::Locker locker(m_threads_mutex);
+ m_threads.push_back(thread_sp);
+}
+
+uint32_t
+ThreadList::GetSize (bool can_update)
+{
+ Mutex::Locker locker(m_threads_mutex);
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+ return m_threads.size();
+}
+
+ThreadSP
+ThreadList::GetThreadAtIndex (uint32_t idx, bool can_update)
+{
+ Mutex::Locker locker(m_threads_mutex);
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+
+ ThreadSP thread_sp;
+ if (idx < m_threads.size())
+ thread_sp = m_threads[idx];
+ return thread_sp;
+}
+
+ThreadSP
+ThreadList::FindThreadByID (lldb::tid_t tid, bool can_update)
+{
+ Mutex::Locker locker(m_threads_mutex);
+
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+
+ ThreadSP thread_sp;
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx]->GetID() == tid)
+ {
+ thread_sp = m_threads[idx];
+ break;
+ }
+ }
+ return thread_sp;
+}
+
+ThreadSP
+ThreadList::GetThreadSPForThreadPtr (Thread *thread_ptr)
+{
+ ThreadSP thread_sp;
+ if (thread_ptr)
+ {
+ Mutex::Locker locker(m_threads_mutex);
+
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx].get() == thread_ptr)
+ {
+ thread_sp = m_threads[idx];
+ break;
+ }
+ }
+ }
+ return thread_sp;
+}
+
+
+
+ThreadSP
+ThreadList::FindThreadByIndexID (uint32_t index_id, bool can_update)
+{
+ Mutex::Locker locker(m_threads_mutex);
+
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+
+ ThreadSP thread_sp;
+ const uint32_t num_threads = m_threads.size();
+ for (uint32_t idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx]->GetIndexID() == index_id)
+ {
+ thread_sp = m_threads[idx];
+ break;
+ }
+ }
+ return thread_sp;
+}
+
+bool
+ThreadList::ShouldStop (Event *event_ptr)
+{
+ Mutex::Locker locker(m_threads_mutex);
+
+ // Running events should never stop, obviously...
+
+
+ bool should_stop = false;
+ m_process->UpdateThreadListIfNeeded();
+
+ collection::iterator pos, end = m_threads.end();
+
+ // Run through the threads and ask whether we should stop. Don't ask
+ // suspended threads, however, it makes more sense for them to preserve their
+ // state across the times the process runs but they don't get a chance to.
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ if ((thread_sp->ThreadStoppedForAReason())
+ && (thread_sp->GetResumeState () != eStateSuspended))
+ {
+ should_stop |= thread_sp->ShouldStop(event_ptr);
+ }
+ }
+ if (should_stop)
+ {
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ thread_sp->WillStop ();
+ }
+ }
+
+ return should_stop;
+}
+
+Vote
+ThreadList::ShouldReportStop (Event *event_ptr)
+{
+ Vote result = eVoteNoOpinion;
+ m_process->UpdateThreadListIfNeeded();
+ collection::iterator pos, end = m_threads.end();
+
+ // Run through the threads and ask whether we should report this event.
+ // For stopping, a YES vote wins over everything. A NO vote wins over NO opinion.
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ if (thread_sp->ThreadStoppedForAReason() && (thread_sp->GetResumeState () != eStateSuspended))
+ {
+ switch (thread_sp->ShouldReportStop (event_ptr))
+ {
+ case eVoteNoOpinion:
+ continue;
+ case eVoteYes:
+ result = eVoteYes;
+ break;
+ case eVoteNo:
+ if (result == eVoteNoOpinion)
+ result = eVoteNo;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+Vote
+ThreadList::ShouldReportRun (Event *event_ptr)
+{
+ Vote result = eVoteNoOpinion;
+ m_process->UpdateThreadListIfNeeded();
+ collection::iterator pos, end = m_threads.end();
+
+ // Run through the threads and ask whether we should report this event.
+ // The rule is NO vote wins over everything, a YES vote wins over no opinion.
+
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ if (thread_sp->GetResumeState () != eStateSuspended)
+
+ switch (thread_sp->ShouldReportRun (event_ptr))
+ {
+ case eVoteNoOpinion:
+ continue;
+ case eVoteYes:
+ if (result == eVoteNoOpinion)
+ result = eVoteYes;
+ break;
+ case eVoteNo:
+ result = eVoteNo;
+ break;
+ }
+ }
+ return result;
+}
+
+void
+ThreadList::Clear()
+{
+ m_stop_id = 0;
+ m_threads.clear();
+ m_current_tid = LLDB_INVALID_THREAD_ID;
+}
+
+void
+ThreadList::RefreshStateAfterStop ()
+{
+ Mutex::Locker locker(m_threads_mutex);
+
+ m_process->UpdateThreadListIfNeeded();
+
+ collection::iterator pos, end = m_threads.end();
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ (*pos)->RefreshStateAfterStop ();
+}
+
+void
+ThreadList::DiscardThreadPlans ()
+{
+ // You don't need to update the thread list here, because only threads
+ // that you currently know about have any thread plans.
+ Mutex::Locker locker(m_threads_mutex);
+
+ collection::iterator pos, end = m_threads.end();
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ (*pos)->DiscardThreadPlans (true);
+
+}
+
+bool
+ThreadList::WillResume ()
+{
+ // Run through the threads and perform their momentary actions.
+ // But we only do this for threads that are running, user suspended
+ // threads stay where they are.
+ bool success = true;
+
+ Mutex::Locker locker(m_threads_mutex);
+ m_process->UpdateThreadListIfNeeded();
+
+ collection::iterator pos, end = m_threads.end();
+
+ // Give all the threads a last chance to set up their state before we
+ // negotiate who is actually going to get a chance to run...
+
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ (*pos)->SetupForResume ();
+
+ // Now go through the threads and see if any thread wants to run just itself.
+ // if so then pick one and run it.
+ ThreadList run_me_only_list (m_process);
+
+ run_me_only_list.SetStopID(m_process->GetStopID());
+
+ ThreadSP immediate_thread_sp;
+ bool run_only_current_thread = false;
+
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ if (thread_sp->GetCurrentPlan()->IsImmediate())
+ {
+ // We first do all the immediate plans, so if we find one, set
+ // immediate_thread_sp and break out, and we'll pick it up first thing
+ // when we're negotiating which threads get to run.
+ immediate_thread_sp = thread_sp;
+ break;
+ }
+ else if (thread_sp->GetResumeState() != eStateSuspended &&
+ thread_sp->GetCurrentPlan()->StopOthers())
+ {
+ // You can't say "stop others" and also want yourself to be suspended.
+ assert (thread_sp->GetCurrentPlan()->RunState() != eStateSuspended);
+
+ if (thread_sp == GetCurrentThread())
+ {
+ run_only_current_thread = true;
+ run_me_only_list.Clear();
+ run_me_only_list.AddThread (thread_sp);
+ break;
+ }
+
+ run_me_only_list.AddThread (thread_sp);
+ }
+
+ }
+
+ if (immediate_thread_sp)
+ {
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ if (thread_sp.get() == immediate_thread_sp.get())
+ thread_sp->WillResume(thread_sp->GetCurrentPlan()->RunState());
+ else
+ thread_sp->WillResume (eStateSuspended);
+ }
+ }
+ else if (run_me_only_list.GetSize (false) == 0)
+ {
+ // Everybody runs as they wish:
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ thread_sp->WillResume(thread_sp->GetCurrentPlan()->RunState());
+ }
+ }
+ else
+ {
+ ThreadSP thread_to_run;
+
+ if (run_only_current_thread)
+ {
+ thread_to_run = GetCurrentThread();
+ }
+ else if (run_me_only_list.GetSize (false) == 1)
+ {
+ thread_to_run = run_me_only_list.GetThreadAtIndex (0);
+ }
+ else
+ {
+ int random_thread = (int)
+ ((run_me_only_list.GetSize (false) * (double) rand ()) / (RAND_MAX + 1.0));
+ thread_to_run = run_me_only_list.GetThreadAtIndex (random_thread);
+ }
+
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ if (thread_sp == thread_to_run)
+ thread_sp->WillResume(thread_sp->GetCurrentPlan()->RunState());
+ else
+ thread_sp->WillResume (eStateSuspended);
+ }
+ }
+
+ return success;
+}
+
+void
+ThreadList::DidResume ()
+{
+ collection::iterator pos, end = m_threads.end();
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ // Don't clear out threads that aren't going to get a chance to run, rather
+ // leave their state for the next time around.
+ ThreadSP thread_sp(*pos);
+ if (thread_sp->GetResumeState() != eStateSuspended)
+ thread_sp->DidResume ();
+ }
+}
+
+ThreadSP
+ThreadList::GetCurrentThread ()
+{
+ Mutex::Locker locker(m_threads_mutex);
+ return FindThreadByID(m_current_tid);
+}
+
+bool
+ThreadList::SetCurrentThreadByID (lldb::tid_t tid)
+{
+ Mutex::Locker locker(m_threads_mutex);
+ if (FindThreadByID(tid).get())
+ m_current_tid = tid;
+ else
+ m_current_tid = LLDB_INVALID_THREAD_ID;
+
+ return m_current_tid != LLDB_INVALID_THREAD_ID;
+}
+
+bool
+ThreadList::SetCurrentThreadByIndexID (uint32_t index_id)
+{
+ Mutex::Locker locker(m_threads_mutex);
+ ThreadSP thread_sp (FindThreadByIndexID(index_id));
+ if (thread_sp.get())
+ m_current_tid = thread_sp->GetID();
+ else
+ m_current_tid = LLDB_INVALID_THREAD_ID;
+
+ return m_current_tid != LLDB_INVALID_THREAD_ID;
+}
+
diff --git a/lldb/source/Target/ThreadPlan.cpp b/lldb/source/Target/ThreadPlan.cpp
new file mode 100644
index 00000000000..c9005c1f345
--- /dev/null
+++ b/lldb/source/Target/ThreadPlan.cpp
@@ -0,0 +1,185 @@
+//===-- 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/Target/ThreadPlan.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Thread.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlan constructor
+//----------------------------------------------------------------------
+ThreadPlan::ThreadPlan(const char *name, Thread &thread, Vote stop_vote, Vote run_vote) :
+ m_name (name),
+ m_thread (thread),
+ m_plan_complete(false),
+ m_plan_complete_mutex (Mutex::eMutexTypeRecursive),
+ m_plan_private (false),
+ m_stop_vote (stop_vote),
+ m_run_vote (run_vote),
+ m_okay_to_discard (false)
+{
+ SetID (GetNextID());
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ThreadPlan::~ThreadPlan()
+{
+}
+
+const char *
+ThreadPlan::GetName () const
+{
+ return m_name.c_str();
+}
+
+Thread &
+ThreadPlan::GetThread()
+{
+ return m_thread;
+}
+
+
+const Thread &
+ThreadPlan::GetThread() const
+{
+ return m_thread;
+}
+
+bool
+ThreadPlan::IsPlanComplete ()
+{
+ Mutex::Locker (m_plan_complete_mutex);
+ return m_plan_complete;
+}
+
+void
+ThreadPlan::SetPlanComplete ()
+{
+ Mutex::Locker (m_plan_complete_mutex);
+ m_plan_complete = true;
+}
+
+bool
+ThreadPlan::MischiefManaged ()
+{
+ Mutex::Locker (m_plan_complete_mutex);
+ m_plan_complete = true;
+ return true;
+}
+
+Vote
+ThreadPlan::ShouldReportStop (Event *event_ptr)
+{
+ if (m_stop_vote == eVoteNoOpinion)
+ {
+ ThreadPlan *prev_plan = GetPreviousPlan ();
+ if (prev_plan)
+ return prev_plan->ShouldReportStop (event_ptr);
+ }
+ return m_stop_vote;
+}
+
+Vote
+ThreadPlan::ShouldReportRun (Event *event_ptr)
+{
+ if (m_run_vote == eVoteNoOpinion)
+ {
+ ThreadPlan *prev_plan = GetPreviousPlan ();
+ if (prev_plan)
+ return prev_plan->ShouldReportRun (event_ptr);
+ }
+ return m_run_vote;
+}
+
+bool
+ThreadPlan::StopOthers ()
+{
+ ThreadPlan *prev_plan;
+ prev_plan = GetPreviousPlan ();
+ if (prev_plan == NULL)
+ return false;
+ else
+ return prev_plan->StopOthers();
+}
+
+bool
+ThreadPlan::WillResume (StateType resume_state, bool current_plan)
+{
+ if (current_plan)
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+
+ if (log)
+ log->Printf("About to resume the \"%s\" plan - state: %s - stop others: %d.",
+ m_name.c_str(), StateAsCString(resume_state), StopOthers());
+ }
+ return true;
+}
+
+lldb::user_id_t
+ThreadPlan::GetNextID()
+{
+ static uint32_t g_nextPlanID = 0;
+ return ++g_nextPlanID;
+}
+
+void
+ThreadPlan::DidPush()
+{
+}
+
+void
+ThreadPlan::WillPop()
+{
+}
+
+void
+ThreadPlan::PushPlan (ThreadPlanSP &thread_plan_sp)
+{
+ m_thread.PushPlan (thread_plan_sp);
+}
+
+ThreadPlan *
+ThreadPlan::GetPreviousPlan ()
+{
+ return m_thread.GetPreviousPlan (this);
+}
+
+void
+ThreadPlan::SetPrivate (bool input)
+{
+ m_plan_private = input;
+}
+
+bool
+ThreadPlan::GetPrivate (void)
+{
+ return m_plan_private;
+}
+
+bool
+ThreadPlan::OkayToDiscard()
+{
+ if (!IsMasterPlan())
+ return true;
+ else
+ return m_okay_to_discard;
+}
+
diff --git a/lldb/source/Target/ThreadPlanBase.cpp b/lldb/source/Target/ThreadPlanBase.cpp
new file mode 100644
index 00000000000..283f3bef4c9
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanBase.cpp
@@ -0,0 +1,202 @@
+//===-- ThreadPlanBase.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/ThreadPlanBase.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+//
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Breakpoint/BreakpointSite.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/ThreadPlanContinue.h"
+#include "lldb/Target/ThreadPlanStepOverBreakpoint.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanBase: This one always stops, and never has anything particular
+// to do.
+// FIXME: The "signal handling" policies should probably go here.
+//----------------------------------------------------------------------
+
+ThreadPlanBase::ThreadPlanBase (Thread &thread) :
+ ThreadPlan("base plan", thread, eVoteYes, eVoteNoOpinion)
+{
+
+}
+
+ThreadPlanBase::~ThreadPlanBase ()
+{
+
+}
+
+void
+ThreadPlanBase::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ s->Printf ("Base thread plan.");
+}
+
+bool
+ThreadPlanBase::ValidatePlan (Stream *error)
+{
+ return true;
+}
+
+bool
+ThreadPlanBase::PlanExplainsStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanBase::ShouldStop (Event *event_ptr)
+{
+ m_stop_vote = eVoteYes;
+ m_run_vote = eVoteYes;
+
+ Thread::StopInfo stop_info;
+ if (m_thread.GetStopInfo(&stop_info))
+ {
+ StopReason reason = stop_info.GetStopReason();
+ switch (reason)
+ {
+ case eStopReasonInvalid:
+ case eStopReasonNone:
+ {
+ m_run_vote = eVoteNo;
+ m_stop_vote = eVoteNo;
+ return false;
+ }
+ case eStopReasonBreakpoint:
+ {
+ // The base plan checks for breakpoint hits.
+
+ BreakpointSiteSP bp_site_sp;
+ //RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ //lldb::addr_t pc = reg_ctx->GetPC();
+ bp_site_sp = m_thread.GetProcess().GetBreakpointSiteList().FindByID (stop_info.GetBreakpointSiteID());
+
+ if (bp_site_sp && bp_site_sp->IsEnabled())
+ {
+ // We want to step over the breakpoint and then continue. So push these two plans.
+
+ StoppointCallbackContext hit_context(event_ptr, &m_thread.GetProcess(), &m_thread, m_thread.GetStackFrameAtIndex(0).get());
+ bool should_stop = m_thread.GetProcess().GetBreakpointSiteList().ShouldStop(&hit_context, bp_site_sp->GetID());
+
+ if (!should_stop)
+ {
+ // If we aren't going to stop at this breakpoint, and it is internal, don't report this stop or the subsequent
+ // running event. Otherwise we will post the stopped & running, but the stopped event will get marked
+ // with "restarted" so the UI will know to wait and expect the consequent "running".
+ uint32_t i;
+ bool is_wholly_internal = true;
+
+ for (i = 0; i < bp_site_sp->GetNumberOfOwners(); i++)
+ {
+ if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal())
+ {
+ is_wholly_internal = false;
+ break;
+ }
+ }
+ if (is_wholly_internal)
+ {
+ m_stop_vote = eVoteNo;
+ m_run_vote = eVoteNo;
+ }
+ else
+ {
+ m_stop_vote = eVoteYes;
+ m_run_vote = eVoteYes;
+ }
+
+ }
+ else
+ {
+ // If we are going to stop for a breakpoint, then unship the other plans
+ // at this point. Don't force the discard, however, so Master plans can stay
+ // in place if they want to.
+ m_thread.DiscardThreadPlans(false);
+ }
+
+ return should_stop;
+ }
+ }
+ case eStopReasonException:
+ // If we crashed, discard thread plans and stop. Don't force the discard, however,
+ // since on rerun the target may clean up this exception and continue normally from there.
+ m_thread.DiscardThreadPlans(false);
+ return true;
+ case eStopReasonSignal:
+ {
+ // Check the signal handling, and if we are stopping for the signal,
+ // discard the plans and stop.
+ UnixSignals &signals = m_thread.GetProcess().GetUnixSignals();
+ uint32_t signo = stop_info.GetSignal();
+ if (signals.GetShouldStop(signo))
+ {
+ m_thread.DiscardThreadPlans(false);
+ return true;
+ }
+ else
+ {
+ // We're not going to stop, but while we are here, let's figure out
+ // whether to report this.
+ if (signals.GetShouldNotify(signo))
+ m_stop_vote = eVoteYes;
+ else
+ m_stop_vote = eVoteNo;
+
+ return false;
+ }
+ }
+ default:
+ return true;
+ }
+
+ }
+
+ // If there's no explicit reason to stop, then we will continue.
+ return false;
+}
+
+bool
+ThreadPlanBase::StopOthers ()
+{
+ return false;
+}
+
+StateType
+ThreadPlanBase::RunState ()
+{
+ return eStateRunning;
+}
+
+bool
+ThreadPlanBase::WillStop ()
+{
+ return true;
+}
+
+// The base plan is never done.
+bool
+ThreadPlanBase::MischiefManaged ()
+{
+ // The base plan is never done.
+ return false;
+}
+
diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp
new file mode 100644
index 00000000000..4b3533a3446
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanCallFunction.cpp
@@ -0,0 +1,250 @@
+//===-- ThreadPlanCallFunction.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/ThreadPlanCallFunction.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanCallFunction: Plan to call a single function
+//----------------------------------------------------------------------
+
+ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
+ Address &function,
+ lldb::addr_t arg,
+ bool stop_other_threads,
+ bool discard_on_error) :
+ ThreadPlan ("Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_valid(false),
+ m_process(thread.GetProcess()),
+ m_arg_addr (arg),
+ m_args (NULL),
+ m_thread(thread),
+ m_stop_other_threads(stop_other_threads)
+{
+
+ SetOkayToDiscard (discard_on_error);
+
+ Process& process = thread.GetProcess();
+ Target& target = process.GetTarget();
+ const ABI *abi = process.GetABI();
+
+ if (!abi)
+ return;
+
+ lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
+
+ SymbolContextList contexts;
+ SymbolContext context;
+ ModuleSP executableModuleSP (target.GetExecutableModule());
+
+ if (!executableModuleSP ||
+ !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
+ return;
+
+ contexts.GetContextAtIndex(0, context);
+
+ m_start_addr = context.symbol->GetValue();
+ lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&process);
+
+ if (!thread.SaveFrameZeroState(m_register_backup))
+ return;
+
+ m_function_addr = function;
+ lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&process);
+
+ if (!abi->PrepareTrivialCall(thread,
+ spBelowRedZone,
+ FunctionLoadAddr,
+ StartLoadAddr,
+ m_arg_addr))
+ return;
+
+ m_valid = true;
+}
+
+ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
+ Address &function,
+ ValueList &args,
+ bool stop_other_threads,
+ bool discard_on_error) :
+ ThreadPlan ("Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_valid(false),
+ m_process(thread.GetProcess()),
+ m_arg_addr (0),
+ m_args (&args),
+ m_thread(thread),
+ m_stop_other_threads(stop_other_threads)
+{
+
+ SetOkayToDiscard (discard_on_error);
+
+ Process& process = thread.GetProcess();
+ Target& target = process.GetTarget();
+ const ABI *abi = process.GetABI();
+
+ if(!abi)
+ return;
+
+ lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
+
+ SymbolContextList contexts;
+ SymbolContext context;
+ ModuleSP executableModuleSP (target.GetExecutableModule());
+
+ if (!executableModuleSP ||
+ !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
+ return;
+
+ contexts.GetContextAtIndex(0, context);
+
+ m_start_addr = context.symbol->GetValue();
+ lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&process);
+
+ if(!thread.SaveFrameZeroState(m_register_backup))
+ return;
+
+ m_function_addr = function;
+ lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&process);
+
+ if (!abi->PrepareNormalCall(thread,
+ spBelowRedZone,
+ FunctionLoadAddr,
+ StartLoadAddr,
+ *m_args))
+ return;
+
+ m_valid = true;
+}
+
+ThreadPlanCallFunction::~ThreadPlanCallFunction ()
+{
+}
+
+void
+ThreadPlanCallFunction::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ {
+ s->Printf("Function call thread plan");
+ }
+ else
+ {
+ if (m_args)
+ s->Printf("Thread plan to call 0x%llx with parsed arguments", m_function_addr.GetLoadAddress(&m_process), m_arg_addr);
+ else
+ s->Printf("Thread plan to call 0x%llx void * argument at: 0x%llx", m_function_addr.GetLoadAddress(&m_process), m_arg_addr);
+ }
+}
+
+bool
+ThreadPlanCallFunction::ValidatePlan (Stream *error)
+{
+ if (!m_valid)
+ return false;
+
+ return true;
+}
+
+bool
+ThreadPlanCallFunction::PlanExplainsStop ()
+{
+ if (!m_subplan_sp)
+ return false;
+ else
+ return m_subplan_sp->PlanExplainsStop();
+}
+
+bool
+ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
+{
+ if (PlanExplainsStop())
+ {
+ m_thread.RestoreSaveFrameZero(m_register_backup);
+ m_thread.ClearStackFrames();
+ SetPlanComplete();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool
+ThreadPlanCallFunction::StopOthers ()
+{
+ return m_stop_other_threads;
+}
+
+void
+ThreadPlanCallFunction::SetStopOthers (bool new_value)
+{
+ if (m_subplan_sp)
+ {
+ ThreadPlanRunToAddress *address_plan = static_cast<ThreadPlanRunToAddress *>(m_subplan_sp.get());
+ address_plan->SetStopOthers(new_value);
+ }
+ m_stop_other_threads = new_value;
+}
+
+StateType
+ThreadPlanCallFunction::RunState ()
+{
+ return eStateRunning;
+}
+
+void
+ThreadPlanCallFunction::DidPush ()
+{
+ m_subplan_sp.reset(new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads));
+
+ m_thread.QueueThreadPlan(m_subplan_sp, false);
+
+}
+
+bool
+ThreadPlanCallFunction::WillStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanCallFunction::MischiefManaged ()
+{
+ if (IsPlanComplete())
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+
+ if (log)
+ log->Printf("Completed call function plan.");
+
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
diff --git a/lldb/source/Target/ThreadPlanContinue.cpp b/lldb/source/Target/ThreadPlanContinue.cpp
new file mode 100644
index 00000000000..63d8a3323d0
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanContinue.cpp
@@ -0,0 +1,120 @@
+//===-- ThreadPlanContinue.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/ThreadPlanContinue.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanContinue: Continue plan
+//----------------------------------------------------------------------
+
+ThreadPlanContinue::ThreadPlanContinue (Thread &thread, bool stop_others, Vote stop_vote, Vote run_vote, bool immediate) :
+ ThreadPlan ("Continue after previous plan", thread, stop_vote, run_vote),
+ m_stop_others (stop_others),
+ m_did_run (false),
+ m_immediate (immediate)
+{
+}
+
+ThreadPlanContinue::~ThreadPlanContinue ()
+{
+}
+
+void
+ThreadPlanContinue::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ s->Printf ("continue");
+ else
+ {
+ s->Printf ("Continue from the previous plan");
+ }
+}
+
+bool
+ThreadPlanContinue::ValidatePlan (Stream *error)
+{
+ // Since we read the instruction we're stepping over from the thread,
+ // this plan will always work.
+ return true;
+}
+
+bool
+ThreadPlanContinue::PlanExplainsStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanContinue::ShouldStop (Event *event_ptr)
+{
+ return false;
+}
+
+bool
+ThreadPlanContinue::IsImmediate () const
+{
+ return m_immediate;
+ return false;
+}
+
+bool
+ThreadPlanContinue::StopOthers ()
+{
+ return m_stop_others;
+}
+
+StateType
+ThreadPlanContinue::RunState ()
+{
+ return eStateRunning;
+}
+
+bool
+ThreadPlanContinue::WillResume (StateType resume_state, bool current_plan)
+{
+ ThreadPlan::WillResume (resume_state, current_plan);
+ if (current_plan)
+ {
+ m_did_run = true;
+ }
+ return true;
+}
+
+bool
+ThreadPlanContinue::WillStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanContinue::MischiefManaged ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+
+ if (m_did_run)
+ {
+ if (log)
+ log->Printf("Completed continue plan.");
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+ else
+ return false;
+}
diff --git a/lldb/source/Target/ThreadPlanRunToAddress.cpp b/lldb/source/Target/ThreadPlanRunToAddress.cpp
new file mode 100644
index 00000000000..0544ea5bcbe
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanRunToAddress.cpp
@@ -0,0 +1,176 @@
+//===-- ThreadPlanRunToAddress.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/RegisterContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanRunToAddress: Continue plan
+//----------------------------------------------------------------------
+
+ThreadPlanRunToAddress::ThreadPlanRunToAddress
+(
+ Thread &thread,
+ Address &address,
+ bool stop_others
+) :
+ ThreadPlan ("Run to breakpoint plan", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_stop_others (stop_others),
+ m_address (LLDB_INVALID_ADDRESS),
+ m_break_id (LLDB_INVALID_BREAK_ID)
+{
+ m_address = address.GetLoadAddress(&m_thread.GetProcess());
+ SetInitialBreakpoint();
+}
+
+ThreadPlanRunToAddress::ThreadPlanRunToAddress
+(
+ Thread &thread,
+ lldb::addr_t address,
+ bool stop_others
+) :
+ ThreadPlan ("Run to breakpoint plan", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_stop_others (stop_others),
+ m_address (address),
+ m_break_id (LLDB_INVALID_BREAK_ID)
+{
+ SetInitialBreakpoint();
+}
+
+void
+ThreadPlanRunToAddress::SetInitialBreakpoint ()
+{
+ Breakpoint *breakpoint;
+ breakpoint = m_thread.GetProcess().GetTarget().CreateBreakpoint (m_address, true).get();
+ if (breakpoint != NULL)
+ {
+ m_break_id = breakpoint->GetID();
+ breakpoint->SetThreadID(m_thread.GetID());
+ }
+}
+
+ThreadPlanRunToAddress::~ThreadPlanRunToAddress ()
+{
+ if (m_break_id != LLDB_INVALID_BREAK_ID)
+ {
+ m_thread.GetProcess().GetTarget().RemoveBreakpointByID (m_break_id);
+ }
+}
+
+void
+ThreadPlanRunToAddress::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ {
+ s->Printf ("run to address: ");
+ s->Address (m_address, sizeof (addr_t));
+ }
+ else
+ {
+ s->Printf ("Run to address: ");
+ s->Address(m_address, sizeof (addr_t));
+ s->Printf (" using breakpoint: %d - ", m_break_id);
+ Breakpoint *breakpoint = m_thread.GetProcess().GetTarget().GetBreakpointByID (m_break_id).get();
+ if (breakpoint)
+ breakpoint->Dump (s);
+ else
+ s->Printf ("but the breakpoint has been deleted.");
+ }
+}
+
+bool
+ThreadPlanRunToAddress::ValidatePlan (Stream *error)
+{
+ // If we couldn't set the breakpoint for some reason, then this won't
+ // work.
+ if(m_break_id == LLDB_INVALID_BREAK_ID)
+ return false;
+ else
+ return true;
+}
+
+bool
+ThreadPlanRunToAddress::PlanExplainsStop ()
+{
+ return AtOurAddress();
+}
+
+bool
+ThreadPlanRunToAddress::ShouldStop (Event *event_ptr)
+{
+ return false;
+}
+
+bool
+ThreadPlanRunToAddress::StopOthers ()
+{
+ return m_stop_others;
+}
+
+void
+ThreadPlanRunToAddress::SetStopOthers (bool new_value)
+{
+ m_stop_others = new_value;
+}
+
+StateType
+ThreadPlanRunToAddress::RunState ()
+{
+ return eStateRunning;
+}
+
+bool
+ThreadPlanRunToAddress::WillStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanRunToAddress::MischiefManaged ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+
+ if (AtOurAddress())
+ {
+ // Remove the breakpoint
+ if (m_break_id != LLDB_INVALID_BREAK_ID)
+ {
+ m_thread.GetProcess().GetTarget().RemoveBreakpointByID (m_break_id);
+ m_break_id = LLDB_INVALID_BREAK_ID;
+ }
+
+ if (log)
+ log->Printf("Completed run to address plan.");
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+ else
+ return false;
+}
+
+bool
+ThreadPlanRunToAddress::AtOurAddress ()
+{
+ lldb::addr_t current_address = m_thread.GetRegisterContext()->GetPC();
+ return m_address == current_address;
+}
diff --git a/lldb/source/Target/ThreadPlanShouldStopHere.cpp b/lldb/source/Target/ThreadPlanShouldStopHere.cpp
new file mode 100644
index 00000000000..493ab63bc33
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanShouldStopHere.cpp
@@ -0,0 +1,53 @@
+//===-- ThreadPlanShouldStopHere.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanShouldStopHere.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+//----------------------------------------------------------------------
+// ThreadPlanShouldStopHere constructor
+//----------------------------------------------------------------------
+ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner, ThreadPlanShouldStopHereCallback callback, void *baton) :
+ m_callback (callback),
+ m_baton (baton),
+ m_owner (owner),
+ m_flags (ThreadPlanShouldStopHere::eNone)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ThreadPlanShouldStopHere::~ThreadPlanShouldStopHere()
+{
+}
+
+void
+ThreadPlanShouldStopHere::SetShouldStopHereCallback (ThreadPlanShouldStopHereCallback callback, void *baton)
+{
+ m_callback = callback;
+ m_baton = baton;
+}
+
+ThreadPlan *
+ThreadPlanShouldStopHere::InvokeShouldStopHereCallback ()
+{
+ if (m_callback)
+ return m_callback (m_owner, m_flags, m_baton);
+ else
+ return NULL;
+} \ No newline at end of file
diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp
new file mode 100644
index 00000000000..f62fdb87c7f
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanStepInRange.cpp
@@ -0,0 +1,154 @@
+//===-- ThreadPlanStepInRange.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/ThreadPlanStepInRange.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanStepOut.h"
+#include "lldb/Target/ThreadPlanStepThrough.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eAvoidNoDebug;
+
+//----------------------------------------------------------------------
+// ThreadPlanStepInRange: Step through a stack range, either stepping over or into
+// based on the value of \a type.
+//----------------------------------------------------------------------
+
+ThreadPlanStepInRange::ThreadPlanStepInRange
+(
+ Thread &thread,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_others
+) :
+ ThreadPlanStepRange ("Step Range stepping in", thread, range, addr_context, stop_others),
+ ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL)
+{
+ SetFlagsToDefault ();
+}
+
+ThreadPlanStepInRange::~ThreadPlanStepInRange ()
+{
+}
+
+void
+ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ s->Printf("step in");
+ else
+ {
+ s->Printf ("Stepping through range (stepping into functions): ");
+ m_address_range.Dump (s, &m_thread.GetProcess(), Address::DumpStyleLoadAddress);
+ }
+}
+
+bool
+ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ m_no_more_plans = false;
+
+ if (log)
+ {
+ StreamString s;
+ s.Address (m_thread.GetRegisterContext()->GetPC(), m_thread.GetProcess().GetAddressByteSize());
+ log->Printf("ThreadPlanStepInRange reached %s.", s.GetData());
+ }
+
+ // If we're still in the range, keep going.
+ if (InRange())
+ return false;
+
+ // If we're in an older frame then we should stop.
+ if (FrameIsOlder())
+ return true;
+
+ // See if we are in a place we should step through (i.e. a trampoline of some sort):
+ // One tricky bit here is that some stubs don't push a frame, so we have to check
+ // both the case of a frame that is younger, or the same as this frame.
+ // However, if the frame is the same, and we are still in the symbol we started
+ // in, the we don't need to do this. This first check isn't strictly necessary,
+ // but it is more efficient.
+
+ if (!FrameIsYounger() && InSymbol())
+ {
+ SetPlanComplete();
+ return true;
+ }
+
+ ThreadPlan* new_plan = NULL;
+
+ bool stop_others;
+ if (m_stop_others == lldb::eOnlyThisThread)
+ stop_others = true;
+ else
+ stop_others = false;
+
+ new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
+ // If not, give the "should_stop" callback a chance to push a plan to get us out of here.
+ // But only do that if we actually have stepped in.
+ if (!new_plan && FrameIsYounger())
+ new_plan = InvokeShouldStopHereCallback();
+
+ if (new_plan == NULL)
+ {
+ m_no_more_plans = true;
+ SetPlanComplete();
+ return true;
+ }
+ else
+ {
+ m_no_more_plans = false;
+ return false;
+ }
+}
+
+void
+ThreadPlanStepInRange::SetFlagsToDefault ()
+{
+ GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
+}
+
+void
+ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value)
+{
+ // TODO: Should we test this for sanity?
+ ThreadPlanStepInRange::s_default_flag_values = new_value;
+}
+
+ThreadPlan *
+ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
+{
+ if (flags.IsSet(eAvoidNoDebug))
+ {
+ StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
+
+ if (!frame->HasDebugInformation())
+ {
+ // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
+ return current_plan->GetThread().QueueThreadPlanForStepOut (false, NULL, true, current_plan->StopOthers(), eVoteNo, eVoteNoOpinion);
+ }
+ }
+
+ return NULL;
+}
diff --git a/lldb/source/Target/ThreadPlanStepInstruction.cpp b/lldb/source/Target/ThreadPlanStepInstruction.cpp
new file mode 100644
index 00000000000..41c4373105b
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanStepInstruction.cpp
@@ -0,0 +1,191 @@
+//===-- ThreadPlanStepInstruction.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "lldb/Target/ThreadPlanStepInstruction.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanStepInstruction: Step over the current instruction
+//----------------------------------------------------------------------
+
+ThreadPlanStepInstruction::ThreadPlanStepInstruction
+(
+ Thread &thread,
+ bool step_over,
+ bool stop_other_threads,
+ Vote stop_vote,
+ Vote run_vote
+) :
+ ThreadPlan ("Step over single instruction", thread, stop_vote, run_vote),
+ m_instruction_addr (0),
+ m_step_over (step_over),
+ m_stack_depth(0),
+ m_stop_other_threads (stop_other_threads)
+{
+ m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0);
+ m_stack_depth = m_thread.GetStackFrameCount();
+}
+
+ThreadPlanStepInstruction::~ThreadPlanStepInstruction ()
+{
+}
+
+void
+ThreadPlanStepInstruction::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ {
+ if (m_step_over)
+ s->Printf ("instruction step over");
+ else
+ s->Printf ("instruction step into");
+ }
+ else
+ {
+ s->Printf ("Stepping one instruction past ");
+ s->Address(m_instruction_addr, sizeof (addr_t));
+ if (m_step_over)
+ s->Printf(" stepping over calls");
+ else
+ s->Printf(" stepping into calls");
+ }
+}
+
+bool
+ThreadPlanStepInstruction::ValidatePlan (Stream *error)
+{
+ // Since we read the instruction we're stepping over from the thread,
+ // this plan will always work.
+ return true;
+}
+
+bool
+ThreadPlanStepInstruction::PlanExplainsStop ()
+{
+ Thread::StopInfo info;
+ if (m_thread.GetStopInfo (&info))
+ {
+ StopReason reason = info.GetStopReason();
+ if (reason == eStopReasonTrace || reason ==eStopReasonNone)
+ return true;
+ else
+ return false;
+ }
+ return false;
+}
+
+bool
+ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
+{
+ if (m_step_over)
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (m_thread.GetStackFrameCount() <= m_stack_depth)
+ {
+ if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
+ {
+ SetPlanComplete();
+ return true;
+ }
+ else
+ return false;
+ }
+ else
+ {
+ // We've stepped in, step back out again:
+ StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
+ if (return_frame)
+ {
+ if (log)
+ {
+ StreamString s;
+ s.PutCString ("Stepped in to: ");
+ addr_t stop_addr = m_thread.GetStackFrameAtIndex(0)->GetPC().GetLoadAddress(&m_thread.GetProcess());
+ s.Address (stop_addr, m_thread.GetProcess().GetAddressByteSize());
+ s.PutCString (" stepping out to: ");
+ addr_t return_addr = return_frame->GetPC().GetLoadAddress(&m_thread.GetProcess());
+ s.Address (return_addr, m_thread.GetProcess().GetAddressByteSize());
+ log->Printf("%s.", s.GetData());
+ }
+ m_thread.QueueThreadPlanForStepOut(false, NULL, true, m_stop_other_threads, eVoteNo, eVoteNoOpinion);
+ return false;
+ }
+ else
+ {
+ if (log)
+ log->Printf("Could not find previous frame, stopping.");
+ SetPlanComplete();
+ return true;
+ }
+
+ }
+
+ }
+ else
+ {
+ if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
+ {
+ SetPlanComplete();
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
+bool
+ThreadPlanStepInstruction::StopOthers ()
+{
+ return m_stop_other_threads;
+}
+
+StateType
+ThreadPlanStepInstruction::RunState ()
+{
+ return eStateStepping;
+}
+
+bool
+ThreadPlanStepInstruction::WillStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanStepInstruction::MischiefManaged ()
+{
+ if (IsPlanComplete())
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ log->Printf("Completed single instruction step plan.");
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp
new file mode 100644
index 00000000000..e05a8a440a1
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanStepOut.cpp
@@ -0,0 +1,228 @@
+//===-- ThreadPlanStepOut.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/ThreadPlanStepOut.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanStepOut: Step out of the current frame
+//----------------------------------------------------------------------
+
+ThreadPlanStepOut::ThreadPlanStepOut
+(
+ Thread &thread,
+ SymbolContext *context,
+ bool first_insn,
+ bool stop_others,
+ Vote stop_vote,
+ Vote run_vote
+) :
+ ThreadPlan ("Step out", thread, stop_vote, run_vote),
+ m_step_from_context (context),
+ m_step_from_insn (LLDB_INVALID_ADDRESS),
+ m_return_addr (LLDB_INVALID_ADDRESS),
+ m_first_insn (first_insn),
+ m_return_bp_id(LLDB_INVALID_BREAK_ID),
+ m_stop_others (stop_others)
+{
+ m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
+
+ // Find the return address and set a breakpoint there:
+ // FIXME - can we do this more securely if we know first_insn?
+
+ StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
+ if (return_frame)
+ {
+ m_return_addr = return_frame->GetPC().GetLoadAddress(&m_thread.GetProcess());
+ Breakpoint *return_bp = m_thread.GetProcess().GetTarget().CreateBreakpoint (m_return_addr, true).get();
+ if (return_bp != NULL)
+ {
+ return_bp->SetThreadID(m_thread.GetID());
+ m_return_bp_id = return_bp->GetID();
+ }
+ else
+ {
+ m_return_bp_id = LLDB_INVALID_BREAK_ID;
+ }
+ }
+
+ m_stack_depth = m_thread.GetStackFrameCount();
+}
+
+ThreadPlanStepOut::~ThreadPlanStepOut ()
+{
+ if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
+ m_thread.GetProcess().GetTarget().RemoveBreakpointByID(m_return_bp_id);
+}
+
+void
+ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ s->Printf ("step out");
+ else
+ {
+ s->Printf ("Stepping out from address 0x%llx to return address 0x%llx using breakpoint site %d",
+ (uint64_t)m_step_from_insn,
+ (uint64_t)m_return_addr,
+ m_return_bp_id);
+ }
+}
+
+bool
+ThreadPlanStepOut::ValidatePlan (Stream *error)
+{
+ if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
+ return false;
+ else
+ return true;
+}
+
+bool
+ThreadPlanStepOut::PlanExplainsStop ()
+{
+ // We don't explain signals or breakpoints (breakpoints that handle stepping in or
+ // out will be handled by a child plan.
+ Thread::StopInfo info;
+ if (m_thread.GetStopInfo (&info))
+ {
+ StopReason reason = info.GetStopReason();
+
+ switch (reason)
+ {
+ case eStopReasonBreakpoint:
+ {
+ // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
+ BreakpointSiteSP this_site = m_thread.GetProcess().GetBreakpointSiteList().FindByID (info.GetBreakpointSiteID());
+ if (!this_site)
+ return false;
+
+ if (this_site->IsBreakpointAtThisSite (m_return_bp_id))
+ {
+ // If there was only one owner, then we're done. But if we also hit some
+ // user breakpoint on our way out, we should mark ourselves as done, but
+ // also not claim to explain the stop, since it is more important to report
+ // the user breakpoint than the step out completion.
+
+ if (this_site->GetNumberOfOwners() == 1)
+ return true;
+ else
+ {
+ SetPlanComplete();
+ return false;
+ }
+ }
+ else
+ return false;
+ }
+ case eStopReasonWatchpoint:
+ case eStopReasonSignal:
+ case eStopReasonException:
+ return false;
+ default:
+ return true;
+ }
+ }
+ return true;
+}
+
+bool
+ThreadPlanStepOut::ShouldStop (Event *event_ptr)
+{
+ if (IsPlanComplete()
+ || m_thread.GetRegisterContext()->GetPC() == m_return_addr
+ || m_stack_depth > m_thread.GetStackFrameCount())
+ {
+ SetPlanComplete();
+ return true;
+ }
+ else
+ return false;
+}
+
+bool
+ThreadPlanStepOut::StopOthers ()
+{
+ return m_stop_others;
+}
+
+StateType
+ThreadPlanStepOut::RunState ()
+{
+ return eStateRunning;
+}
+
+bool
+ThreadPlanStepOut::WillResume (StateType resume_state, bool current_plan)
+{
+ ThreadPlan::WillResume (resume_state, current_plan);
+ if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
+ return false;
+
+ if (current_plan)
+ {
+ Breakpoint *return_bp = m_thread.GetProcess().GetTarget().GetBreakpointByID(m_return_bp_id).get();
+ if (return_bp != NULL)
+ return_bp->SetEnabled (true);
+ }
+ return true;
+}
+
+bool
+ThreadPlanStepOut::WillStop ()
+{
+ Breakpoint *return_bp = m_thread.GetProcess().GetTarget().GetBreakpointByID(m_return_bp_id).get();
+ if (return_bp != NULL)
+ return_bp->SetEnabled (false);
+ return true;
+}
+
+bool
+ThreadPlanStepOut::MischiefManaged ()
+{
+ if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
+ {
+ // If I couldn't set this breakpoint, then I'm just going to jettison myself.
+ return true;
+ }
+ else if (IsPlanComplete())
+ {
+ // Did I reach my breakpoint? If so I'm done.
+ //
+ // I also check the stack depth, since if we've blown past the breakpoint for some
+ // reason and we're now stopping for some other reason altogether, then we're done
+ // with this step out operation.
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ log->Printf("Completed step out plan.");
+ m_thread.GetProcess().GetTarget().RemoveBreakpointByID (m_return_bp_id);
+ m_return_bp_id = LLDB_INVALID_BREAK_ID;
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
diff --git a/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp b/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp
new file mode 100644
index 00000000000..2b8b06d5960
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp
@@ -0,0 +1,130 @@
+//===-- ThreadPlanStepOverBreakpoint.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/ThreadPlanStepOverBreakpoint.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanStepOverBreakpoint: Single steps over a breakpoint bp_site_sp at the pc.
+//----------------------------------------------------------------------
+
+ThreadPlanStepOverBreakpoint::ThreadPlanStepOverBreakpoint (Thread &thread) :
+ ThreadPlan ("Step over breakpoint trap",
+ thread,
+ eVoteNo,
+ eVoteNoOpinion), // We need to report the run since this happens
+ // first in the thread plan stack when stepping
+ // over a breakpoint
+ m_breakpoint_addr (LLDB_INVALID_ADDRESS)
+{
+ m_breakpoint_addr = m_thread.GetRegisterContext()->GetPC();
+ m_breakpoint_site_id = m_thread.GetProcess().GetBreakpointSiteList().FindIDByAddress (m_breakpoint_addr);
+
+}
+
+ThreadPlanStepOverBreakpoint::~ThreadPlanStepOverBreakpoint ()
+{
+}
+
+void
+ThreadPlanStepOverBreakpoint::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ s->Printf("Single stepping past breakpoint site %d at 0x%llx", m_breakpoint_site_id, (uint64_t)m_breakpoint_addr);
+}
+
+bool
+ThreadPlanStepOverBreakpoint::ValidatePlan (Stream *error)
+{
+ return true;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::PlanExplainsStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::ShouldStop (Event *event_ptr)
+{
+ return false;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::StopOthers ()
+{
+ return true;
+}
+
+StateType
+ThreadPlanStepOverBreakpoint::RunState ()
+{
+ return eStateStepping;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::WillResume (StateType resume_state, bool current_plan)
+{
+ ThreadPlan::WillResume (resume_state, current_plan);
+
+ if (current_plan)
+ {
+ BreakpointSiteSP bp_site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByAddress (m_breakpoint_addr));
+ if (bp_site_sp && bp_site_sp->IsEnabled())
+ m_thread.GetProcess().DisableBreakpoint (bp_site_sp.get());
+ }
+ return true;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::WillStop ()
+{
+ BreakpointSiteSP bp_site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByAddress (m_breakpoint_addr));
+ if (bp_site_sp)
+ m_thread.GetProcess().EnableBreakpoint (bp_site_sp.get());
+ return true;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::MischiefManaged ()
+{
+ lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC();
+
+ if (pc_addr == m_breakpoint_addr)
+ {
+ // If we are still at the PC of our breakpoint, then for some reason we didn't
+ // get a chance to run.
+ return false;
+ }
+ else
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ log->Printf("Completed step over breakpoint plan.");
+ // Otherwise, re-enable the breakpoint we were stepping over, and we're done.
+ BreakpointSiteSP bp_site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByAddress (m_breakpoint_addr));
+ if (bp_site_sp)
+ m_thread.GetProcess().EnableBreakpoint (bp_site_sp.get());
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+}
+
diff --git a/lldb/source/Target/ThreadPlanStepOverRange.cpp b/lldb/source/Target/ThreadPlanStepOverRange.cpp
new file mode 100644
index 00000000000..ea56412a010
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanStepOverRange.cpp
@@ -0,0 +1,119 @@
+//===-- ThreadPlanStepOverRange.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/ThreadPlanStepOverRange.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanStepOut.h"
+#include "lldb/Target/ThreadPlanStepThrough.h"
+
+using namespace lldb_private;
+
+
+//----------------------------------------------------------------------
+// ThreadPlanStepOverRange: Step through a stack range, either stepping over or into
+// based on the value of \a type.
+//----------------------------------------------------------------------
+
+ThreadPlanStepOverRange::ThreadPlanStepOverRange
+(
+ Thread &thread,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_others,
+ bool okay_to_discard
+) :
+ ThreadPlanStepRange ("Step range stepping over", thread, range, addr_context, stop_others)
+{
+ SetOkayToDiscard (okay_to_discard);
+}
+
+ThreadPlanStepOverRange::~ThreadPlanStepOverRange ()
+{
+}
+
+void
+ThreadPlanStepOverRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ s->Printf("step over");
+ else
+ {
+ s->Printf ("stepping through range (stepping over functions): ");
+ m_address_range.Dump (s, &m_thread.GetProcess(), Address::DumpStyleLoadAddress);
+ }
+}
+
+bool
+ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+
+ if (log)
+ {
+ StreamString s;
+ s.Address (m_thread.GetRegisterContext()->GetPC(), m_thread.GetProcess().GetAddressByteSize());
+ log->Printf("ThreadPlanStepOverRange reached %s.", s.GetData());
+ }
+
+ // If we're still in the range, keep going.
+ if (InRange())
+ return false;
+
+ // If we're out of the range but in the same frame or in our caller's frame
+ // then we should stop.
+ // When stepping out we only step if we are forcing running one thread.
+ bool stop_others;
+ if (m_stop_others == lldb::eOnlyThisThread)
+ stop_others = true;
+ else
+ stop_others = false;
+
+ ThreadPlan* new_plan = NULL;
+
+ if (FrameIsOlder())
+ return true;
+ else if (FrameIsYounger())
+ {
+ new_plan = m_thread.QueueThreadPlanForStepOut (false, NULL, true, stop_others, lldb::eVoteNo, lldb::eVoteNoOpinion);
+ }
+ else if (!InSymbol())
+ {
+ // This one is a little tricky. Sometimes we may be in a stub or something similar,
+ // in which case we need to get out of there. But if we are in a stub then it's
+ // likely going to be hard to get out from here. It is probably easiest to step into the
+ // stub, and then it will be straight-forward to step out.
+ new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
+ }
+
+ if (new_plan == NULL)
+ m_no_more_plans = true;
+ else
+ m_no_more_plans = false;
+
+ if (new_plan == NULL)
+ {
+ // For efficiencies sake, we know we're done here so we don't have to do this
+ // calculation again in MischiefManaged.
+ SetPlanComplete();
+ return true;
+ }
+ else
+ return false;
+}
diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp
new file mode 100644
index 00000000000..edf80a57d52
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanStepRange.cpp
@@ -0,0 +1,263 @@
+//===-- ThreadPlanStepRange.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/ThreadPlanStepRange.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+//----------------------------------------------------------------------
+// ThreadPlanStepRange: Step through a stack range, either stepping over or into
+// based on the value of \a type.
+//----------------------------------------------------------------------
+
+ThreadPlanStepRange::ThreadPlanStepRange (const char *name, Thread &thread, const AddressRange &range, const SymbolContext &addr_context, lldb::RunMode stop_others) :
+ ThreadPlan (name, thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_address_range (range),
+ m_addr_context (addr_context),
+ m_stop_others (stop_others),
+ m_stack_depth (0),
+ m_no_more_plans (false),
+ m_stack_id (),
+ m_first_run_event (true)
+{
+ m_stack_depth = m_thread.GetStackFrameCount();
+ m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+}
+
+ThreadPlanStepRange::~ThreadPlanStepRange ()
+{
+}
+
+bool
+ThreadPlanStepRange::ValidatePlan (Stream *error)
+{
+ return true;
+}
+
+bool
+ThreadPlanStepRange::PlanExplainsStop ()
+{
+ // We don't explain signals or breakpoints (breakpoints that handle stepping in or
+ // out will be handled by a child plan.
+ Thread::StopInfo info;
+ if (m_thread.GetStopInfo (&info))
+ {
+ StopReason reason = info.GetStopReason();
+
+ switch (reason)
+ {
+ case eStopReasonBreakpoint:
+ case eStopReasonWatchpoint:
+ case eStopReasonSignal:
+ case eStopReasonException:
+ return false;
+ default:
+ return true;
+ }
+ }
+ return true;
+}
+
+Vote
+ThreadPlanStepRange::ShouldReportStop (Event *event_ptr)
+{
+ if (IsPlanComplete())
+ return eVoteYes;
+ else
+ return eVoteNo;
+}
+
+bool
+ThreadPlanStepRange::InRange ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ bool ret_value = false;
+
+ lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC();
+
+ ret_value = m_address_range.ContainsLoadAddress(pc_load_addr, &m_thread.GetProcess());
+
+ if (!ret_value)
+ {
+ // See if we've just stepped to another part of the same line number...
+ StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get();
+
+ SymbolContext new_context(frame->GetSymbolContext(eSymbolContextEverything));
+ if (m_addr_context.line_entry.IsValid() && new_context.line_entry.IsValid())
+ {
+ if ((m_addr_context.line_entry.file == new_context.line_entry.file)
+ && (m_addr_context.line_entry.line == new_context.line_entry.line))
+ {
+ m_addr_context = new_context;
+ m_address_range = m_addr_context.line_entry.range;
+ ret_value = true;
+ if (log)
+ {
+ StreamString s;
+ m_address_range.Dump (&s, &m_thread.GetProcess(), Address::DumpStyleLoadAddress);
+
+ log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData());
+ }
+ }
+ }
+
+ }
+
+ if (!ret_value && log)
+ log->Printf ("Step range plan out of range to 0x%llx", pc_load_addr);
+
+ return ret_value;
+}
+
+bool
+ThreadPlanStepRange::InSymbol()
+{
+ lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
+ Process *process = m_thread.CalculateProcess();
+
+ if (m_addr_context.function != NULL)
+ {
+ return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, process);
+ }
+ else if (m_addr_context.symbol != NULL)
+ {
+ return m_addr_context.symbol->GetAddressRangeRef().ContainsLoadAddress (cur_pc, process);
+ }
+ return false;
+}
+
+// FIXME: This should also handle inlining if we aren't going to do inlining in the
+// main stack.
+//
+// Ideally we should remember the whole stack frame list, and then compare that
+// to the current list.
+
+bool
+ThreadPlanStepRange::FrameIsYounger ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ uint32_t current_depth = m_thread.GetStackFrameCount();
+ if (current_depth == m_stack_depth)
+ {
+ if (log)
+ log->Printf ("Step range FrameIsYounger still in start function.");
+ return false;
+ }
+ else if (current_depth < m_stack_depth)
+ {
+ if (log)
+ log->Printf ("Step range FrameIsYounger stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
+ return false;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Step range FrameIsYounger stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
+ return true;
+ }
+}
+
+bool
+ThreadPlanStepRange::FrameIsOlder ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ uint32_t current_depth = m_thread.GetStackFrameCount();
+ if (current_depth == m_stack_depth)
+ {
+ if (log)
+ log->Printf ("Step range FrameIsOlder still in start function.");
+ return false;
+ }
+ else if (current_depth < m_stack_depth)
+ {
+ if (log)
+ log->Printf ("Step range FrameIsOlder stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
+ return true;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Step range FrameIsOlder stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
+ return false;
+ }
+}
+
+bool
+ThreadPlanStepRange::StopOthers ()
+{
+ if (m_stop_others == lldb::eOnlyThisThread
+ || m_stop_others == lldb::eOnlyDuringStepping)
+ return true;
+ else
+ return false;
+}
+
+bool
+ThreadPlanStepRange::WillStop ()
+{
+ return true;
+}
+
+StateType
+ThreadPlanStepRange::RunState ()
+{
+ return eStateStepping;
+}
+
+bool
+ThreadPlanStepRange::MischiefManaged ()
+{
+ bool done = true;
+ if (!IsPlanComplete())
+ {
+ if (InRange())
+ {
+ done = false;
+ }
+ else if (!FrameIsOlder())
+ {
+ if (m_no_more_plans)
+ done = true;
+ else
+ done = false;
+ }
+ else
+ done = true;
+ }
+
+ if (done)
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ log->Printf("Completed step through range plan.");
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+
+}
diff --git a/lldb/source/Target/ThreadPlanStepThrough.cpp b/lldb/source/Target/ThreadPlanStepThrough.cpp
new file mode 100644
index 00000000000..5e614e5aa52
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanStepThrough.cpp
@@ -0,0 +1,137 @@
+//===-- ThreadPlanStepThrough.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/ThreadPlanStepThrough.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanStepThrough: If the current instruction is a trampoline, step through it
+// If it is the beginning of the prologue of a function, step through that as well.
+// FIXME: At present only handles DYLD trampolines.
+//----------------------------------------------------------------------
+
+ThreadPlanStepThrough::ThreadPlanStepThrough (Thread &thread, bool stop_others) :
+ ThreadPlan ("Step through trampolines and prologues", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_start_address (0),
+ m_stop_others (stop_others)
+{
+ m_start_address = GetThread().GetRegisterContext()->GetPC(0);
+}
+
+ThreadPlanStepThrough::~ThreadPlanStepThrough ()
+{
+}
+
+void
+ThreadPlanStepThrough::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ s->Printf ("Step through");
+ else
+ {
+ s->Printf ("Stepping through trampoline code from: ");
+ s->Address(m_start_address, sizeof (addr_t));
+ }
+}
+
+bool
+ThreadPlanStepThrough::ValidatePlan (Stream *error)
+{
+ if (HappyToStopHere())
+ return false;
+ else
+ return true;
+}
+
+bool
+ThreadPlanStepThrough::PlanExplainsStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanStepThrough::ShouldStop (Event *event_ptr)
+{
+ return true;
+}
+
+bool
+ThreadPlanStepThrough::StopOthers ()
+{
+ return m_stop_others;
+}
+
+StateType
+ThreadPlanStepThrough::RunState ()
+{
+ return eStateStepping;
+}
+
+bool
+ThreadPlanStepThrough::WillResume (StateType resume_state, bool current_plan)
+{
+ ThreadPlan::WillResume(resume_state, current_plan);
+ if (current_plan)
+ {
+ ThreadPlanSP sub_plan_sp(m_thread.GetProcess().GetDynamicLoader()->GetStepThroughTrampolinePlan (m_thread, m_stop_others));
+ if (sub_plan_sp != NULL)
+ PushPlan (sub_plan_sp);
+ }
+ return true;
+}
+
+bool
+ThreadPlanStepThrough::WillStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanStepThrough::MischiefManaged ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+
+ // Stop if we're happy with the place we've landed...
+
+ if (!HappyToStopHere())
+ {
+ // If we are still at the PC we were trying to step over.
+ return false;
+ }
+ else
+ {
+ if (log)
+ log->Printf("Completed step through step plan.");
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+}
+
+bool
+ThreadPlanStepThrough::HappyToStopHere()
+{
+ // This should again ask the various trampolines whether we are still at a
+ // trampoline point, and if so, continue through the possibly nested trampolines.
+
+ return true;
+}
+
diff --git a/lldb/source/Target/ThreadPlanStepUntil.cpp b/lldb/source/Target/ThreadPlanStepUntil.cpp
new file mode 100644
index 00000000000..3f9cdb55047
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanStepUntil.cpp
@@ -0,0 +1,360 @@
+//===-- ThreadPlanStepUntil.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//m_should_stop
+
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/ThreadPlanStepUntil.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanStepUntil: Run until we reach a given line number or step out of the current frame
+//----------------------------------------------------------------------
+
+ThreadPlanStepUntil::ThreadPlanStepUntil
+(
+ Thread &thread,
+ lldb::addr_t *address_list,
+ size_t num_addresses,
+ bool stop_others
+) :
+ ThreadPlan ("Step out", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_step_from_insn (LLDB_INVALID_ADDRESS),
+ m_return_addr (LLDB_INVALID_ADDRESS),
+ m_return_bp_id(LLDB_INVALID_BREAK_ID),
+ m_stepped_out(false),
+ m_should_stop(false),
+ m_explains_stop(false),
+ m_ran_analyze (false),
+ m_stop_others (stop_others)
+{
+
+ SetOkayToDiscard(true);
+ // Stash away our "until" addresses:
+ Target &target = m_thread.GetProcess().GetTarget();
+
+ m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
+ lldb::user_id_t thread_id = m_thread.GetID();
+
+ // Find the return address and set a breakpoint there:
+ // FIXME - can we do this more securely if we know first_insn?
+
+ StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
+ m_return_addr = return_frame->GetPC().GetLoadAddress(&m_thread.GetProcess());
+ Breakpoint *return_bp = target.CreateBreakpoint (m_return_addr, true).get();
+ if (return_bp != NULL)
+ {
+ return_bp->SetThreadID(thread_id);
+ m_return_bp_id = return_bp->GetID();
+ }
+ else
+ {
+ m_return_bp_id = LLDB_INVALID_BREAK_ID;
+ }
+
+ m_stack_depth = m_thread.GetStackFrameCount();
+
+ // Now set breakpoints on all our return addresses:
+ for (int i = 0; i < num_addresses; i++)
+ {
+ Breakpoint *until_bp = target.CreateBreakpoint (address_list[i], true).get();
+ if (until_bp != NULL)
+ {
+ until_bp->SetThreadID(thread_id);
+ m_until_points[address_list[i]] = until_bp->GetID();
+ }
+ else
+ {
+ m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
+ }
+ }
+}
+
+ThreadPlanStepUntil::~ThreadPlanStepUntil ()
+{
+ Clear();
+}
+
+void
+ThreadPlanStepUntil::Clear()
+{
+ Target &target = m_thread.GetProcess().GetTarget();
+ if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
+ {
+ target.RemoveBreakpointByID(m_return_bp_id);
+ m_return_bp_id = LLDB_INVALID_BREAK_ID;
+ }
+
+ until_collection::iterator pos, end = m_until_points.end();
+ for (pos = m_until_points.begin(); pos != end; pos++)
+ {
+ target.RemoveBreakpointByID((*pos).second);
+ }
+ m_until_points.clear();
+}
+
+void
+ThreadPlanStepUntil::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ {
+ s->Printf ("step until");
+ if (m_stepped_out)
+ s->Printf (" - stepped out");
+ }
+ else
+ {
+ if (m_until_points.size() == 1)
+ s->Printf ("Stepping from address 0x%llx until we reach 0x%llx using breakpoint %d",
+ (uint64_t)m_step_from_insn,
+ (uint64_t) (*m_until_points.begin()).first,
+ (*m_until_points.begin()).second);
+ else
+ {
+ until_collection::iterator pos, end = m_until_points.end();
+ s->Printf ("Stepping from address 0x%llx until we reach one of:",
+ (uint64_t)m_step_from_insn);
+ for (pos = m_until_points.begin(); pos != end; pos++)
+ {
+ s->Printf ("\n\t0x%llx (bp: %d)", (uint64_t) (*pos).first, (*pos).second);
+ }
+ }
+ s->Printf(" stepped out address is 0x%lx.", (uint64_t) m_return_addr);
+ }
+}
+
+bool
+ThreadPlanStepUntil::ValidatePlan (Stream *error)
+{
+ if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
+ return false;
+ else
+ {
+ until_collection::iterator pos, end = m_until_points.end();
+ for (pos = m_until_points.begin(); pos != end; pos++)
+ {
+ if (!LLDB_BREAK_ID_IS_VALID ((*pos).second))
+ return false;
+ }
+ return true;
+ }
+}
+
+void
+ThreadPlanStepUntil::AnalyzeStop()
+{
+ if (m_ran_analyze)
+ return;
+
+ Thread::StopInfo info;
+ m_should_stop = true;
+ m_explains_stop = false;
+
+ if (m_thread.GetStopInfo (&info))
+ {
+ StopReason reason = info.GetStopReason();
+
+ switch (reason)
+ {
+ case eStopReasonBreakpoint:
+ {
+ // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
+ BreakpointSiteSP this_site = m_thread.GetProcess().GetBreakpointSiteList().FindByID (info.GetBreakpointSiteID());
+ if (!this_site)
+ {
+ m_explains_stop = false;
+ return;
+ }
+
+ if (this_site->IsBreakpointAtThisSite (m_return_bp_id))
+ {
+ // If we are at our "step out" breakpoint, and the stack depth has shrunk, then
+ // this is indeed our stop.
+ // If the stack depth has grown, then we've hit our step out breakpoint recursively.
+ // If we are the only breakpoint at that location, then we do explain the stop, and
+ // we'll just continue.
+ // If there was another breakpoint here, then we don't explain the stop, but we won't
+ // mark ourselves Completed, because maybe that breakpoint will continue, and then
+ // we'll finish the "until".
+ if (m_stack_depth > m_thread.GetStackFrameCount())
+ {
+ m_stepped_out = true;
+ SetPlanComplete();
+ }
+ else
+ m_should_stop = false;
+
+ if (this_site->GetNumberOfOwners() == 1)
+ m_explains_stop = true;
+ else
+ m_explains_stop = false;
+ return;
+ }
+ else
+ {
+ // Check if we've hit one of our "until" breakpoints.
+ until_collection::iterator pos, end = m_until_points.end();
+ for (pos = m_until_points.begin(); pos != end; pos++)
+ {
+ if (this_site->IsBreakpointAtThisSite ((*pos).second))
+ {
+ // If we're at the right stack depth, then we're done.
+ if (m_stack_depth == m_thread.GetStackFrameCount())
+ SetPlanComplete();
+ else
+ m_should_stop = false;
+
+ // Otherwise we've hit this breakpoint recursively. If we're the
+ // only breakpoint here, then we do explain the stop, and we'll continue.
+ // If not then we should let higher plans handle this stop.
+ if (this_site->GetNumberOfOwners() == 1)
+ m_explains_stop = true;
+ else
+ {
+ m_should_stop = true;
+ m_explains_stop = false;
+ }
+ return;
+ }
+ }
+ }
+ // If we get here we haven't hit any of our breakpoints, so let the higher
+ // plans take care of the stop.
+ m_explains_stop = false;
+ return;
+ }
+ case eStopReasonWatchpoint:
+ case eStopReasonSignal:
+ case eStopReasonException:
+ m_explains_stop = false;
+ break;
+ default:
+ m_explains_stop = true;
+ break;
+ }
+ }
+}
+
+bool
+ThreadPlanStepUntil::PlanExplainsStop ()
+{
+ // We don't explain signals or breakpoints (breakpoints that handle stepping in or
+ // out will be handled by a child plan.
+ AnalyzeStop();
+ return m_explains_stop;
+}
+
+bool
+ThreadPlanStepUntil::ShouldStop (Event *event_ptr)
+{
+ // If we've told our self in ExplainsStop that we plan to continue, then
+ // do so here. Otherwise, as long as this thread has stopped for a reason,
+ // we will stop.
+
+ Thread::StopInfo stop_info (&m_thread);
+ if (!m_thread.GetStopInfo(&stop_info)
+ || stop_info.GetStopReason() == eStopReasonNone)
+ return false;
+
+ AnalyzeStop();
+ return m_should_stop;
+}
+
+bool
+ThreadPlanStepUntil::StopOthers ()
+{
+ return m_stop_others;
+}
+
+StateType
+ThreadPlanStepUntil::RunState ()
+{
+ return eStateRunning;
+}
+
+bool
+ThreadPlanStepUntil::WillResume (StateType resume_state, bool current_plan)
+{
+ ThreadPlan::WillResume (resume_state, current_plan);
+ if (current_plan)
+ {
+ Target &target = m_thread.GetProcess().GetTarget();
+ Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
+ if (return_bp != NULL)
+ return_bp->SetEnabled (true);
+
+ until_collection::iterator pos, end = m_until_points.end();
+ for (pos = m_until_points.begin(); pos != end; pos++)
+ {
+ Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
+ if (until_bp != NULL)
+ until_bp->SetEnabled (true);
+ }
+ }
+
+ m_should_stop = true;
+ m_ran_analyze = false;
+ m_explains_stop = false;
+ return true;
+}
+
+bool
+ThreadPlanStepUntil::WillStop ()
+{
+ Target &target = m_thread.GetProcess().GetTarget();
+ Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
+ if (return_bp != NULL)
+ return_bp->SetEnabled (false);
+
+ until_collection::iterator pos, end = m_until_points.end();
+ for (pos = m_until_points.begin(); pos != end; pos++)
+ {
+ Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
+ if (until_bp != NULL)
+ until_bp->SetEnabled (false);
+ }
+ return true;
+}
+
+bool
+ThreadPlanStepUntil::MischiefManaged ()
+{
+
+ // I'm letting "PlanExplainsStop" do all the work, and just reporting that here.
+ bool done = false;
+ if (IsPlanComplete())
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ log->Printf("Completed step until plan.");
+
+ Clear();
+ done = true;
+ }
+ if (done)
+ ThreadPlan::MischiefManaged ();
+
+ return done;
+
+}
+
diff --git a/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp
new file mode 100644
index 00000000000..e6500c5dba8
--- /dev/null
+++ b/lldb/source/Target/UnixSignals.cpp
@@ -0,0 +1,310 @@
+//===-- UnixSignals.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/UnixSignals.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb_private;
+
+UnixSignals::Signal::Signal (const char *name, bool default_suppress, bool default_stop, bool default_notify) :
+ m_name (name),
+ m_conditions ()
+{
+ m_conditions[Signal::eCondSuppress] = default_suppress;
+ m_conditions[Signal::eCondStop] = default_stop;
+ m_conditions[Signal::eCondNotify] = default_notify;
+}
+
+//----------------------------------------------------------------------
+// UnixSignals constructor
+//----------------------------------------------------------------------
+UnixSignals::UnixSignals ()
+{
+ Reset ();
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+UnixSignals::~UnixSignals ()
+{
+}
+
+void
+UnixSignals::Reset ()
+{
+ // This builds one standard set of Unix Signals. If yours aren't quite in this
+ // order, you can either subclass this class, and use Add & Remove to change them
+ // or you can subclass and build them afresh in your constructor;
+ m_signals.clear();
+
+ AddSignal(1, "SIGHUP", false, true, true ); // 1 hangup
+ AddSignal(2, "SIGINT", true, true, true ); // 2 interrupt
+ AddSignal(3, "SIGQUIT", false, true, true ); // 3 quit
+ AddSignal(4, "SIGILL", false, true, true ); // 4 illegal instruction (not reset when caught)
+ AddSignal(5, "SIGTRAP", true, true, true ); // 5 trace trap (not reset when caught)
+ AddSignal(6, "SIGABRT", false, true, true ); // 6 abort()
+ AddSignal(7, "SIGEMT", false, true, true ); // 7 pollable event ([XSR] generated, not supported)
+ AddSignal(8, "SIGFPE", false, true, true ); // 8 floating point exception
+ AddSignal(9, "SIGKILL", false, true, true ); // 9 kill (cannot be caught or ignored)
+ AddSignal(10, "SIGBUS", false, true, true ); // 10 bus error
+ AddSignal(11, "SIGSEGV", false, true, true ); // 11 segmentation violation
+ AddSignal(12, "SIGSYS", false, true, true ); // 12 bad argument to system call
+ AddSignal(13, "SIGPIPE", false, true, true ); // 13 write on a pipe with no one to read it
+ AddSignal(14, "SIGALRM", false, false, true ); // 14 alarm clock
+ AddSignal(15, "SIGTERM", false, true, true ); // 15 software termination signal from kill
+ AddSignal(16, "SIGURG", false, false, false); // 16 urgent condition on IO channel
+ AddSignal(17, "SIGSTOP", false, true, true ); // 17 sendable stop signal not from tty
+ AddSignal(18, "SIGTSTP", false, true, true ); // 18 stop signal from tty
+ AddSignal(19, "SIGCONT", false, true, true ); // 19 continue a stopped process
+ AddSignal(20, "SIGCHLD", false, false, true ); // 20 to parent on child stop or exit
+ AddSignal(21, "SIGTTIN", false, true, true ); // 21 to readers pgrp upon background tty read
+ AddSignal(22, "SIGTTOU", false, true, true ); // 22 like TTIN for output if (tp->t_local&LTOSTOP)
+ AddSignal(23, "SIGIO", false, false, false); // 23 input/output possible signal
+ AddSignal(24, "SIGXCPU", false, true, true ); // 24 exceeded CPU time limit
+ AddSignal(25, "SIGXFSZ", false, true, true ); // 25 exceeded file size limit
+ AddSignal(26, "SIGVTALRM", false, false, false); // 26 virtual time alarm
+ AddSignal(27, "SIGPROF", false, false, false); // 27 profiling time alarm
+ AddSignal(28, "SIGWINCH", false, false, false); // 28 window size changes
+ AddSignal(29, "SIGINFO", false, true, true ); // 29 information request
+ AddSignal(30, "SIGUSR1", false, true, true ); // 30 user defined signal 1
+ AddSignal(31, "SIGUSR2", false, true, true ); // 31 user defined signal 2
+}
+void
+UnixSignals::AddSignal (int signo, const char *name, bool default_suppress, bool default_stop, bool default_notify)
+{
+ collection::iterator iter = m_signals.find (signo);
+ struct Signal new_signal (name, default_suppress, default_stop, default_notify);
+
+ if (iter != m_signals.end())
+ m_signals.erase (iter);
+
+ m_signals.insert (iter, collection::value_type (signo, new_signal));
+}
+
+void
+UnixSignals::RemoveSignal (int signo)
+{
+ collection::iterator pos = m_signals.find (signo);
+ if (pos != m_signals.end())
+ m_signals.erase (pos);
+}
+
+UnixSignals::Signal *
+UnixSignals::GetSignalByName (const char *name, int32_t &signo)
+{
+ ConstString const_name (name);
+
+ collection::iterator pos, end = m_signals.end ();
+ for (pos = m_signals.begin (); pos != end; pos++)
+ {
+ if (const_name == (*pos).second.m_name)
+ {
+ signo = (*pos).first;
+ return &((*pos).second);
+ }
+ }
+ return NULL;
+}
+
+
+const UnixSignals::Signal *
+UnixSignals::GetSignalByName (const char *name, int32_t &signo) const
+{
+ ConstString const_name (name);
+
+ collection::const_iterator pos, end = m_signals.end ();
+ for (pos = m_signals.begin (); pos != end; pos++)
+ {
+ if (const_name == (*pos).second.m_name)
+ {
+ signo = (*pos).first;
+ return &((*pos).second);
+ }
+ }
+ return NULL;
+}
+
+const char *
+UnixSignals::GetSignalAsCString (int signo) const
+{
+ collection::const_iterator pos = m_signals.find (signo);
+ if (pos == m_signals.end())
+ return NULL;
+ else
+ return (*pos).second.m_name.GetCString ();
+}
+
+
+bool
+UnixSignals::SignalIsValid (int32_t signo) const
+{
+ return m_signals.find (signo) != m_signals.end();
+}
+
+
+int32_t
+UnixSignals::GetSignalNumberFromName (const char *name) const
+{
+ int32_t signo;
+ const Signal *signal = GetSignalByName (name, signo);
+ if (signal == NULL)
+ return LLDB_INVALID_SIGNAL_NUMBER;
+ else
+ return signo;
+}
+
+int32_t
+UnixSignals::GetFirstSignalNumber () const
+{
+ if (m_signals.empty())
+ return LLDB_INVALID_SIGNAL_NUMBER;
+
+ return (*m_signals.begin ()).first;
+}
+
+int32_t
+UnixSignals::GetNextSignalNumber (int32_t current_signal) const
+{
+ collection::const_iterator pos = m_signals.find (current_signal);
+ collection::const_iterator end = m_signals.end();
+ if (pos == end)
+ return LLDB_INVALID_SIGNAL_NUMBER;
+ else
+ {
+ pos++;
+ if (pos == end)
+ return LLDB_INVALID_SIGNAL_NUMBER;
+ else
+ return (*pos).first;
+ }
+}
+
+const char *
+UnixSignals::GetSignalInfo
+(
+ int32_t signo,
+ bool &should_suppress,
+ bool &should_stop,
+ bool &should_notify
+) const
+{
+ collection::const_iterator pos = m_signals.find (signo);
+ if (pos == m_signals.end())
+ return NULL;
+ else
+ {
+ const Signal &signal = (*pos).second;
+ should_suppress = signal.m_conditions[Signal::eCondSuppress];
+ should_stop = signal.m_conditions[Signal::eCondStop];
+ should_notify = signal.m_conditions[Signal::eCondNotify];
+ return signal.m_name.AsCString("");
+ }
+}
+
+bool
+UnixSignals::GetCondition
+(
+ int32_t signo,
+ UnixSignals::Signal::Condition cond_pos
+) const
+{
+ collection::const_iterator pos = m_signals.find (signo);
+ if (pos == m_signals.end())
+ return false;
+ else
+ return (*pos).second.m_conditions[cond_pos];
+}
+
+bool
+UnixSignals::SetCondition (int32_t signo, UnixSignals::Signal::Condition cond_pos, bool value)
+{
+ collection::iterator pos = m_signals.find (signo);
+ if (pos == m_signals.end())
+ return false;
+ else
+ {
+ bool ret_value = (*pos).second.m_conditions[cond_pos];
+ (*pos).second.m_conditions[cond_pos] = value;
+ return ret_value;
+ }
+}
+
+bool
+UnixSignals::SetCondition (const char *signal_name, UnixSignals::Signal::Condition cond_pos, bool value)
+{
+ int32_t signo;
+ Signal *signal = GetSignalByName (signal_name, signo);
+ if (signal == NULL)
+ return false;
+ else
+ {
+ bool ret_value = signal->m_conditions[cond_pos];
+ signal->m_conditions[cond_pos] = value;
+ return ret_value;
+ }
+}
+
+bool
+UnixSignals::GetShouldSuppress (int signo) const
+{
+ return GetCondition (signo, Signal::eCondSuppress);
+}
+
+bool
+UnixSignals::SetShouldSuppress (int signo, bool value)
+{
+ return SetCondition (signo, Signal::eCondSuppress, value);
+}
+
+bool
+UnixSignals::SetShouldSuppress (const char *signal_name, bool value)
+{
+ return SetCondition (signal_name, Signal::eCondSuppress, value);
+}
+
+bool
+UnixSignals::GetShouldStop (int signo) const
+{
+ return GetCondition (signo, Signal::eCondStop);
+}
+
+bool
+UnixSignals::SetShouldStop (int signo, bool value)
+{
+ return SetCondition (signo, Signal::eCondStop, value);
+}
+
+bool
+UnixSignals::SetShouldStop (const char *signal_name, bool value)
+{
+ return SetCondition (signal_name, Signal::eCondStop, value);
+}
+
+bool
+UnixSignals::GetShouldNotify (int signo) const
+{
+ return GetCondition (signo, Signal::eCondNotify);
+}
+
+bool
+UnixSignals::SetShouldNotify (int signo, bool value)
+{
+ return SetCondition (signo, Signal::eCondNotify, value);
+}
+
+bool
+UnixSignals::SetShouldNotify (const char *signal_name, bool value)
+{
+ return SetCondition (signal_name, Signal::eCondNotify, value);
+}
OpenPOWER on IntegriCloud