Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

2009-07-08 Martin Baulig <martin@ximian.com>

	Martin's new Threading Model.

	* classes/GUIManager.cs
	(GUIManager): Made this obsolete, it's now just a tiny wrapper
	around the new API.

	* classes/Operation.cs: New file.
	(ThreadingModel): New public enum.
	(CommandResult): New public abstract class.
	(OperationHost): New internal interface.
	(OperationCommandResult): New public class.

	* backend/ThreadServant.cs
	(ThreadServant.StepInstruction): Removed, use the new Step() API.
	(ThreadServant.StepNativeInstruction): Likewise.
	(ThreadServant.NextInstruction): Likewise.
	(ThreadServant.StepLine): Likewise.
	(ThreadServant.NextLine): Likewise.
	(ThreadServant.Finish): Removed, use the new Step() API.

	* backend/SingleSteppingEngine.cs
	(SSE.OperationStep): Add support for `StepMode.Run'; this
	obsoletes `OperationRun'.
	(SSE.OperationRun): Removed; use `OperationStep' with `StepMode.Run'.
	(SSE.OperationFinish): Removed; use `OperationStep' with
	`StepMode.Finish' or `StepMode.FinishNative'.

	* backend/StepFrame.cs: Moved to ../classes/StepFrame.cs.

	* classes/StepFrame.cs
	(StepMode): Made this public.
	(StepFrame): Make this public and [Serializable].
	(StepMode.Run): Added.
	(StepMode.FinishNative): Added.
	(StepFrame.Until): New public property; only valid in`
	StepMode.Run'.

	* classes/Thread.cs
	(Thread.Step): New public function.
	(Thread.StepInstruction): Obsolete, use the new Step() API.
	(Thread.StepNativeInstruction): Likewise.
	(Thread.NextInstruction): Likewise.
	(Thread.StepLine): Likewise.
	(Thread.NextLine): Likewise.
	(Thread.Continue): Use `Step (StepMode.Run)'.
	(Thread.Background): Obsolete; this was never implemented and
	always the same as Continue().
	(Thread.Finish): Obsolete, use the new Step() API.

	* backend/ThreadServant.cs
	(ThreadServant.Step): New public function.

svn path=/trunk/debugger/; revision=139051
  • Loading branch information...
commit 53ad566fcea1bfd49c1dd053dfeb2332fbfafa0c 1 parent 380cca2
Martin Baulig authored
Showing with 1,954 additions and 1,409 deletions.
  1. +54 −0 ChangeLog
  2. +89 −7 backend/DebuggerServant.cs
  3. +30 −4 backend/Inferior.cs
  4. +5 −3 backend/MonoThreadManager.cs
  5. +231 −30 backend/ProcessServant.cs
  6. +489 −430 backend/SingleSteppingEngine.cs
  7. +9 −6 backend/ThreadManager.cs
  8. +7 −47 backend/ThreadServant.cs
  9. +9 −29 backend/arch/CoreFile.cs
  10. +13 −0 backend/server/i386-arch.c
  11. +11 −2 backend/server/library.c
  12. +9 −2 backend/server/server.h
  13. +20 −18 backend/server/x86-linux-ptrace.c
  14. +4 −3 backend/server/x86-ptrace.c
  15. +13 −0 backend/server/x86_64-arch.c
  16. +27 −2 classes/Debugger.cs
  17. +104 −33 classes/DebuggerConfiguration.cs
  18. +9 −0 classes/DebuggerConfiguration.xsd
  19. +46 −8 classes/DebuggerSession.cs
  20. +42 −329 classes/GUIManager.cs
  21. +108 −0 classes/Operation.cs
  22. +8 −18 classes/Process.cs
  23. +29 −8 {backend → classes}/StepFrame.cs
  24. +102 −104 classes/Thread.cs
  25. +135 −76 frontend/Command.cs
  26. +19 −6 frontend/Expression.cs
  27. +39 −197 frontend/Interpreter.cs
  28. +18 −16 frontend/Main.cs
  29. +0 −1  frontend/ScriptingContext.cs
  30. +1 −0  test/framework/DebuggerTestFixture.cs
  31. +2 −0  test/src/TestChild.cs
  32. +1 −1  test/src/TestMultiThread.cs
  33. +5 −4 test/testsuite/TestAbort.cs
  34. +1 −2  test/testsuite/TestActivateBreakpoints2.cs
  35. +1 −2  test/testsuite/TestAppDomain-Module.cs
  36. +1 −2  test/testsuite/TestAppDomain.cs
  37. +247 −4 test/testsuite/TestExec.cs
  38. +11 −9 test/testsuite/TestMultiThread.cs
  39. +2 −3 test/testsuite/testnativeexec.cs
  40. +3 −3 test/testsuite/testnativefork.cs
