protected void DoProcessEvent(Inferior.ChildEvent cevent)
{
Inferior.ChildEventType message = cevent.Type;
int arg = (int) cevent.Argument;
if (message == Inferior.ChildEventType.THROW_EXCEPTION) {
TargetAddress info = new TargetAddress (inferior.AddressDomain, cevent.Data1);
TargetAddress ip = new TargetAddress (manager.AddressDomain, cevent.Data2);
Report.Debug (DebugFlags.EventLoop,
"{0} received exception: {1} {2} {3}", this, message, info, ip);
TargetAddress stack = inferior.ReadAddress (info);
TargetAddress exc = inferior.ReadAddress (info + inferior.TargetAddressSize);
ExceptionAction action = throw_exception (stack, exc, ip);
Report.Debug (DebugFlags.SSE,
"{0} throw exception ({1}:{2}:{3}) - {4} - {5} - {6}",
this, stack, exc, ip, action, current_operation, temp_breakpoint);
switch (action) {
case ExceptionAction.None:
do_continue ();
return;
case ExceptionAction.Stop:
inferior.WriteInteger (info + 2 * inferior.TargetAddressSize, 1);
PushOperation (new OperationException (this, ip, exc, false));
return;
case ExceptionAction.StopUnhandled:
if (!check_runtime_version (81, 1) && !check_runtime_version (80, 1))
goto case ExceptionAction.Stop;
inferior.WriteInteger (info + 4 + 2 * inferior.TargetAddressSize, 1);
do_continue ();
return;
}
}
if (message == Inferior.ChildEventType.HANDLE_EXCEPTION) {
TargetAddress info = new TargetAddress (inferior.AddressDomain, cevent.Data1);
TargetAddress ip = new TargetAddress (manager.AddressDomain, cevent.Data2);
Report.Debug (DebugFlags.EventLoop,
"{0} received exception: {1} {2} {3}", this, message, info, ip);
TargetAddress stack = inferior.ReadAddress (info);
TargetAddress exc = inferior.ReadAddress (info + inferior.TargetAddressSize);
bool stop = handle_exception (stack, exc, ip);
Report.Debug (DebugFlags.SSE,
"{0} {1}stopping at exception handler ({2}:{3}:{4}) - {4} - {5}",
this, stop ? "" : "not ", stack, exc, ip, current_operation, temp_breakpoint);
if (stop) {
inferior.WriteInteger (info + 2 * inferior.TargetAddressSize, 1);
PushOperation (new OperationException (this, ip, exc, false));
return;
}
do_continue ();
return;
}
if (lmf_breakpoint != null) {
if ((message == Inferior.ChildEventType.CHILD_HIT_BREAKPOINT) &&
(arg == lmf_breakpoint.Breakpoint.ID)) {
remove_lmf_breakpoint ();
Report.Debug (DebugFlags.SSE, "{0} back in managed land: {1}",
this, inferior.CurrentFrame);
Method method = Lookup (inferior.CurrentFrame);
bool is_managed = (method != null) && method.Module.Language.IsManaged;
Report.Debug (DebugFlags.SSE, "{0} back in managed land #1: {1}", this, is_managed);
Queue<ManagedCallbackData> queue = process.MonoManager.ClearManagedCallbacks (inferior);
if (!OnManagedCallback (queue))
do_continue ();
return;
}
}
// To step over a method call, the sse inserts a temporary
// breakpoint immediately after the call instruction and then
// resumes the target.
//
// If the target stops and we have such a temporary breakpoint, we
// need to distinguish a few cases:
//
// a) we may have received a signal
// b) we may have hit another breakpoint
// c) we actually hit the temporary breakpoint
//
// In either case, we need to remove the temporary breakpoint if
// 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) &&
(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 ();
//
// Lookup again using the current address since `arg' points to the hardware breakpoint,
// but there may be a user breakpoint on the current instruction as well.
//
int idx;
bool is_enabled;
BreakpointHandle handle = process.BreakpointManager.LookupBreakpoint (
inferior.CurrentFrame, out idx, out is_enabled);
Report.Debug (DebugFlags.SSE,
"{0} hit temporary breakpoint {1} at {2}: {3} {4} {5}",
this, arg, inferior.CurrentFrame, handle, idx, is_enabled);
if ((handle == null) || !is_enabled || !handle.Breakpoint.Breaks (thread.ID) ||
handle.Breakpoint.HideFromUser) {
message = Inferior.ChildEventType.CHILD_STOPPED;
arg = 0;
cevent = new Inferior.ChildEvent (Inferior.ChildEventType.CHILD_STOPPED, 0, 0, 0);
} else {
cevent = new Inferior.ChildEvent (Inferior.ChildEventType.CHILD_HIT_BREAKPOINT, idx, 0, 0);
ProcessOperationEvent (cevent);
return;
}
}
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;
} 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
// execution.
Breakpoint bpt;
bool remain_stopped = child_breakpoint (cevent, arg, out bpt);
if (!remain_stopped) {
do_continue ();
return;
}
}
ProcessOperationEvent (cevent);
}