Implemented breakpoint service, namely perform these in agent:
breakpoint addition and removal, remove breakpoints from memory read,
run over breakpoint. That should speed up debugging especially stepping.
diff --git a/org.eclipse.cdt.debug.edc.windows.agent/src/WindowsDebugAgent.cpp b/org.eclipse.cdt.debug.edc.windows.agent/src/WindowsDebugAgent.cpp
index 1086893..1a70828 100644
--- a/org.eclipse.cdt.debug.edc.windows.agent/src/WindowsDebugAgent.cpp
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/WindowsDebugAgent.cpp
@@ -18,6 +18,7 @@
#include "RegistersService.h"
#include "MemoryService.h"
#include "LoggingService.h"
+#include "BreakpointsService.h"
#include "EventClientNotifier.h"
#include "Logger.h"
@@ -97,6 +98,14 @@
#endif
try {
+ // For interim test purpose only:
+ // Use this unpublished option to turn off BreakpointsService,
+ // namely use EDC generic breakpoints mechanism.
+ //
+ bool installBpService = true;
+ if (argc > 1 && strcmp(argv[1], "-nobpservice") == 0)
+ installBpService = false;
+
static const char * url = "TCP:";
PeerServer * ps = NULL;
ini_mdep();
@@ -117,6 +126,8 @@
new RegistersService(proto);
new MemoryService(proto);
new LoggingService(proto);
+ if (installBpService)
+ new BreakpointsService(proto);
ps = channel_peer_from_url(url);
diff --git a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/BreakpointsService.cpp b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/BreakpointsService.cpp
new file mode 100644
index 0000000..ef1ff6e
--- /dev/null
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/BreakpointsService.cpp
@@ -0,0 +1,304 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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 "BreakpointsService.h"
+#include "ContextManager.h"
+
+#include <string>
+
+#include "TCFHeaders.h"
+#include "TCFChannel.h"
+
+#include "AgentUtils.h"
+#include "ContextManager.h"
+#include "EventClientNotifier.h"
+#include "Logger.h"
+
+#include "WinProcess.h"
+#include "WinThread.h"
+
+static const char * sServiceName = "Breakpoints";
+
+static const unsigned char sBreakInst = 0xCC;
+
+bool BreakpointsService::sServiceInstalled = false;
+
+//
+// The static function reads the context ids for a breakpoint
+//
+static void read_id_array(InputStream* inp, void* arg)
+{
+ TCFInputStream inpStream(inp);
+ std::vector<std::string>* ids = (std::vector<std::string>*)(arg);
+ std::string str = inpStream.readString();
+ ids->push_back(str);
+}
+
+//
+// This static function is used to read all the breakpoint properties or attributes
+//
+static void read_breakpoint_attr(InputStream * inp, const char * nm, void * arg)
+{
+ TCFInputStream inpStream(inp);
+ TBreakpoint * attrs = (TBreakpoint*)arg;
+
+ if (strcmp(nm, "Location") == 0)
+ {
+ std::string location(inpStream.readString());
+ // atoi fails on large unsigned ints.
+ // this will also handle negative numbers, though.
+ sscanf(location.c_str(), "%u", (unsigned int*)&attrs->address);
+ return;
+ }
+
+ if (strcmp(nm, "ContextIds") == 0)
+ {
+ json_read_array(inp,read_id_array,&attrs->iContextIds);
+ return;
+ }
+
+ if (strcmp(nm, "ID") == 0)
+ {
+ attrs->hostBreakPointId = inpStream.readString();
+ return;
+ }
+
+ if (strcmp(nm, "Enabled") == 0)
+ {
+ attrs->enabled = json_read_boolean(inp);
+ return;
+ }
+
+ json_skip_object(inp);
+}
+
+//
+// BreakpointService::BreakpointService()
+//
+BreakpointsService::BreakpointsService(Protocol * proto)
+ :TCFService(proto)
+{
+ AddCommand("add", CommandAddBreakpoint);
+ AddCommand("remove", CommandRemoveBreakpoint);
+
+ sServiceInstalled = true;
+}
+
+//
+// static function to get the service name
+//
+const char* BreakpointsService::GetName()
+{
+ return sServiceName;
+}
+
+//
+// BreakpointService::CommandAddBreakpoint()
+//
+void BreakpointsService::CommandAddBreakpoint(const char * token, Channel * c)
+{
+ LogTrace("BreakpointService::command_add_Breakpoint", "token: %s", token);
+
+ TCFChannel channel(c);
+ TBreakpoint* breakInfo = new TBreakpoint();
+ json_read_struct(&c->inp, read_breakpoint_attr, breakInfo);
+
+ channel.readZero();
+ channel.readComplete();
+
+ // EDC in 3.x > 20100831 will pass a thread-specific bp (if known) at the end of the list.
+ // For now we stick with process-specific breakpoints.
+ // TODO: see if we want thread-specific breakpoints in the future.
+ std::string contextID = breakInfo->iContextIds.front();
+
+ Context* context = ContextManager::findContext(contextID);
+
+ RunControlContext* thread_context = 0;
+ WinProcess* proc_context = 0;
+
+ if ((proc_context = dynamic_cast<WinProcess*>(context)) != NULL)
+ {
+ // id is a process
+ }
+ else if ((thread_context = dynamic_cast<WinThread*>(context)) != NULL)
+ {
+ // id is a thread
+ proc_context = dynamic_cast<WinProcess*>(ContextManager::findContext(
+ thread_context->GetParentID()));
+ }
+
+ if (!proc_context || !proc_context->IsDebugging())
+ {
+ channel.writeCompleteReply(token, ERR_INV_CONTEXT);
+ return;
+ }
+
+ // "thread_context" is not required.
+ if (thread_context && !thread_context->IsDebugging())
+ {
+ channel.writeCompleteReply(token, ERR_INV_CONTEXT);
+ return;
+ }
+
+ if (!breakInfo->enabled)
+ {
+ trace(LOG_ALWAYS, "!!! cannot set disabled breakpoints");
+ channel.writeCompleteReply(token, ERR_UNSUPPORTED);
+ return;
+ }
+
+ breakInfo->procHandle = proc_context->GetProcessHandle();
+
+ int err = InsertBreak(breakInfo);
+
+ if( err == 0)
+ {
+ trace(LOG_ALWAYS, "Breakpoint added for ID = %s", breakInfo->hostBreakPointId.c_str());
+ sBreakPointMap[breakInfo->hostBreakPointId] = breakInfo;
+ }
+
+ channel.writeCompleteReply(token, err);
+}
+
+//
+// BreakpointService::CommandRemoveBreakpoint()
+//
+void BreakpointsService::CommandRemoveBreakpoint(const char * token, Channel * c)
+{
+ LogTrace("BreakpointService::command_remove_Breakpoint", "token: %s", token);
+
+ TCFChannel channel(c);
+ int err = 0;
+ int overallError = 0;
+ std::vector<std::string> breakIdList;
+ json_read_array(&c->inp, read_id_array, &breakIdList);
+
+ channel.readZero();
+ channel.readComplete();
+
+ std::vector<std::string>::iterator iter ;
+ for(iter = breakIdList.begin(); iter != breakIdList.end(); )
+ {
+ TID2BreakpointMap::iterator it = sBreakPointMap.find(*iter++);
+ if (it == sBreakPointMap.end())
+ {
+ if (!overallError)
+ overallError = ERR_OTHER;
+ continue;
+ }
+
+ TBreakpoint* bp = it->second;
+ sBreakPointMap.erase(it->first);
+
+ err = ClearBreak(bp);
+
+ delete bp;
+
+ // ignore "not found" from the driver, since some breakpoints
+ // are removed automatically on process kill / detach / etc.
+ if (err != 0 && err != ERR_OTHER && !overallError)
+ overallError = err;
+ }
+
+ channel.writeCompleteReply(token, overallError);
+}
+
+/*
+ * Is the Breakpoints service installed in the agent ?
+ */
+bool BreakpointsService::ServiceInstalled()
+{
+ return sServiceInstalled;
+}
+
+/*
+ * Insert a software breakpoint in a process.
+ */
+int BreakpointsService::InsertBreak(const TBreakpoint* bpInfo)
+{
+ // save byte at breakpoint address.
+ if (! ReadProcessMemory(bpInfo->procHandle, (LPCVOID)bpInfo->address, (LPVOID)&bpInfo->originalByte, 1, NULL))
+ return GetLastError();
+
+ // write breakpoint (INT3) to memory
+ if (! WriteProcessMemory(bpInfo->procHandle, (LPVOID)bpInfo->address, (LPVOID)&sBreakInst, 1, NULL))
+ return GetLastError();
+
+ // make sure original instruction isn't already in cache
+ if (! FlushInstructionCache(bpInfo->procHandle, (LPCVOID) bpInfo->address, 1))
+ return GetLastError();
+
+ return 0;
+}
+
+/*
+ * Clear a breakpoint from a process.
+ */
+int BreakpointsService::ClearBreak(const TBreakpoint* bpInfo)
+{
+ // write breakpoint (INT3) to memory
+ if (! WriteProcessMemory(bpInfo->procHandle, (LPVOID)bpInfo->address, (LPVOID)&bpInfo->originalByte, 1, NULL))
+ return GetLastError();
+
+ // make sure bp instruction isn't already in cache
+ if (! FlushInstructionCache(bpInfo->procHandle, (LPCVOID) bpInfo->address, 1))
+ return GetLastError();
+
+ return 0;
+}
+
+/*
+ * find if there's a breakpoint at the given address in a process.
+ */
+TBreakpoint* BreakpointsService::FindBreakpointByAddress(HANDLE processHandle, unsigned long address)
+{
+ TID2BreakpointMap::iterator iter;
+ for (iter = sBreakPointMap.begin(); iter != sBreakPointMap.end(); iter++) {
+ TBreakpoint* bp = iter->second;
+ if (processHandle == bp->procHandle && // same process
+ address == bp->address)
+ return bp;
+ }
+ return NULL;
+}
+
+/*
+ * Given a memory buffer read from a process, remove any breakpoint instructions added by debugger in the buffer.
+ */
+void BreakpointsService::RemoveBreakpointsFromMemoryRead(HANDLE processHandle, ContextAddress address, char* memBuffer, unsigned long size)
+{
+ TID2BreakpointMap::iterator iter;
+ for (iter = sBreakPointMap.begin(); iter != sBreakPointMap.end(); iter++) {
+ TBreakpoint* bp = iter->second;
+ if (processHandle == bp->procHandle && // same process
+ address <= bp->address && address+size > bp->address) // bp falls in the buffer
+ {
+ char *byteToChange = memBuffer + (bp->address - address);
+ *byteToChange = bp->originalByte;
+ }
+ }
+}
+
+/*
+ * Given a memory buffer that has been writen to a process, re-inssert any breakpoints in the buffer range.
+ */
+void BreakpointsService::ReInsertBreakpointsAfterMemoryWrite(HANDLE processHandle, ContextAddress address, char* memBuffer, unsigned long size)
+{
+ TID2BreakpointMap::iterator iter;
+ for (iter = sBreakPointMap.begin(); iter != sBreakPointMap.end(); iter++) {
+ TBreakpoint* bp = iter->second;
+ if (processHandle == bp->procHandle && // same process
+ address <= bp->address && address+size > bp->address) // bp falls in the buffer
+ {
+ InsertBreak(bp);
+ }
+ }
+}
diff --git a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/BreakpointsService.h b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/BreakpointsService.h
new file mode 100644
index 0000000..92783dc
--- /dev/null
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/BreakpointsService.h
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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
+ *******************************************************************************/
+
+#ifndef BREAKPOINTSERVICE_H_
+#define BREAKPOINTSERVICE_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "TCFService.h"
+#include "TCFContext.h"
+
+struct Protocol;
+struct Channel;
+
+//
+// To store the breakpoint info
+//
+struct TBreakpoint
+{
+ std::vector<std::string> iContextIds;
+ HANDLE procHandle; // Win32 handle of the hosting process
+ std::string hostBreakPointId; // breakpoint ID from host debugger.
+ ContextAddress address;
+ bool enabled;
+ unsigned char originalByte; // original byte where we set the bp.
+
+ TBreakpoint(): address(0), enabled(true), originalByte(0)
+ {}
+};
+
+typedef std::map<std::string, TBreakpoint*> TID2BreakpointMap;
+
+/*
+ * A list of breakpoints in all processes in the debug session.
+ */
+static TID2BreakpointMap sBreakPointMap;
+
+//
+// Breakpoint service implementation
+//
+class BreakpointsService: public TCFService
+{
+public:
+ BreakpointsService(Protocol * proto);
+
+ const char* GetName();
+
+ static void CommandAddBreakpoint(const char *, Channel *);
+ static void CommandRemoveBreakpoint(const char *, Channel *);
+
+ static int InsertBreak(const TBreakpoint* bpInfo);
+ static int ClearBreak(const TBreakpoint* bpInfo);
+
+ static TBreakpoint* FindBreakpointByAddress(HANDLE processHandle, unsigned long address);
+ static void RemoveBreakpointsFromMemoryRead(HANDLE, ContextAddress, char*, unsigned long);
+ static void ReInsertBreakpointsAfterMemoryWrite(HANDLE, ContextAddress, char*, unsigned long);
+
+ static bool ServiceInstalled();
+
+private:
+ static bool sServiceInstalled;
+};
+
+
+#endif /* BREAKPOINTSERVICE_H_ */
diff --git a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/ResumeContextAction.cpp b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/ResumeContextAction.cpp
index 925113a..3ee5f1e 100644
--- a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/ResumeContextAction.cpp
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/ResumeContextAction.cpp
@@ -13,18 +13,67 @@
#include "WinProcess.h"
#include "WinThread.h"
#include "WinDebugMonitor.h"
+#include "RunControlService.h"
+#include "BreakpointsService.h"
-ResumeContextAction::ResumeContextAction(const AgentActionParams& params, ContextOSID processid,
- ContextOSID threadid) : AgentAction(params) {
- processid_ = processid;
- threadid_ = threadid;
+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() {
- ContinueDebugEvent(processid_, threadid_, DBG_CONTINUE);
+ // 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();
+
+ ContinueDebugEvent(process_.GetOSID(), thread_.GetOSID(), DBG_CONTINUE);
+
+ // 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.
+ }
}
diff --git a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/ResumeContextAction.h b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/ResumeContextAction.h
index 7e57b58..2e4c1de 100644
--- a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/ResumeContextAction.h
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/ResumeContextAction.h
@@ -11,17 +11,19 @@
#pragma once
#include "AgentAction.h"
#include "TCFContext.h"
+#include "WinProcess.h"
+#include "WinThread.h"
class ResumeContextAction: public AgentAction {
public:
- ResumeContextAction(const AgentActionParams& params, ContextOSID processid, ContextOSID threadid);
+ ResumeContextAction(const AgentActionParams& params, WinProcess& process, WinThread& thread, long resumeMode);
virtual ~ResumeContextAction(void);
void Run();
private:
- ContextOSID processid_;
- ContextOSID threadid_;
-
+ WinProcess& process_;
+ WinThread& thread_;
+ long resumeMode_;
};
diff --git a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinDebugMonitor.h b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinDebugMonitor.h
index 9cedef8..aed6d0a 100644
--- a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinDebugMonitor.h
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinDebugMonitor.h
@@ -77,10 +77,11 @@
static std::string GetDebugExceptionDescription(const EXCEPTION_DEBUG_INFO& exceptionInfo);
+ void HandleDebugEvent(DEBUG_EVENT& debugEvent);
+
private:
void AttachToProcessForDebug();
- void HandleDebugEvent(DEBUG_EVENT& debugEvent);
void HandleNoDebugEvent();
void HandleExceptionEvent(DEBUG_EVENT& debugEvent);
diff --git a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinProcess.cpp b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinProcess.cpp
index 40f82e4..9ae67e9 100644
--- a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinProcess.cpp
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinProcess.cpp
@@ -20,6 +20,7 @@
#include "ProtocolConstants.h"
#include "RunControlService.h"
#include "ContextManager.h"
+#include "BreakpointsService.h"
std::map<int, WinProcess*> WinProcess::processIDMap;
@@ -101,13 +102,14 @@
}
int WinProcess::ReadMemory(const ReadWriteMemoryParams& params) throw (AgentException) {
- // to do: handle breakpoints and watchpoints
int result = 0;
boolean success = ReadProcessMemory(processHandle_, (LPCVOID) params.address,
params.memBuffer, params.size, params.sizeTransferred);
if (!success)
result = GetLastError();
+ else
+ BreakpointsService::RemoveBreakpointsFromMemoryRead(processHandle_, params.address, params.memBuffer, params.size);
return result;
}
@@ -120,7 +122,9 @@
params.memBuffer, params.size, params.sizeTransferred);
if (!success)
result = GetLastError();
-
+ else {
+ BreakpointsService::ReInsertBreakpointsAfterMemoryWrite(processHandle_, params.address, params.memBuffer, params.size);
+ }
return result;
}
diff --git a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinThread.cpp b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinThread.cpp
index 63d33fc..811b235 100644
--- a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinThread.cpp
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinThread.cpp
@@ -21,6 +21,7 @@
#include "ResumeContextAction.h"
#include "ProtocolConstants.h"
#include "RunControlService.h"
+#include "BreakpointsService.h"
std::map<std::pair<int, int>, WinThread*> WinThread::threadIDMap_;
@@ -121,11 +122,41 @@
MarkSuspended();
exceptionInfo_ = debugEvent.u.Exception;
EnsureValidContextInfo();
+ AdjustPC();
EventClientNotifier::SendContextSuspended(this,
GetPCAddress(), GetSuspendReason(), GetExceptionMessage());
}
+/*
+ * Check if the program is stopped due to a software breakpoint
+ * installed by the agent, if yes, move PC back by one byte.
+ */
+void WinThread::AdjustPC() {
+ // Bail out if the agent does not install & manage
+ // breakpoints (namely the EDC host uses generic
+ // software breakpoint mechanism).
+ if (! BreakpointsService::ServiceInstalled())
+ return;
+
+ /*
+ * Check
+ * 1. Did we stop due to a breakpoint exception ?
+ * -- This is to prevent adjusting PC for other exceptions such as
+ * divide-by-zero & invalid code.
+ * 2. is there a software breakpoint at the byte right before the PC?
+ * -- this is to exclude the case of user-inserted "int 3" instruction.
+ */
+ if (exceptionInfo_.ExceptionRecord.ExceptionCode != EXCEPTION_BREAKPOINT)
+ return;
+
+ ContextAddress pc = GetPCAddress();
+ pc--;
+ if (NULL != BreakpointsService::FindBreakpointByAddress(parentProcess_.GetProcessHandle(), pc)) {
+ SetRegisterValue("EIP", 4, (char*)&pc);
+ }
+}
+
void WinThread::HandleExecutableEvent(bool isLoaded, const std::string& exePath,
unsigned long baseAddress, unsigned long codeSize) {
MarkSuspended();
@@ -412,20 +443,23 @@
}
else {
parentProcess_.GetMonitor()->PostAction(new ResumeContextAction(
- params, parentProcess_.GetOSID(), GetOSID()));
+ params, parentProcess_, *this, RM_RESUME));
}
}
-void WinThread::SingleStep(const AgentActionParams& params) throw (AgentException) {
- //if (exceptionInfo_.ExceptionRecord.ExceptionCode == USER_SUSPEND_THREAD){
- // ResumeThread(handle_);
- //}
+/*
+ * Enable single instruction step by setting Trap Flag (TF) bit.
+ */
+void WinThread::EnableSingleStep() {
#define FLAG_TRACE_BIT 0x100
+ // The bit will be auto-cleared after next resume.
threadContextInfo_.EFlags |= FLAG_TRACE_BIT;
SetThreadContext(handle_, &threadContextInfo_);
+}
+void WinThread::SingleStep(const AgentActionParams& params) throw (AgentException) {
parentProcess_.GetMonitor()->PostAction(new ResumeContextAction(
- params, parentProcess_.GetOSID(), GetOSID()));
+ params, parentProcess_, *this, RM_STEP_INTO));
}
void WinThread::PrepareForTermination(const AgentActionParams& params) throw (AgentException) {
diff --git a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinThread.h b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinThread.h
index b9d7b85..57a0270 100644
--- a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinThread.h
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinThread.h
@@ -57,6 +57,11 @@
void HandleExecutableEvent(bool isLoaded, const std::string& exePath,
unsigned long baseAddress, unsigned long codeSize);
+ /** Address where suspend is reported */
+ ContextAddress GetPCAddress();
+
+ void EnableSingleStep();
+
private:
void initialize();
@@ -65,8 +70,8 @@
bool isSuspended();
void MarkSuspended();
- /** Address where suspend is reported */
- ContextAddress GetPCAddress();
+ void AdjustPC();
+
/** REASON_xx code for suspend */
const char* GetSuspendReason();
/** Description for suspend */