View
54 ChangeLog
@@ -1,3 +1,57 @@
+2009-07-08 Martin Baulig <martin@ximian.com>
+
+ Martin's new Threading Model.
+
+ * classes/GUIManager.cs
+ (GUIManager): Made this obsolete, it's now just a tiny wrapper
+ around the new API.
+
+ * classes/Operation.cs: New file.
+ (ThreadingModel): New public enum.
+ (CommandResult): New public abstract class.
+ (OperationHost): New internal interface.
+ (OperationCommandResult): New public class.
+
+ * backend/ThreadServant.cs
+ (ThreadServant.StepInstruction): Removed, use the new Step() API.
+ (ThreadServant.StepNativeInstruction): Likewise.
+ (ThreadServant.NextInstruction): Likewise.
+ (ThreadServant.StepLine): Likewise.
+ (ThreadServant.NextLine): Likewise.
+ (ThreadServant.Finish): Removed, use the new Step() API.
+
+ * backend/SingleSteppingEngine.cs
+ (SSE.OperationStep): Add support for `StepMode.Run'; this
+ obsoletes `OperationRun'.
+ (SSE.OperationRun): Removed; use `OperationStep' with `StepMode.Run'.
+ (SSE.OperationFinish): Removed; use `OperationStep' with
+ `StepMode.Finish' or `StepMode.FinishNative'.
+
+ * backend/StepFrame.cs: Moved to ../classes/StepFrame.cs.
+
+ * classes/StepFrame.cs
+ (StepMode): Made this public.
+ (StepFrame): Make this public and [Serializable].
+ (StepMode.Run): Added.
+ (StepMode.FinishNative): Added.
+ (StepFrame.Until): New public property; only valid in`
+ StepMode.Run'.
+
+ * classes/Thread.cs
+ (Thread.Step): New public function.
+ (Thread.StepInstruction): Obsolete, use the new Step() API.
+ (Thread.StepNativeInstruction): Likewise.
+ (Thread.NextInstruction): Likewise.
+ (Thread.StepLine): Likewise.
+ (Thread.NextLine): Likewise.
+ (Thread.Continue): Use `Step (StepMode.Run)'.
+ (Thread.Background): Obsolete; this was never implemented and
+ always the same as Continue().
+ (Thread.Finish): Obsolete, use the new Step() API.
+
+ * backend/ThreadServant.cs
+ (ThreadServant.Step): New public function.
+
2009-07-13 Jonathan Chambers <joncham@gmail.com>
* backend/Inferior.cs: Add and handle WINDOWS server type.
View
96 backend/DebuggerServant.cs
@@ -16,7 +16,7 @@
namespace Mono.Debugger.Backend
{
- internal class DebuggerServant : DebuggerMarshalByRefObject, IDisposable
+ internal class DebuggerServant : DebuggerMarshalByRefObject, IOperationHost, IDisposable
{
Debugger client;
DebuggerConfiguration config;
@@ -33,6 +33,7 @@ internal class DebuggerServant : DebuggerMarshalByRefObject, IDisposable
ObjectCache.Initialize ();
thread_manager = new ThreadManager (this);
process_hash = Hashtable.Synchronized (new Hashtable ());
+ stopped_event = new ManualResetEvent (false);
}
public Debugger Client {
@@ -59,6 +60,7 @@ internal void OnModuleUnLoaded (Module module)
internal void OnMainProcessCreatedEvent (ProcessServant process)
{
+ process_hash.Add (process, process);
client.OnMainProcessCreatedEvent (process.Client);
}
@@ -107,6 +109,16 @@ internal void SendTargetEvent (SingleSteppingEngine sse, TargetEventArgs args)
}
}
+ internal void OnEnterNestedBreakState (SingleSteppingEngine sse)
+ {
+ client.OnEnterNestedBreakState (sse.Thread);
+ }
+
+ internal void OnLeaveNestedBreakState (SingleSteppingEngine sse)
+ {
+ client.OnLeaveNestedBreakState (sse.Thread);
+ }
+
public void Kill ()
{
main_process = null;
@@ -140,7 +152,7 @@ public void Detach ()
}
}
- public Process Run (DebuggerSession session)
+ public Process Run (DebuggerSession session, out CommandResult result)
{
check_disposed ();
@@ -148,12 +160,11 @@ public Process Run (DebuggerSession session)
throw new TargetException (TargetError.AlreadyHaveTarget);
ProcessStart start = new ProcessStart (session);
- main_process = thread_manager.StartApplication (start);
- process_hash.Add (main_process, main_process);
+ main_process = thread_manager.StartApplication (start, out result);
return main_process.Client;
}
- public Process Attach (DebuggerSession session, int pid)
+ public Process Attach (DebuggerSession session, int pid, out CommandResult result)
{
check_disposed ();
@@ -161,8 +172,7 @@ public Process Attach (DebuggerSession session, int pid)
throw new TargetException (TargetError.AlreadyHaveTarget);
ProcessStart start = new ProcessStart (session, pid);
- main_process = thread_manager.StartApplication (start);
- process_hash.Add (main_process, main_process);
+ main_process = thread_manager.StartApplication (start, out result);
return main_process.Client;
}
@@ -200,6 +210,78 @@ public void Error (string message, params object[] args)
Console.WriteLine ("ERROR: " + String.Format (message, args));
}
+#region Global Threading Model
+
+ ManualResetEvent stopped_event;
+ OperationCommandResult current_operation;
+
+ internal WaitHandle WaitHandle {
+ get { return stopped_event; }
+ }
+
+ internal CommandResult StartOperation (ThreadingModel model, SingleSteppingEngine caller)
+ {
+ if (!ThreadManager.InBackgroundThread)
+ throw new InternalError ();
+
+ if ((model & ThreadingModel.ThreadingMode) == ThreadingModel.Default) {
+ if (Inferior.HasThreadEvents)
+ model |= ThreadingModel.Single;
+ else
+ model |= ThreadingModel.Process;
+ }
+
+ if ((model & ThreadingModel.ThreadingMode) != ThreadingModel.Global)
+ return caller.Process.StartOperation (model, caller);
+
+ if (current_operation != null)
+ throw new TargetException (TargetError.NotStopped);
+
+ lock (this) {
+ stopped_event.Reset ();
+ current_operation = new OperationCommandResult (this, model);
+ }
+
+ foreach (ProcessServant process in process_hash.Values) {
+ process.StartGlobalOperation (model, caller, current_operation);
+ }
+
+ return current_operation;
+ }
+
+ public void OperationCompleted (SingleSteppingEngine caller, TargetEventArgs result, ThreadingModel model)
+ {
+ if (!ThreadManager.InBackgroundThread)
+ throw new InternalError ();
+
+ foreach (ProcessServant process in process_hash.Values) {
+ process.OperationCompleted (caller, result, model);
+ }
+
+ lock (this) {
+ current_operation = null;
+ stopped_event.Set ();
+ }
+ }
+
+ WaitHandle IOperationHost.WaitHandle {
+ get { return stopped_event; }
+ }
+
+ void IOperationHost.SendResult (SingleSteppingEngine sse, TargetEventArgs args)
+ {
+ SendTargetEvent (sse, args);
+ }
+
+ void IOperationHost.Abort ()
+ {
+ foreach (ProcessServant process in process_hash.Values) {
+ process.Stop ();
+ }
+ }
+
+#endregion
+
//
// IDisposable
//
View
34 backend/Inferior.cs
@@ -65,7 +65,7 @@ internal class Inferior : TargetAccess, ITargetNotification, IDisposable
static extern TargetError mono_debugger_server_initialize_process (IntPtr handle);
[DllImport("monodebuggerserver")]
- static extern TargetError mono_debugger_server_initialize_thread (IntPtr handle, int child_pid);
+ static extern TargetError mono_debugger_server_initialize_thread (IntPtr handle, int child_pid, bool wait);
[DllImport("monodebuggerserver")]
static extern TargetError mono_debugger_server_io_thread_main (IntPtr io_data, ChildOutputHandler output_handler);
@@ -193,6 +193,9 @@ internal class Inferior : TargetAccess, ITargetNotification, IDisposable
static extern TargetError mono_debugger_server_get_callback_frame (IntPtr handle, long stack_pointer, bool exact_match, IntPtr info);
[DllImport("monodebuggerserver")]
+ static extern TargetError mono_debugger_server_restart_notification (IntPtr handle);
+
+ [DllImport("monodebuggerserver")]
static extern void mono_debugger_server_set_runtime_info (IntPtr handle, IntPtr mono_runtime_info);
[DllImport("monodebuggerserver")]
@@ -603,6 +606,11 @@ public void DisableBreakpoint (int breakpoint)
server_handle, breakpoint));
}
+ public void RestartNotification ()
+ {
+ check_error (mono_debugger_server_restart_notification (server_handle));
+ }
+
public ProcessStart ProcessStart {
get {
return start;
@@ -668,7 +676,22 @@ public void InitializeThread (int pid)
initialized = true;
- check_error (mono_debugger_server_initialize_thread (server_handle, pid));
+ check_error (mono_debugger_server_initialize_thread (server_handle, pid, true));
+ this.child_pid = pid;
+
+ SetupInferior ();
+
+ change_target_state (TargetState.Stopped, 0);
+ }
+
+ public void InitializeAfterExec (int pid)
+ {
+ if (initialized)
+ throw new TargetException (TargetError.AlreadyHaveTarget);
+
+ initialized = true;
+
+ check_error (mono_debugger_server_initialize_thread (server_handle, pid, false));
this.child_pid = pid;
SetupInferior ();
@@ -678,7 +701,7 @@ public void InitializeThread (int pid)
public void Attach (int pid)
{
- if (has_target)
+ if (has_target || initialized)
throw new TargetException (TargetError.AlreadyHaveTarget);
has_target = true;
@@ -692,7 +715,9 @@ public void Attach (int pid)
start.SetupApplication (exe_file, cwd, cmdline_args);
- InitializeThread (pid);
+ initialized = true;
+
+ SetupInferior ();
change_target_state (TargetState.Stopped, 0);
}
@@ -732,6 +757,7 @@ public ChildEvent ProcessEvent (int status)
case ChildEventType.CHILD_STOPPED:
case ChildEventType.CHILD_INTERRUPTED:
case ChildEventType.CHILD_HIT_BREAKPOINT:
+ case ChildEventType.CHILD_NOTIFICATION:
change_target_state (TargetState.Stopped);
break;
View
8 backend/MonoThreadManager.cs
@@ -239,18 +239,20 @@ internal void ThreadCreated (SingleSteppingEngine sse)
sse.Inferior.SetRuntimeInfo (mono_runtime_info);
if (!MonoDebuggerInfo.CheckRuntimeVersion (81, 3) && !process.IsAttached) {
if (++index < 3)
- sse.SetDaemon ();
+ sse.Thread.ThreadFlags |= Thread.Flags.Daemon | Thread.Flags.Immutable;
} else {
- sse.SetDaemon ();
+ sse.Thread.ThreadFlags |= Thread.Flags.Daemon | Thread.Flags.Immutable;
}
}
void check_thread_flags (SingleSteppingEngine engine, ThreadFlags flags)
{
if ((flags & (ThreadFlags.Internal | ThreadFlags.ThreadPool)) != ThreadFlags.Internal) {
- engine.SetManaged ();
+ engine.Thread.ThreadFlags &= ~(Thread.Flags.Daemon | Thread.Flags.Immutable);
if (engine != process.MainThread)
process.Debugger.Client.OnManagedThreadCreatedEvent (engine.Thread);
+ } else if ((flags & ThreadFlags.ThreadPool) != 0) {
+ engine.Thread.ThreadFlags &= ~Thread.Flags.Immutable;
}
}
View
261 backend/ProcessServant.cs
@@ -15,7 +15,7 @@
namespace Mono.Debugger.Backend
{
- internal class ProcessServant : DebuggerMarshalByRefObject
+ internal class ProcessServant : DebuggerMarshalByRefObject, IOperationHost
{
Process client;
TargetInfo target_info;
@@ -33,6 +33,8 @@ internal class ProcessServant : DebuggerMarshalByRefObject
protected ThreadServant main_thread;
Hashtable thread_hash;
+ ProcessServant parent;
+
ThreadDB thread_db;
bool is_attached;
@@ -53,6 +55,8 @@ private ProcessServant (ThreadManager manager, DebuggerSession session)
thread_lock_mutex = new DebuggerMutex ("thread_lock_mutex");
+ stopped_event = new ST.ManualResetEvent (false);
+
thread_hash = Hashtable.Synchronized (new Hashtable ());
target_info = Inferior.GetTargetInfo ();
@@ -89,6 +93,8 @@ private ProcessServant (ProcessServant parent, int pid)
this.is_forked = true;
this.initialized = true;
+ this.parent = parent;
+
breakpoint_manager = new BreakpointManager (parent.breakpoint_manager);
exception_handlers = new Dictionary<int,ExceptionCatchPoint> ();
@@ -183,6 +189,10 @@ private ProcessServant (ProcessServant parent, int pid)
get { return start.CommandLineArguments; }
}
+ internal ST.WaitHandle WaitHandle {
+ get { return stopped_event; }
+ }
+
internal void ThreadCreated (Inferior inferior, int pid, bool do_attach, bool resume_thread)
{
Inferior new_inferior = inferior.CreateThread (pid, do_attach);
@@ -198,7 +208,11 @@ internal void ThreadCreated (Inferior inferior, int pid, bool do_attach, bool re
get_thread_info (inferior, new_thread);
OnThreadCreatedEvent (new_thread);
- new_thread.StartThread (resume_thread);
+ if (resume_thread) {
+ CommandResult result = current_operation != null ?
+ current_operation : new ThreadCommandResult (new_thread.Thread);
+ new_thread.StartThread (result);
+ }
}
internal void ChildForked (Inferior inferior, int pid)
@@ -224,7 +238,8 @@ internal void ChildForked (Inferior inferior, int pid)
manager.Debugger.OnProcessCreatedEvent (new_process);
new_process.OnThreadCreatedEvent (new_thread);
- new_thread.StartForkedChild ();
+ CommandResult result = new_process.CloneParentOperation (new_thread);
+ new_thread.StartForkedChild (result);
}
internal void ChildExecd (Inferior inferior)
@@ -248,7 +263,7 @@ internal void ChildExecd (Inferior inferior)
if (breakpoint_manager != null)
breakpoint_manager.Dispose ();
- session = session.Clone (start.Options, "@" + id);
+ session = session.Clone (client, start.Options, "@" + id);
session.OnProcessCreated (client);
breakpoint_manager = new BreakpointManager ();
@@ -261,7 +276,7 @@ internal void ChildExecd (Inferior inferior)
native_language = new NativeLanguage (this, os, target_info);
Inferior new_inferior = Inferior.CreateInferior (manager, this, start);
- new_inferior.InitializeThread (inferior.PID);
+ new_inferior.InitializeAfterExec (inferior.PID);
SingleSteppingEngine new_thread = new SingleSteppingEngine (
manager, this, new_inferior, inferior.PID);
@@ -285,17 +300,20 @@ internal void ChildExecd (Inferior inferior)
manager.Debugger.OnProcessExecdEvent (this);
manager.Debugger.OnThreadCreatedEvent (new_thread.Thread);
initialized = is_forked = false;
+ main_thread = new_thread;
- new_thread.StartApplication ();
+ CommandResult result = CloneParentOperation (new_thread);
+ new_thread.StartExecedChild (result);
}
- internal void StartApplication ()
+ internal CommandResult StartApplication ()
{
SingleSteppingEngine engine = new SingleSteppingEngine (manager, this, start);
initialized = true;
this.main_thread = engine;
+ engine.Thread.ThreadFlags |= Thread.Flags.StopOnExit;
if (thread_hash.Contains (engine.PID))
thread_hash [engine.PID] = engine;
@@ -306,14 +324,23 @@ internal void StartApplication ()
session.OnMainProcessCreated (client);
manager.Debugger.OnMainProcessCreatedEvent (this);
- engine.StartApplication ();
+ CommandResult result = Debugger.StartOperation (start.Session.Config.ThreadingModel, engine);
+ return engine.StartApplication (result);
}
internal void OnProcessExitedEvent ()
{
+ DropGlobalThreadLock ();
+
+ if (current_state == ProcessState.Running) {
+ current_state = ProcessState.Exited;
+ current_operation.Completed ();
+ current_operation = null;
+ stopped_event.Set ();
+ }
+
if (!is_forked)
session.OnProcessExited (client);
- client.OnProcessExited ();
session.MainThreadGroup.RemoveThread (main_thread.ID);
manager.Debugger.OnProcessExitedEvent (this);
}
@@ -641,10 +668,203 @@ internal void DropGlobalThreadLock ()
if (thread_hash.Count != 0)
throw new InternalError ();
- has_thread_lock = false;
- thread_lock_mutex.Unlock ();
+ if (has_thread_lock) {
+ has_thread_lock = false;
+ thread_lock_mutex.Unlock ();
+ }
+ }
+
+#region User Threads
+
+ internal enum ProcessState
+ {
+ SingleThreaded,
+ Running,
+ Stopping,
+ Stopped,
+ Exited
+ }
+
+ protected ST.ManualResetEvent stopped_event;
+
+ ProcessState current_state = ProcessState.Stopped;
+ OperationCommandResult current_operation = null;
+
+ public void OperationCompleted (SingleSteppingEngine caller, TargetEventArgs result, ThreadingModel model)
+ {
+ if (!ThreadManager.InBackgroundThread)
+ throw new InternalError ();
+
+ if (current_state == ProcessState.Stopping)
+ return;
+ else if (current_state != ProcessState.Running)
+ throw new InternalError ();
+
+ if ((result != null) && (caller != main_thread) &&
+ ((result.Type == TargetEventType.TargetExited) || (result.Type == TargetEventType.TargetSignaled)))
+ return;
+
+ current_state = ProcessState.Stopping;
+ SuspendUserThreads (model, caller);
+
+ lock (this) {
+ current_state = ProcessState.Stopped;
+ current_operation.Completed ();
+ current_operation = null;
+ stopped_event.Set ();
+ }
+ }
+
+ protected void SuspendUserThreads (ThreadingModel model, SingleSteppingEngine caller)
+ {
+ Report.Debug (DebugFlags.Threads,
+ "Suspending user threads: {0} {1}", model, caller);
+
+ foreach (SingleSteppingEngine engine in thread_hash.Values) {
+ Report.Debug (DebugFlags.Threads, " check user thread: {0} {1}",
+ engine, engine.Thread.ThreadFlags);
+ if (engine == caller)
+ continue;
+ if (((engine.Thread.ThreadFlags & Thread.Flags.Immutable) != 0) &&
+ ((model & ThreadingModel.StopImmutableThreads) == 0))
+ continue;
+ if (((engine.Thread.ThreadFlags & Thread.Flags.Daemon) != 0) &&
+ ((model & ThreadingModel.StopDaemonThreads) == 0))
+ continue;
+ engine.SuspendUserThread ();
+ }
+
+ Report.Debug (DebugFlags.Threads,
+ "Done suspending user threads: {0} {1}", model, caller);
+ }
+
+ protected void ResumeUserThreads (ThreadingModel model, SingleSteppingEngine caller)
+ {
+ Report.Debug (DebugFlags.Threads,
+ "Resuming user threads: {0}", caller);
+
+ foreach (SingleSteppingEngine engine in thread_hash.Values) {
+ if (engine == caller)
+ continue;
+ if ((engine.Thread.ThreadFlags & Thread.Flags.AutoRun) == 0)
+ continue;
+ if (((engine.Thread.ThreadFlags & Thread.Flags.Immutable) != 0) &&
+ ((model & ThreadingModel.StopImmutableThreads) == 0))
+ continue;
+ if (((engine.Thread.ThreadFlags & Thread.Flags.Daemon) != 0) &&
+ ((model & ThreadingModel.StopDaemonThreads) == 0))
+ continue;
+
+ CommandResult result;
+ if (current_operation != null)
+ result = current_operation;
+ else
+ result = new ThreadCommandResult (engine.Thread);
+
+ engine.ResumeUserThread (result);
+ }
+
+ Report.Debug (DebugFlags.Threads,
+ "Resumed user threads: {0}", caller);
}
+ internal CommandResult StartOperation (ThreadingModel model, SingleSteppingEngine caller)
+ {
+ if (!ThreadManager.InBackgroundThread)
+ throw new InternalError ();
+
+ if ((current_state != ProcessState.Stopped) && (current_state != ProcessState.SingleThreaded))
+ throw new TargetException (TargetError.NotStopped);
+
+ if ((model & ThreadingModel.ThreadingMode) == ThreadingModel.Single) {
+ current_state = ProcessState.SingleThreaded;
+ if ((model & ThreadingModel.ResumeThreads) != 0)
+ ResumeUserThreads (model, caller);
+ return new ThreadCommandResult (caller.Thread);
+ } else if ((model & ThreadingModel.ThreadingMode) != ThreadingModel.Process) {
+ throw new ArgumentException ();
+ }
+
+ lock (this) {
+ current_state = ProcessState.Running;
+ stopped_event.Reset ();
+ current_operation = new OperationCommandResult (this, model);
+ }
+
+ ResumeUserThreads (model, caller);
+ return current_operation;
+ }
+
+ internal void StartGlobalOperation (ThreadingModel model, SingleSteppingEngine caller, OperationCommandResult operation)
+ {
+ if (!ThreadManager.InBackgroundThread)
+ throw new InternalError ();
+
+ if ((current_state != ProcessState.Stopped) && (current_state != ProcessState.SingleThreaded))
+ throw new TargetException (TargetError.NotStopped);
+
+ lock (this) {
+ current_state = ProcessState.Running;
+ stopped_event.Reset ();
+ current_operation = operation;
+ }
+
+ ResumeUserThreads (model, caller);
+ }
+
+ protected CommandResult CloneParentOperation (SingleSteppingEngine new_thread)
+ {
+ if (parent.current_state == ProcessState.SingleThreaded) {
+ current_state = ProcessState.SingleThreaded;
+ return new ThreadCommandResult (new_thread.Thread);
+ }
+
+ if (parent.current_state != ProcessState.Running)
+ throw new InternalError ();
+
+ current_state = ProcessState.Running;
+ if ((parent.current_operation.ThreadingModel & ThreadingModel.ThreadingMode) == ThreadingModel.Global)
+ current_operation = parent.current_operation;
+ else if ((parent.current_operation.ThreadingModel & ThreadingModel.ThreadingMode) == ThreadingModel.Process)
+ current_operation = new OperationCommandResult (this, parent.current_operation.ThreadingModel);
+ else
+ throw new InternalError ();
+
+ return current_operation;
+ }
+
+ internal void Stop ()
+ {
+ main_thread.Invoke (delegate {
+ current_state = ProcessState.Stopping;
+
+ SuspendUserThreads (ThreadingModel.Process, null);
+ current_state = ProcessState.Stopped;
+ if (current_operation != null) {
+ current_operation.Completed ();
+ current_operation = null;
+ }
+ stopped_event.Set ();
+ return null;
+ }, null);
+ }
+
+ ST.WaitHandle IOperationHost.WaitHandle {
+ get { return stopped_event; }
+ }
+
+ void IOperationHost.SendResult (SingleSteppingEngine sse, TargetEventArgs args)
+ {
+ Debugger.SendTargetEvent (sse, args);
+ }
+
+ void IOperationHost.Abort ()
+ {
+ Stop ();
+ }
+
+#endregion
+
public void ActivatePendingBreakpoints (CommandResult result)
{
((SingleSteppingEngine) main_thread).ManagedCallback (
@@ -675,25 +895,6 @@ internal void RemoveExceptionCatchPoint (int index)
}
//
- // Stopping / resuming all threads for the GUI
- //
-
- internal void OnTargetEvent (SingleSteppingEngine sse, TargetEventArgs args)
- {
- client.OnTargetEvent (sse, args);
- }
-
- internal void OnEnterNestedBreakState (SingleSteppingEngine sse)
- {
- client.OnEnterNestedBreakState (sse);
- }
-
- internal void OnLeaveNestedBreakState (SingleSteppingEngine sse)
- {
- client.OnLeaveNestedBreakState (sse);
- }
-
- //
// IDisposable
//
View
919 backend/SingleSteppingEngine.cs
@@ -109,32 +109,38 @@ protected SingleSteppingEngine (ThreadManager manager, ProcessServant process)
this.inferior = inferior;
this.pid = pid;
+ engine_stopped = true;
manager.AddEngine (this);
}
- public CommandResult StartApplication ()
+ public CommandResult StartApplication (CommandResult result)
{
- CommandResult result = new ThreadCommandResult (thread);
+ engine_stopped = false;
current_operation = new OperationStart (this, result);
current_operation.Execute ();
return result;
}
- public CommandResult StartThread (bool resume_thread)
+ public CommandResult StartExecedChild (CommandResult result)
{
- CommandResult result = new ThreadCommandResult (thread);
- if (resume_thread)
- current_operation = new OperationRun (this, result);
- else
- current_operation = new OperationInitialize (this, result);
+ engine_stopped = false;
+ current_operation = new OperationStart (this, result);
current_operation.Execute ();
return result;
}
- public CommandResult StartForkedChild ()
+ public CommandResult StartThread (CommandResult result)
{
- CommandResult result = new ThreadCommandResult (thread);
- current_operation = new OperationRun (this, result);
+ engine_stopped = false;
+ current_operation = new OperationStep (this, StepMode.Run, result);
+ current_operation.Execute ();
+ return current_operation.Result;
+ }
+
+ public CommandResult StartForkedChild (CommandResult result)
+ {
+ engine_stopped = false;
+ current_operation = new OperationStep (this, StepMode.Run, result);
PushOperation (new OperationInitAfterFork (this));
return result;
}
@@ -160,7 +166,7 @@ public void ProcessEvent (int status)
ProcessEvent (inferior.ProcessEvent (status));
}
- public void ProcessEvent (Inferior.ChildEvent cevent)
+ public bool ProcessEvent (Inferior.ChildEvent cevent)
{
Report.Debug (DebugFlags.EventLoop, "{0} received event {1}",
this, cevent);
@@ -168,39 +174,48 @@ public void ProcessEvent (Inferior.ChildEvent cevent)
if (killed) {
if (cevent.Type == Inferior.ChildEventType.CHILD_INTERRUPTED) {
inferior.Continue ();
- return;
+ return true;
} else if (cevent.Type != Inferior.ChildEventType.CHILD_EXITED) {
Report.Debug (DebugFlags.EventLoop,
"{0} received event {1} when already killed",
this, cevent);
- return;
+ return true;
}
}
- if (HasThreadLock) {
- Report.Debug (DebugFlags.EventLoop,
- "{0} received event {1} at {3} while being thread-locked ({2})",
- this, cevent, thread_lock, inferior.CurrentFrame);
- thread_lock.SetStopEvent (cevent);
- return;
- } else if (cevent.Type == Inferior.ChildEventType.CHILD_NOTIFICATION) {
- Report.Debug (DebugFlags.Notification,
- "{0} received event {1} {2}",
- this, cevent, (NotificationType) cevent.Argument);
- } else if ((cevent.Type == Inferior.ChildEventType.CHILD_EXITED) ||
- (cevent.Type == Inferior.ChildEventType.CHILD_SIGNALED)) {
- Report.Debug (DebugFlags.SSE, "{0} is now dead: {1}", this, cevent);
+ if ((cevent.Type == Inferior.ChildEventType.CHILD_EXITED) ||
+ (cevent.Type == Inferior.ChildEventType.CHILD_SIGNALED)) {
+ Report.Debug (DebugFlags.SSE, "{0} received {1} while running {2}",
+ this, cevent, current_operation);
+ // we can't remove the breakpoint anymore after
+ // the target exited, but we need to clear this id.
+ temp_breakpoint = null;
dead = true;
} else {
+ string frame_text = "";
Inferior.StackFrame iframe = inferior.GetCurrentFrame (true);
if (iframe != null)
- Report.Debug (DebugFlags.EventLoop,
- "{0} received event {1} at {2} while running {3}",
- this, cevent, iframe.Address, current_operation);
+ frame_text = " at " + iframe.Address.ToString ();
+
+ string running_text;
+ if (HasThreadLock)
+ running_text = String.Format ("being thread-locked ({0})", thread_lock);
else
- Report.Debug (DebugFlags.EventLoop,
- "{0} received event {1} while running {2}",
- this, cevent, current_operation);
+ running_text = String.Format ("running {0}", current_operation);
+
+ string event_text;
+ if (cevent.Type == Inferior.ChildEventType.CHILD_NOTIFICATION)
+ event_text = String.Format ("notification {0} ({1})", cevent, (NotificationType) cevent.Argument);
+ else
+ event_text = "event " + cevent.ToString ();
+
+ Report.Debug (DebugFlags.EventLoop, "{0} received {1}{2} while {3}",
+ this, event_text, frame_text, running_text);
+
+ if (HasThreadLock) {
+ thread_lock.SetStopEvent (cevent);
+ return false;
+ }
}
if (ProcessServant.IsAttached && !attach_initialized) {
@@ -210,41 +225,100 @@ public void ProcessEvent (Inferior.ChildEvent cevent)
cevent = new Inferior.ChildEvent (Inferior.ChildEventType.CHILD_STOPPED, 0, 0, 0);
}
- if (cevent.Type == Inferior.ChildEventType.CHILD_INTERRUPTED) {
+ bool resume_target;
+ if (manager.HandleChildEvent (this, inferior, ref cevent, out resume_target)) {
+ Report.Debug (DebugFlags.EventLoop,
+ "{0} done handling event: {1}{2}{3}{4}",
+ this, cevent, resume_target ? " resume-target" : "" ,
+ stop_requested ? " stop-requested" : "",
+ HasThreadLock ? " thread-lock" : "");
+ if (stop_requested) {
+ OperationInterrupted ();
+ } else if (resume_target) {
+ if (!current_operation.ResumeOperation ())
+ inferior.Continue ();
+ }
+ return true;
+ }
+
+ Inferior.ChildEventType message = cevent.Type;
+ int arg = (int) cevent.Argument;
+
+ switch (message) {
+ case Inferior.ChildEventType.CHILD_INTERRUPTED:
+ OperationInterrupted ();
+ return true;
+ case Inferior.ChildEventType.CHILD_SIGNALED:
+ if (killed)
+ OperationCompleted (new TargetEventArgs (TargetEventType.TargetExited, 0));
+ else
+ OperationCompleted (new TargetEventArgs (TargetEventType.TargetSignaled, arg));
+ return true;
+
+ case Inferior.ChildEventType.CHILD_EXITED:
+ OperationCompleted (new TargetEventArgs (TargetEventType.TargetExited, arg));
+ return true;
+
+ case Inferior.ChildEventType.CHILD_CALLBACK_COMPLETED:
frame_changed (inferior.CurrentFrame, null);
+ OperationCompleted (new TargetEventArgs (TargetEventType.TargetStopped, 0, current_frame));
+ return true;
- long abort_rti = -1;
- lock (this) {
- abort_rti = abort_requested;
- abort_requested = -1;
- }
- Report.Debug (DebugFlags.SSE, "{0} interrupted: {1} - {2}", this, abort_rti, current_frame);
- if (abort_rti >= 0) {
- DoAbortInvocation (abort_rti);
- } else {
- OperationCompleted (new TargetEventArgs (TargetEventType.TargetInterrupted, 0, current_frame));
+ case Inferior.ChildEventType.RUNTIME_INVOKE_DONE:
+ OperationRuntimeInvoke rti = rti_stack.Pop ();
+ if (rti.ID != cevent.Argument)
+ throw new InternalError ("{0} got unknown RUNTIME_INVOKE_DONE: {1} {2}", this, rti.ID, cevent);
+
+ frame_changed (inferior.CurrentFrame, null);
+ rti.Completed (cevent.Data1, cevent.Data2);
+
+ if (rti.IsSuspended) {
+ InterruptibleOperation io = nested_break_stack.Pop ();
+ if (io != rti)
+ throw new InternalError ("{0} unexpected item on nested break state stack: {1}", this, io);
+ process.Debugger.OnLeaveNestedBreakState (this);
}
- return;
+
+ if (current_operation != rti)
+ current_operation.Result.Completed ();
+ current_operation = rti;
+
+ TargetEventArgs args = rti.OperationCompleted (current_frame, false);
+ OperationCompleted (args);
+ return true;
}
- bool resume_target;
- if (manager.HandleChildEvent (this, inferior, ref cevent, out resume_target)) {
- Report.Debug (DebugFlags.EventLoop,
- "{0} done handling event: {1} {2} {3}",
- this, cevent, resume_target, HasThreadLock);
- if (!resume_target)
- return;
- if ((current_operation != null) && current_operation.ResumeOperation ())
- return;
- inferior.Continue ();
- return;
+ if (stop_requested) {
+ switch (message) {
+ case Inferior.ChildEventType.CHILD_STOPPED:
+ case Inferior.ChildEventType.CHILD_CALLBACK:
+ case Inferior.ChildEventType.CHILD_HIT_BREAKPOINT:
+ OperationInterrupted ();
+ return true;
+
+ case Inferior.ChildEventType.UNHANDLED_EXCEPTION:
+ case Inferior.ChildEventType.THROW_EXCEPTION:
+ case Inferior.ChildEventType.HANDLE_EXCEPTION:
+ case Inferior.ChildEventType.CHILD_NOTIFICATION:
+ inferior.RestartNotification ();
+ OperationInterrupted ();
+ return true;
+
+ default:
+ OperationInterrupted ();
+ return false;
+ }
}
+ DoProcessEvent (cevent);
+ return true;
+ }
+
+ protected void DoProcessEvent (Inferior.ChildEvent cevent)
+ {
Inferior.ChildEventType message = cevent.Type;
int arg = (int) cevent.Argument;
- TargetEventArgs result = null;
-
if (message == Inferior.ChildEventType.THROW_EXCEPTION) {
TargetAddress info = new TargetAddress (inferior.AddressDomain, cevent.Data1);
TargetAddress ip = new TargetAddress (manager.AddressDomain, cevent.Data2);
@@ -341,49 +415,35 @@ public void ProcessEvent (Inferior.ChildEvent cevent)
// the target is to remain stopped. Note that this piece of code
// here only deals with the temporary breakpoint, the handling of
// a signal or another breakpoint is done later.
- if (temp_breakpoint != null) {
- if ((message == Inferior.ChildEventType.CHILD_EXITED) ||
- (message == Inferior.ChildEventType.CHILD_SIGNALED))
- // we can't remove the breakpoint anymore after
- // the target exited, but we need to clear this id.
- temp_breakpoint = null;
- else if ((message == Inferior.ChildEventType.CHILD_HIT_BREAKPOINT) &&
- (arg == temp_breakpoint.ID)) {
- // we hit the temporary breakpoint; this'll always
- // happen in the `correct' thread since the
- // `temp_breakpoint_id' is only set in this
- // SingleSteppingEngine and not in any other thread's.
-
- remove_temporary_breakpoint ();
-
- Breakpoint bpt = lookup_breakpoint (arg);
- Report.Debug (DebugFlags.SSE,
- "{0} hit temporary breakpoint {1} at {2} {3}",
- this, arg, inferior.CurrentFrame, bpt);
- if ((bpt == null) || !bpt.Breaks (thread.ID) || bpt.HideFromUser) {
- message = Inferior.ChildEventType.CHILD_STOPPED;
- arg = 0;
- cevent = new Inferior.ChildEvent (
- Inferior.ChildEventType.CHILD_STOPPED, 0, 0, 0);
- } else {
- ProcessOperationEvent (cevent);
- return;
- }
+ if ((temp_breakpoint != null) &&
+ (message == Inferior.ChildEventType.CHILD_HIT_BREAKPOINT) && (arg == temp_breakpoint.ID)) {
+ // we hit the temporary breakpoint; this'll always
+ // happen in the `correct' thread since the
+ // `temp_breakpoint_id' is only set in this
+ // SingleSteppingEngine and not in any other thread's.
+
+ remove_temporary_breakpoint ();
+
+ Breakpoint bpt = lookup_breakpoint (arg);
+ Report.Debug (DebugFlags.SSE,
+ "{0} hit temporary breakpoint {1} at {2} {3}",
+ this, arg, inferior.CurrentFrame, bpt);
+ if ((bpt == null) || !bpt.Breaks (thread.ID) || bpt.HideFromUser) {
+ message = Inferior.ChildEventType.CHILD_STOPPED;
+ arg = 0;
+ cevent = new Inferior.ChildEvent (Inferior.ChildEventType.CHILD_STOPPED, 0, 0, 0);
+ } else {
+ ProcessOperationEvent (cevent);
+ return;
}
}
- switch (message) {
- case Inferior.ChildEventType.CHILD_STOPPED:
- break;
-
- case Inferior.ChildEventType.UNHANDLED_EXCEPTION: {
+ if (message == Inferior.ChildEventType.UNHANDLED_EXCEPTION) {
TargetAddress exc = new TargetAddress (manager.AddressDomain, cevent.Data1);
TargetAddress ip = new TargetAddress (manager.AddressDomain, cevent.Data2);
PushOperation (new OperationException (this, ip, exc, true));
return;
- }
-
- case Inferior.ChildEventType.CHILD_HIT_BREAKPOINT: {
+ } else if (message == Inferior.ChildEventType.CHILD_HIT_BREAKPOINT) {
// Ok, the next thing we need to check is whether this is actually "our"
// breakpoint or whether it belongs to another thread. In this case,
// `step_over_breakpoint' does everything for us and we can just continue
@@ -394,49 +454,6 @@ public void ProcessEvent (Inferior.ChildEvent cevent)
do_continue ();
return;
}
- break;
- }
-
- case Inferior.ChildEventType.CHILD_SIGNALED:
- if (killed)
- OperationCompleted (new TargetEventArgs (TargetEventType.TargetExited, 0));
- else
- OperationCompleted (new TargetEventArgs (TargetEventType.TargetSignaled, arg));
- return;
-
- case Inferior.ChildEventType.CHILD_EXITED:
- OperationCompleted (new TargetEventArgs (TargetEventType.TargetExited, arg));
- return;
-
- case Inferior.ChildEventType.CHILD_CALLBACK_COMPLETED:
- frame_changed (inferior.CurrentFrame, null);
- OperationCompleted (new TargetEventArgs (TargetEventType.TargetStopped, 0, current_frame));
- return;
-
- case Inferior.ChildEventType.RUNTIME_INVOKE_DONE:
- OperationRuntimeInvoke rti = rti_stack.Pop ();
- if (rti.ID != cevent.Argument)
- throw new InternalError ("{0} got unknown RUNTIME_INVOKE_DONE: {1} {2}", this, rti.ID, cevent);
-
- frame_changed (inferior.CurrentFrame, null);
- rti.Completed (cevent.Data1, cevent.Data2);
-
- if (rti.IsSuspended) {
- InterruptibleOperation io = nested_break_stack.Pop ();
- if (io != rti)
- throw new InternalError ("{0} unexpected item on nested break state stack: {1}", this, io);
- process.OnLeaveNestedBreakState (this);
- }
-
- if (current_operation != rti)
- current_operation.CompletedOperation ();
- current_operation = rti;
-
- TargetEventArgs args = null;
- if ((rti.Flags & RuntimeInvokeFlags.SendEventOnCompletion) != 0)
- args = new TargetEventArgs (TargetEventType.RuntimeInvokeDone, rti.Result, current_frame);
- OperationCompleted (args);
- return;
}
ProcessOperationEvent (cevent);
@@ -462,6 +479,8 @@ protected void ProcessOperationEvent (Inferior.ChildEvent cevent)
if (current_operation == null)
throw new InternalError ("SSE {0} has no current operation, but received event {1}", this, cevent);
+ Report.Debug (DebugFlags.EventLoop, "{0} process operation event: {1} {2}", this, current_operation, cevent);
+
Operation.EventResult status = current_operation.ProcessEvent (cevent, out result);
Report.Debug (DebugFlags.EventLoop, "{0} processed operation event: {1} {2} {3} {4}", this,
@@ -487,7 +506,7 @@ protected void ProcessOperationEvent (Inferior.ChildEvent cevent)
}
case Operation.EventResult.CompletedCallback:
- OperationCompleted (null);
+ OperationCompleted (result);
return;
case Operation.EventResult.ResumeOperation:
@@ -512,53 +531,77 @@ bool check_runtime_version (int major, int minor)
#endregion
- void AbortRuntimeInvoke (long rti_id)
+ void OperationInterrupted ()
+ {
+ frame_changed (inferior.CurrentFrame, null);
+
+ long abort_rti = -1;
+ lock (this) {
+ abort_rti = abort_requested;
+ abort_requested = -1;
+ }
+ Report.Debug (DebugFlags.SSE, "{0} operation interrupted: {1} - {2}", this, abort_rti, current_frame);
+ if (abort_rti >= 0) {
+ DoAbortInvocation (abort_rti);
+ } else {
+ if (stop_requested)
+ OperationCompleted (null);
+ else
+ OperationCompleted (new TargetEventArgs (TargetEventType.TargetInterrupted, 0, current_frame));
+ }
+ }
+
+ OperationRuntimeInvoke AbortRuntimeInvoke (long rti_id)
{
OperationRuntimeInvoke rti = rti_stack.Pop ();
if (rti.ID != rti_id)
throw new InternalError ("{0} aborting rti failed: {1} {2}", this, rti.ID, rti_id);
- inferior.AbortInvoke (rti_id);
+ rti.AbortInvoke ();
if (rti.IsSuspended) {
InterruptibleOperation io = nested_break_stack.Pop ();
if (io != rti)
throw new InternalError ("{0} aborting rti failed: {1}", this, io);
- process.OnLeaveNestedBreakState (this);
+ process.Debugger.OnLeaveNestedBreakState (this);
}
+
+ return rti;
}
- void OperationCompleted (TargetEventArgs result)
+ void OperationCompleted (TargetEventArgs args)
{
- OperationCompleted (result, false);
+ OperationCompleted (args, false);
}
- void OperationCompleted (TargetEventArgs result, bool suspended)
+ void OperationCompleted (TargetEventArgs args, bool suspended)
{
lock (this) {
remove_temporary_breakpoint ();
engine_stopped = true;
- last_target_event = result;
+ stop_requested = false;
+ last_target_event = args;
+
+ OperationCommandResult result = current_operation.Result as OperationCommandResult;
+
+ Report.Debug (DebugFlags.EventLoop, "{0} {1} operation {2}: {3} {4}",
+ this, suspended ? "suspending" : "terminating", current_operation,
+ result != null, args);
+
+ if (result != null)
+ result.Completed (this, args);
+
operation_completed_event.Set ();
- Report.Debug (DebugFlags.EventLoop, "{0} {1} operation {2}: {3}",
- this, suspended ? "suspending" : "terminating", current_operation, result);
if (suspended) {
- if (result != null)
- process.OnTargetEvent (this, result);
- process.OnEnterNestedBreakState (this);
+ process.Debugger.OnEnterNestedBreakState (this);
((InterruptibleOperation) current_operation).IsSuspended = true;
nested_break_stack.Push ((InterruptibleOperation) current_operation);
+ current_operation.CompletedOperation (true);
current_operation = null;
} else {
- if (result != null)
- process.OnTargetEvent (this, result);
- if (current_operation != null) {
- Report.Debug (DebugFlags.EventLoop, "{0} setting completed: {1} {2}",
- this, current_operation, current_operation.Result);
- current_operation.CompletedOperation ();
- current_operation = null;
- }
+ current_operation.CompletedOperation (false);
+ current_operation = null;
}
}
}
@@ -608,7 +651,12 @@ internal void OnThreadExited (Inferior.ChildEvent cevent)
else
result = new TargetEventArgs (TargetEventType.TargetExited, arg);
temp_breakpoint = null;
- OperationCompleted (result);
+ dead = true;
+
+ if (current_operation != null)
+ OperationCompleted (result);
+ else
+ process.Debugger.SendTargetEvent (this, result);
process.OnThreadExitedEvent (this);
Dispose ();
@@ -657,6 +705,9 @@ void set_registers (Registers registers)
void StartOperation ()
{
lock (this) {
+ Report.Debug (DebugFlags.SSE, "{0} start operation: {1} {2}",
+ this, engine_stopped, HasThreadLock);
+
if (!engine_stopped || HasThreadLock) {
Report.Debug (DebugFlags.Wait, "{0} not stopped: {1} {2}",
this, engine_stopped, HasThreadLock);
@@ -855,9 +906,14 @@ public override void Kill ()
killed = true;
SendCommand (delegate {
Inferior.ChildEvent stop_event;
- if (!engine_stopped)
- inferior.Stop (out stop_event);
+ Report.Debug (DebugFlags.SSE, "{0} kill: {1}", this, engine_stopped);
+ if (!engine_stopped) {
+ bool stopped = inferior.Stop (out stop_event);
+ Report.Debug (DebugFlags.SSE, "{0} kill #1: {1} {2} {3}",
+ this, engine_stopped, stopped, stop_event);
+ }
inferior.Kill ();
+ Report.Debug (DebugFlags.SSE, "{0} kill #2", this);
return null;
});
}
@@ -909,7 +965,12 @@ internal override void DetachThread ()
inferior = null;
}
- OperationCompleted (new TargetEventArgs (TargetEventType.TargetExited, 0));
+ TargetEventArgs result = new TargetEventArgs (TargetEventType.TargetExited, 0);
+ if (current_operation != null)
+ OperationCompleted (result);
+ else
+ process.Debugger.SendTargetEvent (this, result);
+
process.OnThreadExitedEvent (this);
Dispose ();
}
@@ -925,10 +986,7 @@ public override void Stop ()
bool stopped = inferior.Stop ();
if (!Inferior.HasThreadEvents && !stopped)
- {
- ProcessEvent (new Inferior.ChildEvent (Inferior.ChildEventType.CHILD_INTERRUPTED, 0, 0, 0));
- engine_stopped = true;
- }
+ OperationInterrupted ();
Report.Debug (DebugFlags.EventLoop, "{0} interrupt #1: {1}",
this, stopped);
@@ -1132,7 +1190,7 @@ Operation frame_changed (TargetAddress address, Operation operation)
registers = inferior.GetRegisters ();
if ((operation != null) && !main_retaddr.IsNull && (iframe.StackPointer >= main_retaddr))
- return new OperationRun (this, false, operation.Result);
+ return new OperationStep (this, StepMode.Run, operation.Result);
// Compute the current stack frame.
if ((current_method != null) && current_method.HasLineNumbers) {
@@ -1223,23 +1281,26 @@ Operation frame_changed (TargetAddress address, Operation operation)
// happens when returning from a method call; in this
// case, we need to continue stepping until we reach the
// next source line.
- return new OperationStep (this, new StepFrame (
- address - source.LineOffset, address + source.LineRange,
- null, language, StepMode.SourceLine), operation.Result);
+ StepFrame sframe = new StepFrame (
+ language, StepMode.SourceLine, null,
+ address - source.LineOffset, address + source.LineRange);
+ return new OperationStep (this, sframe, operation.Result);
}
LineNumberTable lnt = method.LineNumberTable;
if (lnt.HasMethodBounds && (address < lnt.MethodStartAddress)) {
- return new OperationStep (this, new StepFrame (
- method.StartAddress, lnt.MethodStartAddress, null,
- null, StepMode.Finish), operation.Result);
+ StepFrame sframe = new StepFrame (
+ null, StepMode.Finish, null,
+ method.StartAddress, lnt.MethodStartAddress);
+ return new OperationStep (this, sframe, operation.Result);
} else if (method.HasMethodBounds && (address < method.MethodStartAddress)) {
// Do not stop inside a method's prologue code, but stop
// immediately behind it (on the first instruction of the
// method's actual code).
- return new OperationStep (this, new StepFrame (
- method.StartAddress, method.MethodStartAddress, null,
- null, StepMode.Finish), operation.Result);
+ StepFrame sframe = new StepFrame (
+ null, StepMode.Finish, null,
+ method.StartAddress, method.MethodStartAddress);
+ return new OperationStep (this, sframe, operation.Result);
}
return null;
@@ -1454,7 +1515,7 @@ StepFrame CreateStepFrame ()
TargetAddress start = frame.TargetAddress - offset;
TargetAddress end = frame.TargetAddress + range;
- return new StepFrame (start, end, frame, language, StepMode.StepFrame);
+ return new StepFrame (language, StepMode.StepFrame, frame, start, end);
}
// <summary>
@@ -1510,10 +1571,16 @@ void restore_stack (StackData stack)
// </summary>
internal override void AcquireThreadLock ()
{
+ if (HasThreadLock)
+ throw new InternalError ("Recursive thread lock");
+
Report.Debug (DebugFlags.Threads,
"{0} acquiring thread lock: {1} {2}",
this, engine_stopped, current_operation);
+ if (engine_stopped)
+ return;
+
Inferior.ChildEvent stop_event;
bool stopped = inferior.Stop (out stop_event);
thread_lock = new ThreadLockData (stopped, stop_event, true);
@@ -1536,6 +1603,9 @@ internal override void AcquireThreadLock ()
if (!EndStackAddress.IsNull)
inferior.WriteAddress (EndStackAddress, new_rsp);
+
+ frame_changed (inferior.CurrentFrame, null);
+ engine_stopped = true;
}
internal override void ReleaseThreadLock ()
@@ -1553,6 +1623,8 @@ internal override void ReleaseThreadLock ()
thread_lock.PopRegisters (inferior);
if (thread_lock.StopEvent != null)
manager.AddPendingEvent (this, thread_lock.StopEvent);
+ if (thread_lock.Stopped)
+ engine_stopped = false;
thread_lock = null;
}
@@ -1582,6 +1654,69 @@ internal void ReleaseThreadLock (Inferior.ChildEvent cevent)
ProcessEvent (cevent);
}
+ internal override void SuspendUserThread ()
+ {
+ if (!ThreadManager.InBackgroundThread)
+ throw new InternalError ();
+ if (HasThreadLock)
+ throw new InternalError ("Recursive thread lock");
+
+ Report.Debug (DebugFlags.Threads,
+ "{0} suspend user thread: {1} {2}",
+ this, engine_stopped, current_operation);
+
+ if (engine_stopped)
+ return;
+
+ Inferior.ChildEvent stop_event;
+ bool stopped = inferior.Stop (out stop_event);
+
+ stop_requested = true;
+
+ if (stop_event != null) {
+ if (ProcessEvent (stop_event))
+ stop_event = null;
+ } else {
+ OperationInterrupted ();
+ }
+
+ if (stop_event != null)
+ thread_lock = new ThreadLockData (stopped, stop_event, false);
+
+ Report.Debug (DebugFlags.Threads,
+ "{0} suspend user thread done: {1} {2} {3}",
+ this, stopped, stop_event, current_operation);
+
+ }
+
+ internal override void ResumeUserThread (CommandResult result)
+ {
+ if (!ThreadManager.InBackgroundThread)
+ throw new InternalError ();
+
+ Report.Debug (DebugFlags.Threads,
+ "{0} resume user thread: {1} {2} {3}", this, engine_stopped,
+ HasThreadLock, thread.ThreadFlags);
+
+ if (thread_lock != null) {
+ if (thread_lock.PushedRegisters || (thread_lock.StopEvent == null))
+ throw new InternalError ();
+
+ manager.AddPendingEvent (this, thread_lock.StopEvent);
+
+ thread_lock = null;
+ engine_stopped = false;
+
+ current_operation = new OperationStep (this, StepMode.Run, result);
+ return;
+ }
+
+ if (!engine_stopped)
+ return;
+
+ StartOperation (new OperationStep (this, StepMode.Run, result));
+ }
+
internal bool OnModuleLoaded (Module module)
{
return ActivatePendingBreakpoints (module);
@@ -1630,7 +1765,7 @@ internal bool ActivatePendingBreakpoints (Module module)
update_current_frame (main_frame);
}
- Report.Debug (DebugFlags.SSE, "{0} activate pending breakpoints", this);
+ Report.Debug (DebugFlags.SSE, "{0} activate pending breakpoints: {1}", this, process.Session.Events.Length);
Queue pending = new Queue ();
foreach (Event e in process.Session.Events) {
@@ -1682,44 +1817,22 @@ public override string ToString ()
#region SSE Commands
- public override void StepInstruction (CommandResult result)
+ internal override ThreadCommandResult Old_Step (StepMode mode, StepFrame frame)
{
- StartOperation (new OperationStep (this, StepMode.SingleInstruction, result));
- }
-
- public override void StepNativeInstruction (CommandResult result)
- {
- StartOperation (new OperationStep (this, StepMode.NativeInstruction, result));
- }
-
- public override void NextInstruction (CommandResult result)
- {
- StartOperation (new OperationStep (this, StepMode.NextInstruction, result));
- }
-
- public override void StepLine (CommandResult result)
- {
- StartOperation (new OperationStep (this, StepMode.SourceLine, result));
- }
-
- public override void NextLine (CommandResult result)
- {
- StartOperation (new OperationStep (this, StepMode.NextLine, result));
- }
-
- public override void Finish (bool native, CommandResult result)
- {
- StartOperation (new OperationFinish (this, native, result));
+ ThreadCommandResult result = new ThreadCommandResult (thread);
+ StartOperation (new OperationStep (this, mode, frame, result));
+ return result;
}
- public override void Continue (TargetAddress until, CommandResult result)
+ public override CommandResult Step (ThreadingModel model, StepMode mode, StepFrame frame)
{
- StartOperation (new OperationRun (this, until, false, result));
- }
+ StartOperation ();
- public override void Background (TargetAddress until, CommandResult result)
- {
- StartOperation (new OperationRun (this, until, true, result));
+ return (CommandResult) SendCommand (delegate {
+ Report.Debug (DebugFlags.SSE, "{0} step: {1} {2} {3}", this, model, mode, frame);
+ CommandResult result = process.Debugger.StartOperation (model, this);
+ return ProcessOperation (new OperationStep (this, mode, frame, result));
+ });
}
public override void RuntimeInvoke (TargetFunctionType function,
@@ -1829,11 +1942,12 @@ public override CommandResult Return (ReturnMode mode)
frame_changed (inferior.CurrentFrame, null);
TargetEventArgs args = new TargetEventArgs (
TargetEventType.TargetStopped, 0, current_frame);
- process.OnTargetEvent (this, args);
+ process.Debugger.SendTargetEvent (this, args);
return null;
}
- return StartOperation (new OperationReturn (this, bt, mode));
+ CommandResult result = new ThreadCommandResult (thread);
+ return StartOperation (new OperationReturn (this, bt, mode, result));
});
}
@@ -1907,7 +2021,8 @@ void DoAbortInvocation (long rti_id)
if (bt.Count < 2)
throw new TargetException (TargetError.NoStack);
- PushOperation (new OperationReturn (this, bt, ReturnMode.Invocation));
+ CommandResult result = new ThreadCommandResult (thread);
+ PushOperation (new OperationReturn (this, bt, ReturnMode.Invocation, result));
}
public override Backtrace GetBacktrace (Backtrace.Mode mode, int max_frames)
@@ -2142,10 +2257,15 @@ public void ManagedCallback (ManagedCallbackFunction func, CommandResult result)
bool ok = false;
process.AcquireGlobalThreadLock (this);
foreach (SingleSteppingEngine engine in process.ThreadServants) {
+ try {
if (engine.do_managed_callback (data)) {
ok = true;
break;
}
+ } catch (Exception ex) {
+ Console.WriteLine ("FUCK: {0} {1}", engine, ex);
+ }
+
}
if (!ok) {
@@ -2317,6 +2437,7 @@ protected override void DoDispose ()
bool engine_stopped;
bool reached_main;
bool killed, dead;
+ bool stop_requested;
bool attach_initialized;
long tid;
int pid;
@@ -2511,10 +2632,12 @@ public void PushOperation (Operation op)
child = op;
}
- public void CompletedOperation ()
+ public virtual void CompletedOperation (bool suspended)
{
- Result.Completed ();
- child = null;
+ if (!suspended) {
+ Result.Completed ();
+ child = null;
+ }
}
public virtual EventResult ProcessEvent (Inferior.ChildEvent cevent,
@@ -2644,10 +2767,15 @@ public virtual EventResult CompletedOperation (Inferior.ChildEvent cevent, Event
}
}
- args = new TargetEventArgs (TargetEventType.TargetStopped, 0, sse.current_frame);
+ args = OperationCompleted (sse.current_frame, result == EventResult.SuspendOperation);
return result;
}
+ public virtual TargetEventArgs OperationCompleted (StackFrame frame, bool suspended)
+ {
+ return null;
+ }
+
protected abstract EventResult DoProcessEvent (Inferior.ChildEvent cevent,
out TargetEventArgs args);
@@ -2750,10 +2878,15 @@ protected override void DoExecute ()
}
Report.Debug (DebugFlags.SSE, "{0} start #1: {1}", sse, cevent);
- sse.PushOperation (new OperationRun (sse, true, Result));
+ sse.PushOperation (new OperationStep (sse, StepMode.Run, Result));
return EventResult.Running;
}
+ public override TargetEventArgs OperationCompleted (StackFrame frame, bool suspended)
+ {
+ return new TargetEventArgs (TargetEventType.TargetStopped, 0, frame);
+ }
+
public override bool HandleException (TargetAddress stack, TargetAddress exc)
{
return sse.reached_main ? false : true;
@@ -2854,7 +2987,7 @@ protected override void DoExecute ()
func.Token, Index, func.DeclaringType.BaseName, ID);
}
- protected override EventResult CallbackCompleted (long data1, long data2)
+ protected override EventResult CallbackCompleted (long data1, long data2, out TargetEventArgs args)
{
TargetAddress info = new TargetAddress (inferior.AddressDomain, data1);
@@ -2863,32 +2996,8 @@ protected override EventResult CallbackCompleted (long data1, long data2)
sse.Process.MonoLanguage.RegisterMethodLoadHandler (inferior, info, Index, Handle.MethodLoaded);
Handle.Breakpoint.OnBreakpointBound ();
- return EventResult.AskParent;
- }
- }
-
- protected class OperationInitialize : Operation
- {
- public OperationInitialize (SingleSteppingEngine sse, CommandResult result)
- : base (sse, result)
- { }
-
- public override bool IsSourceOperation {
- get { return true; }
- }
-
- protected override void DoExecute ()
- { }
-
- protected override EventResult DoProcessEvent (Inferior.ChildEvent cevent,
- out TargetEventArgs args)
- {
- Report.Debug (DebugFlags.SSE,
- "{0} initialize ({1})", sse,
- DebuggerWaitHandle.CurrentThread);
-
args = null;
- return EventResult.Completed;
+ return EventResult.AskParent;
}
}
@@ -2937,7 +3046,7 @@ protected override void DoExecute ()
inferior.CallMethod (info.InitCodeBuffer, 0, 0, ID);
}
- protected override EventResult CallbackCompleted (long data1, long data2)
+ protected override EventResult CallbackCompleted (long data1, long data2, out TargetEventArgs args)
{
Report.Debug (DebugFlags.SSE,
"{0} init code buffer: {1:x} {2:x} {3}",
@@ -2947,6 +3056,7 @@ protected override EventResult CallbackCompleted (long data1, long data2)
sse.process.MonoManager.InitCodeBuffer (inferior, buffer);
RestoreStack ();
+ args = null;
return EventResult.AskParent;
}
}
@@ -3115,6 +3225,12 @@ protected OperationStepBase (SingleSteppingEngine sse, CommandResult result)
: base (sse, result)
{ }
+ public override void Execute ()
+ {
+ Report.Debug (DebugFlags.SSE, "{0} start stepping operation: {1} {2}", sse, this, Result);
+ base.Execute ();
+ }
+
protected override EventResult DoProcessEvent (Inferior.ChildEvent cevent,
out TargetEventArgs args)
{
@@ -3128,6 +3244,11 @@ protected OperationStepBase (SingleSteppingEngine sse, CommandResult result)
return completed ? EventResult.Completed : EventResult.Running;
}
+ public override TargetEventArgs OperationCompleted (StackFrame frame, bool suspended)
+ {
+ return new TargetEventArgs (TargetEventType.TargetStopped, 0, frame);
+ }
+
protected abstract bool DoProcessEvent ();
protected abstract bool TrampolineHandler (Method method);
@@ -3135,8 +3256,10 @@ protected OperationStepBase (SingleSteppingEngine sse, CommandResult result)
protected class OperationStep : OperationStepBase
{
- public StepMode StepMode;
- public StepFrame StepFrame;
+ public readonly StepMode StepMode;
+ public StepFrame StepFrame {
+ get; private set;
+ }
public OperationStep (SingleSteppingEngine sse, StepMode mode, CommandResult result)
: base (sse, result)
@@ -3151,17 +3274,34 @@ public OperationStep (SingleSteppingEngine sse, StepFrame frame, CommandResult r
this.StepMode = frame.Mode;
}
+ public OperationStep (SingleSteppingEngine sse, StepMode mode, StepFrame frame, CommandResult result)
+ : base (sse, result)
+ {
+ this.StepFrame = frame;
+ this.StepMode = mode;
+ }
+
public override bool IsSourceOperation {
get {
return (StepMode == StepMode.SourceLine) ||
(StepMode == StepMode.NextLine) ||
- (StepMode == StepMode.Finish);
+ (StepMode == StepMode.Finish) ||
+ (StepMode == StepMode.Run);
}
}
protected override void DoExecute ()
{
+ Report.Debug (DebugFlags.SSE, "{0} step execute: {1}", sse, inferior.CurrentFrame);
+
switch (StepMode) {
+ case StepMode.Run:
+ if (StepFrame != null)
+ sse.do_continue (StepFrame.Until);
+ else
+ sse.do_continue ();
+ break;
+
case StepMode.NativeInstruction:
sse.do_step_native ();
break;
@@ -3189,8 +3329,8 @@ protected override void DoExecute ()
sse.do_next ();
else {
StepFrame = new StepFrame (
- frame.Start, frame.End, frame.StackFrame,
- null, StepMode.Finish);
+ null, StepMode.Finish, frame.StackFrame,
+ frame.Start, frame.End);
Step (true);
}
break;
@@ -3201,6 +3341,7 @@ protected override void DoExecute ()
break;
case StepMode.Finish:
+ case StepMode.FinishNative:
Step (true);
break;
@@ -3214,7 +3355,7 @@ public override bool ResumeOperation ()
Report.Debug (DebugFlags.SSE, "{0} resuming operation {1}", sse, this);
if (sse.temp_breakpoint != null) {
- inferior.Continue ();
+ sse.do_continue ();
return true;
}
@@ -3223,6 +3364,8 @@ public override bool ResumeOperation ()
public override bool HandleException (TargetAddress stack, TargetAddress exc)
{
+ if (StepMode == StepMode.Run)
+ return false;
if ((StepMode != StepMode.SourceLine) && (StepMode != StepMode.NextLine) &&
(StepMode != StepMode.StepFrame))
return true;
@@ -3281,8 +3424,8 @@ bool check_method_operation (TargetAddress current_frame)
Report.Debug (DebugFlags.SSE, "{0} reached method epilogue: {1} {2} {3}",
sse, current_frame, lnt.MethodEndAddress, method.EndAddress);
StepFrame = new StepFrame (
- lnt.MethodEndAddress, method.EndAddress,
- null, null, StepMode.Finish);
+ null, StepMode.Finish, null,
+ lnt.MethodEndAddress, method.EndAddress);
return true;
}
@@ -3291,11 +3434,31 @@ bool check_method_operation (TargetAddress current_frame)
protected bool Step (bool first)
{
- if (StepFrame == null)
- return true;
-
TargetAddress current_frame = inferior.CurrentFrame;
- again:
+
+ if (StepMode == StepMode.Run) {
+ TargetAddress until = StepFrame != null ? StepFrame.Until : TargetAddress.Null;
+ if (!until.IsNull && (current_frame == until))
+ return true;
+ sse.do_continue ();
+ return false;
+ }
+
+ if (StepMode == StepMode.FinishNative) {
+ Inferior.StackFrame frame = inferior.GetCurrentFrame ();
+ TargetAddress stack = frame.StackPointer;
+
+ Report.Debug (DebugFlags.SSE,
+ "{0} finish native: stack = {1}, " +
+ "until = {2}", sse, stack, StepFrame.Until);
+
+ if (stack <= StepFrame.Until) {
+ sse.do_next ();
+ return false;
+ }
+ }
+
+ again:
bool in_frame = sse.is_in_step_frame (StepFrame, current_frame);
Report.Debug (DebugFlags.SSE, "{0} stepping at {1} in {2} ({3}in frame)",
sse, current_frame, StepFrame, !in_frame ? "not " : "");
@@ -3387,176 +3550,38 @@ protected bool Step (bool first)
return false;
}
- protected override bool DoProcessEvent ()
- {
- Report.Debug (DebugFlags.SSE, "{0} processing {1} event.",
- sse, this);
- return Step (false);
- }
-
- protected override string MyToString ()
- {
- return String.Format ("{0}:{1}", StepMode, StepFrame);
- }
- }
-
- protected class OperationRun : Operation
- {
- TargetAddress until;
- bool in_background;
-
- public override bool CheckBreakpointsOnCompletion {
- get { return true; }
- }
-
- public OperationRun (SingleSteppingEngine sse, TargetAddress until,
- bool in_background, CommandResult result)
- : base (sse, result)
- {
- this.until = until;
- this.in_background = in_background;
- }
-
- public OperationRun (SingleSteppingEngine sse, bool in_background,
- CommandResult result)
- : this (sse, TargetAddress.Null, in_background, result)
- { }
-
- public OperationRun (SingleSteppingEngine sse, CommandResult result)
- : this (sse, TargetAddress.Null, true, result)
- { }
-
-
- public bool InBackground {
- get { return in_background; }
- }
-
- public override bool IsSourceOperation {
- get { return true; }
- }
-
- protected override void DoExecute ()
- {
- if (!until.IsNull)
- sse.do_continue (until);
- else
- sse.do_continue ();
- }
-
- public override bool ResumeOperation ()
- {
- Report.Debug (DebugFlags.SSE, "{0} resuming operation {1}", sse, this);
-
- sse.do_continue ();
- return true;
- }
-
protected override EventResult DoProcessEvent (Inferior.ChildEvent cevent,
out TargetEventArgs args)
{
- args = null;
- if (!until.IsNull && inferior.CurrentFrame == until)
- return EventResult.Completed;
- Report.Debug (DebugFlags.EventLoop, "{0} received {1} at {2} in {3}",
- sse, cevent, inferior.CurrentFrame, this);
- if ((cevent.Type == Inferior.ChildEventType.CHILD_HIT_BREAKPOINT) ||
- (cevent.Type == Inferior.ChildEventType.CHILD_CALLBACK) ||
- (cevent.Type == Inferior.ChildEventType.RUNTIME_INVOKE_DONE))
- return EventResult.Completed;
- Execute ();
- return EventResult.Running;
- }
+ string frame_text = "";
+ Inferior.StackFrame iframe = inferior.GetCurrentFrame (true);
+ if (iframe != null)
+ frame_text = " at " + iframe.Address.ToString ();
- public override bool HandleException (TargetAddress stack, TargetAddress exc)
- {
- return false;
- }
- }
+ Report.Debug (DebugFlags.EventLoop, "{0} received {1}{2} in {3}",
+ sse, cevent, frame_text, this);
- protected class OperationFinish : OperationStepBase
- {
- public readonly bool Native;
-
- public OperationFinish (SingleSteppingEngine sse, bool native, CommandResult result)
- : base (sse, result)
- {
- this.Native = native;
- }
-
- public override bool IsSourceOperation {
- get { return !Native; }
- }
-
- StepFrame step_frame;
- TargetAddress until;
-
- protected override void DoExecute ()
- {
- if (!Native) {
- StackFrame frame = sse.CurrentFrame;
- if (frame.Method == null)
- throw new TargetException (TargetError.NoMethod);
-
- step_frame = new StepFrame (
- frame.Method.StartAddress, frame.Method.EndAddress,
- frame, null, StepMode.Finish);
- } else {
- Inferior.StackFrame frame = inferior.GetCurrentFrame ();
- until = frame.StackPointer;
-
- Report.Debug (DebugFlags.SSE,
- "{0} starting finish native until {1} {2}",
- sse, until, sse.temp_breakpoint);
- }
-
- sse.do_next ();
- }
-
- public override bool ResumeOperation ()
- {
- Report.Debug (DebugFlags.SSE, "{0} resuming operation {1}", sse, this);
-
- if (sse.temp_breakpoint != null) {
- inferior.Continue ();
- return true;
+ if ((StepMode == StepMode.Run) &&
+ ((cevent.Type == Inferior.ChildEventType.CHILD_HIT_BREAKPOINT) ||
+ (cevent.Type == Inferior.ChildEventType.CHILD_CALLBACK) ||
+ (cevent.Type == Inferior.ChildEventType.RUNTIME_INVOKE_DONE))) {
+ args = null;
+ return EventResult.Completed;
}
- return !DoProcessEvent ();
+ return base.DoProcessEvent (cevent, out args);
}
protected override bool DoProcessEvent ()
{
- if (step_frame != null) {
- bool in_frame = sse.is_in_step_frame (step_frame, inferior.CurrentFrame);
- Report.Debug (DebugFlags.SSE,
- "{0} finish {1} at {2} ({3}", sse, step_frame,
- inferior.CurrentFrame, in_frame);
-
- if (!in_frame)
- return true;
-
- sse.do_next ();
- return false;
- }
-
- Inferior.StackFrame frame = inferior.GetCurrentFrame ();
- TargetAddress stack = frame.StackPointer;
-
- Report.Debug (DebugFlags.SSE,
- "{0} finish native: stack = {1}, " +
- "until = {2}", sse, stack, until);
-
- if (stack <= until) {
- sse.do_next ();
- return false;
- }
-
- return true;
+ Report.Debug (DebugFlags.SSE, "{0} processing {1} event.",
+ sse, this);
+ return Step (false);
}
- protected override bool TrampolineHandler (Method method)
+ protected override string MyToString ()
{
- return false;
+ return String.Format ("{0}:{1}", StepMode, StepFrame);
}
}
@@ -3617,8 +3642,7 @@ public override void Execute ()
}
try {
- args = null;
- return CallbackCompleted (cevent);
+ return CallbackCompleted (cevent.Data1, cevent.Data2, out args);
} catch (Exception ex) {
Report.Debug (DebugFlags.SSE, "{0} got exception while handling event {1}: {2}",
sse, cevent, ex);
@@ -3627,12 +3651,7 @@ public override void Execute ()
}
}
- protected virtual EventResult CallbackCompleted (Inferior.ChildEvent cevent)
- {
- return CallbackCompleted (cevent.Data1, cevent.Data2);
- }
-
- protected abstract EventResult CallbackCompleted (long data1, long data2);
+ protected abstract EventResult CallbackCompleted (long data1, long data2, out TargetEventArgs args);
public override bool IsSourceOperation {
get { return false; }
@@ -3747,6 +3766,11 @@ bool do_execute ()
args = null;
return EventResult.ResumeOperation;
}
+
+ public override TargetEventArgs OperationCompleted (StackFrame frame, bool suspended)
+ {
+ return null;
+ }
}
protected class OperationRuntimeInvoke : InterruptibleOperation
@@ -3757,6 +3781,7 @@ protected class OperationRuntimeInvoke : InterruptibleOperation
public readonly TargetObject[] ParamObjects;
public readonly RuntimeInvokeFlags Flags;
+ bool stopped_somewhere;
OperationRuntimeInvokeHelper helper;
public override bool IsSourceOperation {
@@ -3895,6 +3920,25 @@ public void Completed (long data1, long data2)
Result.InvocationCompleted = true;
}
+ public override TargetEventArgs OperationCompleted (StackFrame frame, bool suspended)
+ {
+ if (Result.InvocationCompleted || Result.InvocationAborted) {
+ if (stopped_somewhere || ((Flags & RuntimeInvokeFlags.SendEventOnCompletion) != 0))
+ return new TargetEventArgs (TargetEventType.RuntimeInvokeDone, Result, frame);
+ else
+ return null;
+ }
+
+ stopped_somewhere = true;
+ return new TargetEventArgs (TargetEventType.TargetStopped, 0, frame);
+ }
+
+ public void AbortInvoke ()
+ {
+ inferior.AbortInvoke (ID);
+ Result.InvocationAborted = true;
+ }
+
protected class OperationRuntimeInvokeHelper : OperationCallback
{
public readonly OperationRuntimeInvoke RTI;
@@ -4050,7 +4094,7 @@ bool get_virtual_method ()
return false;
}
- protected override EventResult CallbackCompleted (long data1, long data2)
+ protected override EventResult CallbackCompleted (long data1, long data2, out TargetEventArgs args)
{
switch (stage) {
case Stage.Uninitialized: {
@@ -4064,6 +4108,7 @@ protected override EventResult CallbackCompleted (long data1, long data2)
((IMonoStructType) RTI.Function.DeclaringType).ResolveClass (inferior, false);
stage = Stage.ResolvedClass;
do_execute ();
+ args = null;
return EventResult.Running;
}
@@ -4078,6 +4123,7 @@ protected override EventResult CallbackCompleted (long data1, long data2)
instance = (TargetStructObject) parent_type.GetObject (inferior, new_loc);
stage = Stage.HasMethodAddress;
do_execute ();
+ args = null;
return EventResult.Running;
}
@@ -4095,6 +4141,7 @@ protected override EventResult CallbackCompleted (long data1, long data2)
"Unable to get virtual method `{0}'.", RTI.Function.FullName);
RTI.Result.InvocationCompleted = true;
RestoreStack ();
+ args = null;
return EventResult.CompletedCallback;
}
@@ -4111,6 +4158,7 @@ protected override EventResult CallbackCompleted (long data1, long data2)
stage = Stage.HasVirtualMethod;
do_execute ();
+ args = null;
return EventResult.Running;
}
@@ -4122,12 +4170,14 @@ protected override EventResult CallbackCompleted (long data1, long data2)
stage = Stage.CompiledMethod;
do_execute ();
+ args = null;
return EventResult.Running;
}
case Stage.InvokedMethod: {
RTI.Completed (data1, data2);
RestoreStack ();
+ args = null;
return EventResult.CompletedCallback;
}
@@ -4288,7 +4338,7 @@ protected override void DoExecute ()
return EventResult.Running;
}
- protected override EventResult CallbackCompleted (long data1, long data2)
+ protected override EventResult CallbackCompleted (long data1, long data2, out TargetEventArgs args)
{
if (inferior.TargetAddressSize == 4)
data1 &= 0xffffffffL;
@@ -4299,6 +4349,7 @@ protected override EventResult CallbackCompleted (long data1, long data2)
RestoreStack ();
Result.Result = new TargetAddress (inferior.AddressDomain, data1);
+ args = null;
return EventResult.CompletedCallback;
}
}
@@ -4726,10 +4777,11 @@ protected class OperationReturn : OperationCallback
{
public readonly Backtrace Backtrace;
public readonly ReturnMode Mode;
+ OperationRuntimeInvoke aborted_rti;
int level = 0;
- public OperationReturn (SingleSteppingEngine sse, Backtrace bt, ReturnMode mode)
- : base (sse)
+ public OperationReturn (SingleSteppingEngine sse, Backtrace bt, ReturnMode mode, CommandResult result)
+ : base (sse, result)
{
this.Backtrace = bt;
this.Mode = mode;
@@ -4741,10 +4793,9 @@ protected override void DoExecute ()
inferior.CallMethod (sse.MonoDebuggerInfo.RunFinally, null, ID);
}
- protected override EventResult CallbackCompleted (long data1, long data2)
+ protected override EventResult CallbackCompleted (long data1, long data2, out TargetEventArgs args)
{
- DiscardStack ();
-
+ args = null;
StackFrame parent_frame = Backtrace.Frames [++level];
inferior.SetRegisters (parent_frame.Registers);
@@ -4752,7 +4803,7 @@ protected override EventResult CallbackCompleted (long data1, long data2)
Report.Debug (DebugFlags.SSE, "{0} return: {1} {2}\n{3}", sse, level, cframe, parent_frame);
if (cframe != null) {
Report.Debug (DebugFlags.SSE, "{0} return aborting rti: {1}", sse, cframe);
- sse.AbortRuntimeInvoke (cframe.ID);
+ aborted_rti = sse.AbortRuntimeInvoke (cframe.ID);
return EventResult.Completed;
}
@@ -4764,6 +4815,14 @@ protected override EventResult CallbackCompleted (long data1, long data2)
DoExecute ();
return EventResult.Running;
}
+
+ public override TargetEventArgs OperationCompleted (StackFrame frame, bool suspended)
+ {
+ if (aborted_rti != null)
+ return aborted_rti.OperationCompleted (frame, suspended);
+ else
+ return new TargetEventArgs (TargetEventType.TargetStopped, 0, frame);
+ }
}
protected abstract class InterruptibleOperation : Operation
View
15 backend/ThreadManager.cs
@@ -198,7 +198,7 @@ internal SingleSteppingEngine GetEngine (int id)
engine, inferior, ref cevent, out resume_target);
if ((cevent.Type == Inferior.ChildEventType.CHILD_EXITED) ||
- (cevent.Type == Inferior.ChildEventType.CHILD_SIGNALED)) {
+ (cevent.Type == Inferior.ChildEventType.CHILD_SIGNALED)) {
thread_hash.Remove (engine.PID);
engine_hash.Remove (engine.ID);
engine.OnThreadExited (cevent);
@@ -245,7 +245,7 @@ internal SingleSteppingEngine GetEngine (int id)
return command.Result;
}
- public ProcessServant StartApplication (ProcessStart start)
+ public ProcessServant StartApplication (ProcessStart start, out CommandResult result)
{
Command command = new Command (CommandType.CreateProcess, start);
@@ -264,8 +264,11 @@ public ProcessServant StartApplication (ProcessStart start)
if (command.Result is Exception)
throw (Exception) command.Result;
- else
- return (ProcessServant) command.Result;
+ else {
+ var pair = (KeyValuePair<CommandResult,ProcessServant>) command.Result;
+ result = pair.Key;
+ return pair.Value;
+ }
}
internal void AddPendingEvent (SingleSteppingEngine engine, Inferior.ChildEvent cevent)
@@ -361,11 +364,11 @@ void engine_thread_main ()
ProcessServant process = new ProcessServant (this, start);
processes.Add (process);
- process.StartApplication ();
+ CommandResult result = process.StartApplication ();
RequestWait ();
- command.Result = process;
+ command.Result = new KeyValuePair<CommandResult,ProcessServant> (result, process);
} catch (ST.ThreadAbortException) {
return;