/******************************************************************************* | |
* Copyright (c) 2009 Nokia and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License v1.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/epl-v10.html | |
* | |
* Contributors: | |
* Nokia - Initial API and implementation | |
*******************************************************************************/ | |
#include "ResumeContextAction.h" | |
#include "TCFContext.h" | |
#include "WinProcess.h" | |
#include "WinThread.h" | |
#include "WinDebugMonitor.h" | |
#include "RunControlService.h" | |
#include "BreakpointsService.h" | |
ResumeContextAction::ResumeContextAction(const AgentActionParams& params, | |
WinProcess& process, | |
WinThread& thread, | |
long resumeMode) : AgentAction(params), process_(process), thread_(thread) { | |
resumeMode_ = resumeMode; | |
} | |
ResumeContextAction::~ResumeContextAction(void) { | |
} | |
/* | |
* This will & must be run in debugger monitor thread. | |
*/ | |
void ResumeContextAction::Run() { | |
// Single step over a breakpoint (if any) at current PC. | |
// | |
TBreakpoint* bpAtStartAddress | |
= BreakpointsService::FindBreakpointByAddress(process_.GetProcessHandle(), thread_.GetPCAddress()); | |
if (bpAtStartAddress) { | |
BreakpointsService::ClearBreak(bpAtStartAddress); | |
thread_.EnableSingleStep(); | |
} else if (resumeMode_ == RM_STEP_INTO) | |
thread_.EnableSingleStep(); | |
thread_.MarkResumed(); | |
::ContinueDebugEvent(process_.GetOSID(), thread_.GetOSID(), thread_.GetContinueStatus()); | |
// notify host the Resume action is done before | |
// any suspend event is reported. | |
params.reportSuccessForAction(); | |
if (bpAtStartAddress) { | |
DEBUG_EVENT debugEvent; | |
if (::WaitForDebugEvent(&debugEvent, 200 /* ms */)) { | |
// Done executing single instruction. | |
BreakpointsService::InsertBreak(bpAtStartAddress); // restore the bp | |
if (debugEvent.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP) { | |
if (resumeMode_ == RM_STEP_INTO) | |
// single-step done, report suspend event to host. | |
process_.GetMonitor()->HandleDebugEvent(debugEvent); | |
else | |
// other resume modes | |
// Ignore the SINGLE_STEP event, go on to Resume again | |
::ContinueDebugEvent(process_.GetOSID(), thread_.GetOSID(), DBG_CONTINUE); | |
} else { | |
// Other exceptions | |
// Handle the event, say, report to host. | |
process_.GetMonitor()->HandleDebugEvent(debugEvent); | |
} | |
} else { | |
trace(LOG_ALWAYS, "Failed to execute one instruction. Error: %d", GetLastError()); | |
} | |
} | |
// else the event loop of monitor thread would catch and report event. | |
} |