internal SingleSteppingEngine GetEngineByTID(Inferior inferior, long tid) { foreach (SingleSteppingEngine engine in thread_hash.Values) { if (engine.TID == tid) { return(engine); } } if (thread_db == null) { Report.Error("Failed to initialize thread_db on {0}: {1}", start.CommandLine, start); return(null); } SingleSteppingEngine result = null; thread_db.GetThreadInfo(inferior, delegate(int t_lwp, long t_tid) { if (tid != t_tid) { return; } result = (SingleSteppingEngine)thread_hash [t_lwp]; }); if (result == null) { Report.Error("Cannot find thread {0:x} in {1}", tid, start.CommandLine); } return(result); }
internal void ChildForked(Inferior inferior, int pid) { Process new_process = new Process(this, pid); new_process.ProcessStart.StopInMain = false; Inferior new_inferior = Inferior.CreateInferior( manager, new_process, new_process.ProcessStart); new_inferior.InitializeThread(pid); if (!manager.Debugger.Configuration.FollowFork) { new_inferior.DetachAfterFork(); return; } SingleSteppingEngine new_thread = new SingleSteppingEngine( manager, new_process, new_inferior, pid); Report.Debug(DebugFlags.Threads, "Child forked: {0} {1}", pid, new_thread); new_process.main_thread = new_thread; manager.Debugger.OnProcessCreatedEvent(new_process); new_process.OnThreadCreatedEvent(new_thread); CommandResult result = new_process.CloneParentOperation(new_thread); new_thread.StartForkedChild(result); }
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; } else { thread_hash.Add(engine.PID, engine); } session.MainThreadGroup.AddThread(engine.Thread.ID); session.OnMainProcessCreated(this); manager.Debugger.OnMainProcessCreatedEvent(this); CommandResult result = Debugger.StartOperation(start.Session.Config.ThreadingModel, engine); return(engine.StartApplication(result)); }
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 ProcessCommandResult(this, parent.current_operation.ThreadingModel); } else { throw new InternalError(); } return(current_operation); }
internal void ThreadCreated(Inferior inferior, int pid, bool do_attach, bool resume_thread) { Inferior new_inferior = inferior.CreateThread(pid, do_attach); SingleSteppingEngine new_thread = new SingleSteppingEngine(manager, this, new_inferior, pid); Report.Debug(DebugFlags.Threads, "Thread created: {0} {1} {2}", pid, new_thread, do_attach); if (mono_manager != null) { mono_manager.ThreadCreated(new_thread); } if (!do_attach && !is_execed) { get_thread_info(inferior, new_thread); } OnThreadCreatedEvent(new_thread); if (resume_thread) { CommandResult result = current_operation != null ? current_operation : new ThreadCommandResult(new_thread.Thread); new_thread.StartThread(result); } else { new_thread.StartSuspended(); } }
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 ProcessCommandResult(this, model); } ResumeUserThreads(model, caller); return(current_operation); }
internal void OperationCompleted(SingleSteppingEngine caller, TargetEventArgs result, ThreadingModel model) { if (!ThreadManager.InBackgroundThread && Inferior.HasThreadEvents) { 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(); } }
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); }
internal object SendCommand(SingleSteppingEngine sse, TargetAccessDelegate target, object user_data) { Command command = new Command(sse, target, user_data); if (!engine_event.WaitOne(WaitTimeout, false)) { throw new TargetException(TargetError.NotStopped); } event_queue.Lock(); engine_event.Reset(); current_command = command; event_queue.Signal(); event_queue.Unlock(); engine_event.WaitOne(); if (command.Result is Exception) { throw (Exception)command.Result; } else { return(command.Result); } }
void check_pending_events() { SingleSteppingEngine[] list = new SingleSteppingEngine [pending_events.Count]; pending_events.Keys.CopyTo(list, 0); for (int i = 0; i < list.Length; i++) { SingleSteppingEngine engine = list [i]; if (engine.Process.HasThreadLock) { continue; } Inferior.ChildEvent cevent = (Inferior.ChildEvent)pending_events [engine]; pending_events.Remove(engine); try { Report.Debug(DebugFlags.Wait, "ThreadManager {0} process pending event: {1} {2}", DebuggerWaitHandle.CurrentThread, engine, cevent); engine.ReleaseThreadLock(cevent); Report.Debug(DebugFlags.Wait, "ThreadManager {0} process pending event done: {1}", DebuggerWaitHandle.CurrentThread, engine); } catch (ST.ThreadAbortException) { ; } catch (Exception e) { Report.Debug(DebugFlags.Wait, "ThreadManager caught exception: {0}", e); } } }
void get_thread_info(Inferior inferior, SingleSteppingEngine engine) { if (thread_db == null) { if (mono_manager == null) { return; } Report.Error("Failed to initialize thread_db on {0}: {1} {2}", start.CommandLine, start, Environment.StackTrace); throw new InternalError(); } bool found = false; thread_db.GetThreadInfo(inferior, delegate(int lwp, long tid) { if (lwp != engine.PID) { return; } engine.SetTID(tid); found = true; }); if (!found) { Report.Error("Cannot find thread {0:x} in {1}", engine.PID, start.CommandLine); } }
internal override void Completed(SingleSteppingEngine sse, TargetEventArgs args) { Host.OperationCompleted(sse, args, ThreadingModel); if (args != null) { Host.SendResult(sse, args); } }
internal void ThreadCreated(SingleSteppingEngine sse) { sse.Inferior.SetRuntimeInfo(mono_runtime_info); if (!MonoDebuggerInfo.CheckRuntimeVersion(81, 3) && !process.IsAttached) { if (++index < 3) { sse.Thread.ThreadFlags |= Thread.Flags.Daemon | Thread.Flags.Immutable; } } else { 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.Thread.ThreadFlags &= ~(Thread.Flags.Daemon | Thread.Flags.Immutable); if (engine != process.MainThreadServant) { process.Debugger.OnManagedThreadCreatedEvent(engine.Thread); } } else if ((flags & ThreadFlags.ThreadPool) != 0) { engine.Thread.ThreadFlags &= ~Thread.Flags.Immutable; } }
void OperationCompleted(SingleSteppingEngine caller, TargetEventArgs result, ThreadingModel model) { if (!ThreadManager.InBackgroundThread) { throw new InternalError(); } foreach (Process process in process_hash.Values) { process.OperationCompleted(caller, result, model); } lock (this) { current_operation = null; stopped_event.Set(); } }
internal void ReleaseGlobalThreadLock(SingleSteppingEngine caller) { Report.Debug(DebugFlags.Threads, "Releasing global thread lock: {0}", caller); foreach (ThreadServant thread in thread_hash.Values) { if (thread == caller) { continue; } thread.ReleaseThreadLock(); } has_thread_lock = false; thread_lock_mutex.Unlock(); Report.Debug(DebugFlags.Threads, "Released global thread lock: {0}", caller); }
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 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); }
public void Kill() { if (!Inferior.HasThreadEvents) { SingleSteppingEngine[] sses = new SingleSteppingEngine [thread_hash.Count]; thread_hash.Values.CopyTo(sses, 0); foreach (SingleSteppingEngine sse in sses) { sse.SetKilledFlag(); } foreach (SingleSteppingEngine sse in sses) { sse.Kill(); } } else { main_thread.Kill(); } }
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 GlobalCommandResult(this, model); } foreach (Process process in process_hash.Values) { process.StartGlobalOperation(model, caller, current_operation); } return(current_operation); }
internal virtual void Completed(SingleSteppingEngine sse, TargetEventArgs args) { if ((args != null) && ((args.Type == TargetEventType.TargetExited) || (args.Type == TargetEventType.TargetSignaled))) { if ((sse.Thread.ThreadFlags & Thread.Flags.StopOnExit) == 0) { Host.SendResult(sse, args); return; } } if (!IsCompleted) { IsCompleted = true; if (args != null) { Host.SendResult(sse, args); } Host.OperationCompleted(sse, args, ThreadingModel); } }
internal void InitializeThreads(Inferior inferior, bool resume_threads) { if (thread_db != null) { return; } thread_db = ThreadDB.Create(this, inferior); if (thread_db == null) { if (!IsManaged) { return; } Report.Error("Failed to initialize thread_db on {0}", start.CommandLine); throw new TargetException(TargetError.CannotStartTarget, "Failed to initialize thread_db on {0}", start.CommandLine); } int[] threads = inferior.GetThreads(); foreach (int thread in threads) { if (thread_hash.Contains(thread)) { continue; } ThreadCreated(inferior, thread, Inferior.HasThreadEvents, resume_threads); } thread_db.GetThreadInfo(inferior, delegate(int lwp, long tid) { SingleSteppingEngine engine = (SingleSteppingEngine)thread_hash [lwp]; if (engine == null) { Report.Error("Unknown thread {0} in {1}", lwp, start.CommandLine); return; } engine.SetTID(tid); }); }
// <summary> // Stop all currently running threads without sending any notifications. // The threads are automatically resumed to their previos state when // ReleaseGlobalThreadLock() is called. // </summary> internal void AcquireGlobalThreadLock(SingleSteppingEngine caller) { if (has_thread_lock) { throw new InternalError("Recursive thread lock"); } thread_lock_mutex.Lock(); Report.Debug(DebugFlags.Threads, "Acquiring global thread lock: {0}", caller); has_thread_lock = true; foreach (ThreadServant thread in thread_hash.Values) { if (thread == caller) { continue; } thread.AcquireThreadLock(); } Report.Debug(DebugFlags.Threads, "Done acquiring global thread lock: {0}", caller); }
internal bool HandleChildEvent(SingleSteppingEngine engine, Inferior inferior, ref Inferior.ChildEvent cevent, out bool resume_target) { if (cevent.Type == Inferior.ChildEventType.NONE) { resume_target = true; return(true); } if (cevent.Type == Inferior.ChildEventType.CHILD_CREATED_THREAD) { int pid = (int)cevent.Argument; inferior.Process.ThreadCreated(inferior, pid, false, true); if (pending_sigstops.ContainsKey(pid)) { pending_sigstops.Remove(pid); } resume_target = true; return(true); } if (cevent.Type == Inferior.ChildEventType.CHILD_FORKED) { inferior.Process.ChildForked(inferior, (int)cevent.Argument); resume_target = true; return(true); } if (cevent.Type == Inferior.ChildEventType.CHILD_EXECD) { thread_hash.Remove(engine.PID); engine_hash.Remove(engine.ID); inferior.Process.ChildExecd(engine, inferior); resume_target = false; return(true); } if (cevent.Type == Inferior.ChildEventType.CHILD_STOPPED) { if (cevent.Argument == inferior.SIGCHLD) { cevent = new Inferior.ChildEvent( Inferior.ChildEventType.CHILD_STOPPED, 0, 0, 0); resume_target = true; return(true); } else if (inferior.Has_SIGWINCH && (cevent.Argument == inferior.SIGWINCH)) { resume_target = true; return(true); } else if (inferior.HasSignals && (cevent.Argument == inferior.Kernel_SIGRTMIN + 1)) { // __SIGRTMIN and __SIGRTMIN+1 are used internally by the threading library resume_target = true; return(true); } } if (inferior.Process.OperatingSystem.CheckForPendingMonoInit(inferior)) { resume_target = true; return(true); } bool retval = false; resume_target = false; if (inferior.Process.MonoManager != null) { retval = inferior.Process.MonoManager.HandleChildEvent( engine, inferior, ref cevent, out resume_target); } if ((cevent.Type == Inferior.ChildEventType.CHILD_EXITED) || (cevent.Type == Inferior.ChildEventType.CHILD_SIGNALED)) { thread_hash.Remove(engine.PID); engine_hash.Remove(engine.ID); engine.OnThreadExited(cevent); resume_target = false; return(true); } return(retval); }
internal override void OnExecd(SingleSteppingEngine new_thread) { Thread = new_thread.Thread; }
void IOperationHost.SendResult(SingleSteppingEngine sse, TargetEventArgs args) { sse.Process.Debugger.OnTargetEvent(sse.Client, args); }
void IOperationHost.OperationCompleted(SingleSteppingEngine sse, TargetEventArgs args, ThreadingModel model) { }
bool wait_thread_main() { Report.Debug(DebugFlags.Wait, "Wait thread sleeping"); wait_event.WaitOne(); waiting = true; again: Report.Debug(DebugFlags.Wait, "Wait thread again"); int pid = 0, status = 0; if (abort_requested) { Report.Debug(DebugFlags.Wait, "Wait thread abort requested"); // // Reap all our children. // do { Report.Debug(DebugFlags.Wait, "Wait thread reaping children"); pid = mono_debugger_server_global_wait(out status); Report.Debug(DebugFlags.Wait, "Wait thread received event: {0} {1:x}", pid, status); } while (pid > 0); Report.Debug(DebugFlags.Wait, "Wait thread done"); return(false); } if (DateTime.Now - last_pending_sigstop > new TimeSpan(0, 2, 30)) { foreach (int pending in pending_sigstops.Keys) { Report.Error("Got SIGSTOP from unknown PID {0}!", pending); } pending_sigstops.Clear(); last_pending_sigstop = DateTime.Now; } Report.Debug(DebugFlags.Wait, "Wait thread waiting"); // // Wait until we got an event from the target or a command from the user. // pid = mono_debugger_server_global_wait(out status); Report.Debug(DebugFlags.Wait, "Wait thread received event: {0} {1:x}", pid, status); // // Note: `pid' is basically just an unique number which identifies the // SingleSteppingEngine of this event. // if (abort_requested || (pid <= 0)) { return(true); } if (!Inferior.HasThreadEvents) { int arg; Inferior.ChildEventType etype = mono_debugger_server_dispatch_simple(status, out arg); SingleSteppingEngine engine = (SingleSteppingEngine)thread_hash [pid]; if (etype == Inferior.ChildEventType.CHILD_EXITED) { if (engine != null) { SingleSteppingEngine[] sses = new SingleSteppingEngine [thread_hash.Count]; thread_hash.Values.CopyTo(sses, 0); foreach (SingleSteppingEngine sse in sses) { sse.ProcessEvent(status); } Dispose(); waiting = false; return(true); } else { goto again; } } if (engine == null) { SingleSteppingEngine[] sses = new SingleSteppingEngine [thread_hash.Count]; thread_hash.Values.CopyTo(sses, 0); Inferior inferior = sses[0].Inferior; inferior.Process.ThreadCreated(inferior, pid, false, true); goto again; } ArrayList check_threads = new ArrayList(); bool got_threads = true; foreach (Process process in processes) { got_threads = got_threads && process.CheckForThreads(check_threads); } if (got_threads) { int[] lwps = new int [thread_hash.Count]; thread_hash.Keys.CopyTo(lwps, 0); foreach (int lwp in lwps) { if (!check_threads.Contains(lwp)) { SingleSteppingEngine old_engine = (SingleSteppingEngine)thread_hash [lwp]; thread_hash.Remove(old_engine.PID); engine_hash.Remove(old_engine.ID); old_engine.Process.OnThreadExitedEvent(old_engine); old_engine.Dispose(); } } } } SingleSteppingEngine event_engine = (SingleSteppingEngine)thread_hash [pid]; if (event_engine == null && Inferior.HasThreadEvents) { int arg; Inferior.ChildEventType etype = mono_debugger_server_dispatch_simple(status, out arg); /* * Ignore exit events from unknown children. */ if ((etype == Inferior.ChildEventType.CHILD_EXITED) && (arg == 0)) { goto again; } /* * There is a race condition in the Linux kernel which shows up on >= 2.6.27: * * When creating a new thread, the initial stopping event of that thread is sometimes * sent before sending the `PTRACE_EVENT_CLONE' for it. * * Because of this, we explicitly wait for the new thread to stop and ignore any * "early" stopping signals. * * See also the comments in _server_ptrace_wait_for_new_thread() in x86-linux-ptrace.c * and bugs #423518 and #466012. * */ if ((etype != Inferior.ChildEventType.CHILD_STOPPED) || (arg != 0)) { Report.Error("WARNING: Got event {0:x} for unknown pid {1}", status, pid); waiting = false; RequestWait(); return(true); } if (!pending_sigstops.ContainsKey(pid)) { pending_sigstops.Add(pid, DateTime.Now); } Report.Debug(DebugFlags.Wait, "Ignoring SIGSTOP from unknown pid {0}.", pid); goto again; } engine_event.WaitOne(); event_queue.Lock(); engine_event.Reset(); if (current_event != null) { Console.WriteLine("Current_event is not null: {0}", Environment.StackTrace); throw new InternalError(); } current_event = event_engine; current_event_status = status; waiting = false; event_queue.Signal(); event_queue.Unlock(); return(true); }
// <summary> // The heart of the SingleSteppingEngine. This runs in a background // thread and processes stepping commands and events. // // For each application we're debugging, there is just one SingleSteppingEngine, // no matter how many threads the application has. The engine is using one single // event loop which is processing commands from the user and events from all of // the application's threads. // </summary> void engine_thread_main() { Report.Debug(DebugFlags.Wait, "ThreadManager waiting"); event_queue.Wait(); Report.Debug(DebugFlags.Wait, "ThreadManager done waiting"); if (abort_requested) { Report.Debug(DebugFlags.Wait, "Engine thread abort requested"); return; } int status; SingleSteppingEngine event_engine; Command command; Report.Debug(DebugFlags.Wait, "ThreadManager woke up: {0} {1:x} {2}", current_event, current_event_status, current_command); event_engine = current_event; status = current_event_status; current_event = null; current_event_status = 0; command = current_command; current_command = null; if (event_engine != null) { try { Report.Debug(DebugFlags.Wait, "ThreadManager {0} process event: {1}", DebuggerWaitHandle.CurrentThread, event_engine); event_engine.ProcessEvent(status); Report.Debug(DebugFlags.Wait, "ThreadManager {0} process event done: {1}", DebuggerWaitHandle.CurrentThread, event_engine); } catch (ST.ThreadAbortException) { ; } catch (Exception e) { Report.Debug(DebugFlags.Wait, "ThreadManager caught exception: {0}", e); Console.WriteLine("EXCEPTION: {0}", e); } check_pending_events(); if (command == null) { engine_event.Set(); } RequestWait(); } if (command == null) { return; } // These are synchronous commands; ie. the caller blocks on us // until we finished the command and sent the result. if (command.Type == CommandType.TargetAccess) { try { if (command.Engine.Inferior != null) { command.Result = command.Engine.Invoke( (TargetAccessDelegate)command.Data1, command.Data2); } } catch (ST.ThreadAbortException) { return; } catch (Exception ex) { command.Result = ex; } check_pending_events(); engine_event.Set(); } else if (command.Type == CommandType.CreateProcess) { try { ProcessStart start = (ProcessStart)command.Data1; Process process = new Process(this, start); processes.Add(process); CommandResult result = process.StartApplication(); RequestWait(); command.Result = new KeyValuePair <CommandResult, Process> (result, process); } catch (ST.ThreadAbortException) { return; } catch (Exception ex) { command.Result = ex; } engine_event.Set(); } else { throw new InvalidOperationException(); } }
internal void AddPendingEvent(SingleSteppingEngine engine, Inferior.ChildEvent cevent) { Report.Debug(DebugFlags.Wait, "Add pending event: {0} {1}", engine, cevent); pending_events.Add(engine, cevent); }
internal bool HandleChildEvent(SingleSteppingEngine engine, Inferior inferior, ref Inferior.ChildEvent cevent, out bool resume_target) { if (cevent.Type == Inferior.ChildEventType.CHILD_NOTIFICATION) { NotificationType type = (NotificationType) cevent.Argument; Report.Debug (DebugFlags.EventLoop, "{0} received notification {1}: {2}", engine, type, cevent); switch (type) { case NotificationType.AcquireGlobalThreadLock: Report.Debug (DebugFlags.Threads, "{0} received notification {1}", engine, type); engine.Process.AcquireGlobalThreadLock (engine); break; case NotificationType.ReleaseGlobalThreadLock: Report.Debug (DebugFlags.Threads, "{0} received notification {1}", engine, type); engine.Process.ReleaseGlobalThreadLock (engine); break; case NotificationType.ThreadCreated: { TargetAddress data = new TargetAddress ( inferior.AddressDomain, cevent.Data2); TargetAddress lmf = inferior.ReadAddress (data + 8); engine.SetManagedThreadData (lmf, data + 24); if (MonoDebuggerInfo.CheckRuntimeVersion (81, 3)) { int flags_offset = 56 + inferior.TargetAddressSize; ThreadFlags flags = (ThreadFlags) inferior.ReadInteger (data + flags_offset); check_thread_flags (engine, flags); } Report.Debug (DebugFlags.Threads, "{0} managed thread created: {1:x} {2} {3} - {4}", engine, cevent.Data1, data, lmf, engine.LMFAddress); break; } case NotificationType.ThreadCleanup: { TargetAddress data = new TargetAddress ( inferior.AddressDomain, cevent.Data1); Report.Debug (DebugFlags.Threads, "{0} managed thread cleanup: {1:x} {2}", engine, cevent.Data2, data); break; } case NotificationType.GcThreadCreated: { TargetAddress data = new TargetAddress ( inferior.AddressDomain, cevent.Data1); long tid = cevent.Data2; Report.Debug (DebugFlags.Threads, "{0} created gc thread: {1:x} {2}", engine, tid, data); engine = engine.Process.GetEngineByTID (inferior, tid); if (engine == null) throw new InternalError (); engine.OnManagedThreadCreated (data); break; } case NotificationType.GcThreadExited: Report.Debug (DebugFlags.Threads, "{0} gc thread exited", engine); engine.OnManagedThreadExited (); try { inferior.Continue (); } catch { // Ignore errors; for some reason, the thread may have died // already by the time get this notification. } resume_target = false; return true; case NotificationType.InitializeThreadManager: csharp_language = inferior.Process.CreateMonoLanguage ( debugger_info); if (engine.Process.IsAttached) csharp_language.InitializeAttach (inferior); else csharp_language.Initialize (inferior); break; case NotificationType.ReachedMain: { Inferior.StackFrame iframe = inferior.GetCurrentFrame (false); engine.SetMainReturnAddress (iframe.StackPointer); engine.Process.OnProcessReachedMainEvent (); resume_target = !engine.InitializeBreakpoints (); return true; } case NotificationType.WrapperMain: break; case NotificationType.MainExited: engine.SetMainReturnAddress (TargetAddress.Null); break; case NotificationType.UnhandledException: cevent = new Inferior.ChildEvent ( Inferior.ChildEventType.UNHANDLED_EXCEPTION, 0, cevent.Data1, cevent.Data2); resume_target = false; return false; case NotificationType.HandleException: cevent = new Inferior.ChildEvent ( Inferior.ChildEventType.HANDLE_EXCEPTION, 0, cevent.Data1, cevent.Data2); resume_target = false; return false; case NotificationType.ThrowException: cevent = new Inferior.ChildEvent ( Inferior.ChildEventType.THROW_EXCEPTION, 0, cevent.Data1, cevent.Data2); resume_target = false; return false; case NotificationType.FinalizeManagedCode: mono_debugger_server_finalize_mono_runtime (mono_runtime_info); mono_runtime_info = IntPtr.Zero; csharp_language = null; break; case NotificationType.OldTrampoline: case NotificationType.Trampoline: resume_target = false; return false; case NotificationType.ClassInitialized: break; case NotificationType.InterruptionRequest: inferior.WriteInteger (MonoDebuggerInfo.InterruptionRequest, 0); var callbacks = managed_callbacks; managed_callbacks = new Queue<ManagedCallbackData> (); resume_target = !engine.OnManagedCallback (callbacks); return true; default: { TargetAddress data = new TargetAddress ( inferior.AddressDomain, cevent.Data1); resume_target = csharp_language.Notification ( engine, inferior, type, data, cevent.Data2); return true; } } resume_target = true; return true; } if ((cevent.Type == Inferior.ChildEventType.CHILD_STOPPED) && (cevent.Argument == thread_abort_signal)) { resume_target = true; return true; } if ((cevent.Type == Inferior.ChildEventType.CHILD_STOPPED) && (cevent.Argument != 0) && ! engine.Process.Session.Config.StopOnManagedSignals) { if (inferior.IsManagedSignal ((int) cevent.Argument)) { resume_target = true; return true; } } resume_target = false; return false; }
internal void ThreadCreated(SingleSteppingEngine sse) { sse.Inferior.SetRuntimeInfo (mono_runtime_info); if (!MonoDebuggerInfo.CheckRuntimeVersion (81, 3) && !process.IsAttached) { if (++index < 3) sse.Thread.ThreadFlags |= Thread.Flags.Daemon | Thread.Flags.Immutable; } else { 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.Thread.ThreadFlags &= ~(Thread.Flags.Daemon | Thread.Flags.Immutable); if (engine != process.MainThreadServant) process.Debugger.OnManagedThreadCreatedEvent (engine.Thread); } else if ((flags & ThreadFlags.ThreadPool) != 0) { engine.Thread.ThreadFlags &= ~Thread.Flags.Immutable; } }