Kirk's latest work on watchpoints.
diff --git a/org.eclipse.cdt.debug.edc.windows.agent/src/tcf_agent/framework/errors.c b/org.eclipse.cdt.debug.edc.windows.agent/src/tcf_agent/framework/errors.c
index 4d74712..1eb6066 100644
--- a/org.eclipse.cdt.debug.edc.windows.agent/src/tcf_agent/framework/errors.c
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/tcf_agent/framework/errors.c
@@ -350,6 +350,12 @@
     case ERR_HWBRK_INVALID_SIZE: return "Invalid size";
     case ERR_HWBRK_NO_RESOURCES: return "No resources available";
     case ERR_HWBRK_NOT_ALIGNED:  return "Invalid address alignment";
+    case ERR_HWBRK_INVALID_MODE: return "Invalid hardware breakpoint mode";
+    case ERR_PGPRO_UNSET:        return "Cannot set page protection";
+    case ERR_PGPRO_UNRESET:      return "Cannot reset page protection";
+    case ERR_PGPRO_UNCHANGED:    return "Cannot change page protection";
+    case ERR_PGPRO_INVALID_MODE: return "Invalid page protection mode";
+    case ERR_PGPRO_NO_ADDR:      return "No page containing address";
     default:
         if (err >= ERR_MESSAGE_MIN && err <= ERR_MESSAGE_MAX) {
             if (is_dispatch_thread()) {
diff --git a/org.eclipse.cdt.debug.edc.windows.agent/src/tcf_agent/framework/errors.h b/org.eclipse.cdt.debug.edc.windows.agent/src/tcf_agent/framework/errors.h
index 80f90f7..bbca6bb 100644
--- a/org.eclipse.cdt.debug.edc.windows.agent/src/tcf_agent/framework/errors.h
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/tcf_agent/framework/errors.h
@@ -56,6 +56,12 @@
 #define ERR_HWBRK_INVALID_SIZE  (STD_ERR_BASE + 30)
 #define ERR_HWBRK_NO_RESOURCES  (STD_ERR_BASE + 31)
 #define ERR_HWBRK_NOT_ALIGNED   (STD_ERR_BASE + 32)
+#define ERR_HWBRK_INVALID_MODE  (STD_ERR_BASE + 33)
+#define ERR_PGPRO_UNSET         (STD_ERR_BASE + 34)
+#define ERR_PGPRO_UNRESET       (STD_ERR_BASE + 35)
+#define ERR_PGPRO_UNCHANGED     (STD_ERR_BASE + 36)
+#define ERR_PGPRO_INVALID_MODE  (STD_ERR_BASE + 37)
+#define ERR_PGPRO_NO_ADDR       (STD_ERR_BASE + 38)
 
 typedef struct ErrorReportItem {
     char * name;
diff --git a/org.eclipse.cdt.debug.edc.windows.agent/src/tcf_agent/services/discovery.c b/org.eclipse.cdt.debug.edc.windows.agent/src/tcf_agent/services/discovery.c
index fa9211f..cb34237 100644
--- a/org.eclipse.cdt.debug.edc.windows.agent/src/tcf_agent/services/discovery.c
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/tcf_agent/services/discovery.c
@@ -59,7 +59,7 @@
     return 0;
 }
 
-static void command_sync(char * token, Channel * c) {
+static void command_sync(const char* token, Channel * c) {
     if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
     write_stringz(&c->out, "R");
     write_stringz(&c->out, token);
@@ -100,7 +100,7 @@
     peer_server_addprop((PeerServer *)x, loc_strdup(name), json_read_alloc_string(inp));
 }
 
-static void command_redirect(char * token, Channel * c) {
+static void command_redirect(const char * token, Channel * c) {
     PeerServer * ps = NULL;
     int free_ps = 0;
 
@@ -135,7 +135,7 @@
     if (free_ps) peer_server_free(ps);
 }
 
-static void command_get_peers(char * token, Channel * c) {
+static void command_get_peers(const char * token, Channel * c) {
     if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
 
     write_stringz(&c->out, "R");
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
index 9a0c180..347d920 100644
--- 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
@@ -22,7 +22,6 @@
 #include "EventClientNotifier.h"

 #include "Logger.h"

 

-#include "WinHWBkptMgr.h"

 #include "WinProcess.h"

 #include "WinThread.h"

 

@@ -32,6 +31,10 @@
 

 bool BreakpointsService::sServiceInstalled = false;

 

+inline bool TBreakpoint::SameProcess(const HANDLE& procH) const

+	{ return process && process->GetProcessHandle() == procH; }

+

+

 //

 // The static function reads the context ids for a breakpoint

 //

@@ -58,11 +61,11 @@
 	if (::strcmp(nm, "BreakpointType") == 0) {

 		std::string type = inpStream.readString();

 		if (type.compare("Auto") == 0) {

-			attrs->bpType = type_Auto;

+			attrs->requestedType = type_Auto;

 		} else if (type.compare("Software") == 0) {

-			attrs->bpType = type_Software;

+			attrs->requestedType = type_Software;

 		} else if (type.compare("Hardware") == 0) {

-			attrs->bpType = type_Hardware;

+			attrs->requestedType = type_Hardware;

 		}

 		return;

 	}

@@ -167,7 +170,7 @@
 	}

 

 	int err;

-	if (ACCESSMODE_EXECUTE == breakInfo->accessMode)

+	if (breakInfo->IsTypeBreakpoint())

 		err = InsertBreak(breakInfo);

 	else

 		err = InsertWatch(breakInfo);

@@ -207,7 +210,7 @@
 		TBreakpoint* bp = it->second;

 		sBreakPointMap.erase(it->first);

 

-		if (ACCESSMODE_EXECUTE == bp->accessMode)

+		if (bp->IsTypeBreakpoint())

 			err = ClearBreak(bp);

 		else

 			err = ClearWatch(bp);

@@ -237,15 +240,17 @@
 	const HANDLE& procHandle = bpInfo->process->GetProcessHandle();

 

 	// save byte at breakpoint address.

-	if (! ::ReadProcessMemory(procHandle, (LPCVOID)bpInfo->address, (LPVOID)&bpInfo->originalByte, 1, NULL))

+	if (FAILED(::ReadProcessMemory(procHandle, (LPCVOID)bpInfo->address,

+								   (LPVOID)&bpInfo->originalByte, 1, NULL)))

 		return ::GetLastError();

 

 	// write breakpoint (INT3) to memory

-	if (! ::WriteProcessMemory(procHandle, (LPVOID)bpInfo->address, (LPVOID)&sBreakInst, 1, NULL))

+	if (FAILED(::WriteProcessMemory(procHandle, (LPVOID)bpInfo->address,

+									(LPVOID)&sBreakInst, 1, NULL)))

 		return ::GetLastError();

 

 	// make sure original instruction isn't already in cache

-	if (! ::FlushInstructionCache(procHandle, (LPCVOID)bpInfo->address, 1))

+	if (FAILED(::FlushInstructionCache(procHandle, (LPCVOID)bpInfo->address, 1)))

 		return ::GetLastError();

 

 	return 0;

@@ -255,14 +260,18 @@
  * Clear a breakpoint from a process.

  */

 int BreakpointsService::ClearBreak(const TBreakpoint* bpInfo) {

+	if (!bpInfo->process)

+		return 0;	// process may have cleaned up after itself upon exit

+

 	const HANDLE& procHandle = bpInfo->process->GetProcessHandle();

 

 	// write original byte back over top of (INT3) in memory

-	if (! ::WriteProcessMemory(procHandle, (LPVOID)bpInfo->address, (LPVOID)&bpInfo->originalByte, 1, NULL))

+	if (FAILED(::WriteProcessMemory(procHandle, (LPVOID)bpInfo->address,

+									(LPVOID)&bpInfo->originalByte, 1, NULL)))

 		return ::GetLastError();

 

 	// make sure bp instruction isn't already in cache

-	if (! ::FlushInstructionCache(procHandle, (LPCVOID)bpInfo->address, 1))

+	if (FAILED(::FlushInstructionCache(procHandle, (LPCVOID)bpInfo->address, 1)))

 		return ::GetLastError();

 

 	return 0;

@@ -271,15 +280,17 @@
 /*

  * establish a hardware watchpoint using the hardware debug registers

  */

-int BreakpointsService::InsertWatch(TBreakpoint* bpInfo) {

-	return WinHWBkptMgr::SetHardwareBreak(bpInfo);

+int BreakpointsService::InsertWatch(TBreakpoint* wpInfo) {

+	return wpInfo->process->SetWatchpoint(wpInfo);

 }

 

 /*

  * clear the hardware debug register for a given watchpoint

  */

-int BreakpointsService::ClearWatch(TBreakpoint* bpInfo) {

-	return WinHWBkptMgr::ClearHardwareBreak(bpInfo);

+int BreakpointsService::ClearWatch(TBreakpoint* wpInfo) {

+	if (!wpInfo->process)

+		return 0;	// process may have cleaned up after itself upon exit

+	return wpInfo->process->ClearWatchpoint(wpInfo);

 }

 

 /*

@@ -290,8 +301,7 @@
 	TID2BreakpointMap::iterator iter;

 	for (iter = sBreakPointMap.begin(); iter != sBreakPointMap.end(); iter++) {

 		TBreakpoint* bp = iter->second;

-		if (ACCESSMODE_EXECUTE == bp->accessMode

-			&& bp->process && processHandle == bp->process->GetProcessHandle()	// same process

+		if (bp->IsTypeBreakpoint() && bp->SameProcess(processHandle)

 			&& address == bp->address)

 		{

 			return bp;

@@ -310,8 +320,7 @@
 	TID2BreakpointMap::iterator iter;

 	for (iter = sBreakPointMap.begin(); iter != sBreakPointMap.end(); iter++) {

 		TBreakpoint* wp = iter->second;

-		if (ACCESSMODE_EXECUTE != wp->accessMode

-			&& wp->process && processHandle == wp->process->GetProcessHandle()	// same process

+		if (wp->IsTypeWatchpoint() && wp->SameProcess(processHandle)

 			&& wp->address <= address && address < wp->address+wp->size)

 		{

 			return wp;

@@ -321,7 +330,9 @@
 }

 

 /*

- * Given a memory buffer read from a process, remove any breakpoint instructions added by debugger in the buffer.

+ * Given a memory buffer read from a process, remove any breakpoint

+ * instructions added by debugger in the buffer.

+ * ASSUMPTION: caller has temporarily diabled page-protection if necessary

  */

 void BreakpointsService::RemoveBreakpointsFromMemoryRead(

 		const HANDLE& processHandle, ContextAddress address, char* memBuffer,

@@ -329,8 +340,7 @@
 	TID2BreakpointMap::iterator iter;

 	for (iter = sBreakPointMap.begin(); iter != sBreakPointMap.end(); iter++) {

 		TBreakpoint* bp = iter->second;

-		if (ACCESSMODE_EXECUTE == bp->accessMode

-			&& bp->process && processHandle == bp->process->GetProcessHandle()	// same process

+		if (bp->IsTypeBreakpoint() && bp->SameProcess(processHandle)

 			&& address <= bp->address && address+size > bp->address)	// bp falls in the buffer

 		{

 			char *byteToChange = memBuffer + (bp->address - address);

@@ -340,7 +350,9 @@
 }

 

 /*

- * Given a memory buffer that has been writen to a process, re-inssert any breakpoints in the buffer range.

+ * Given a memory buffer that has been writen to a process,

+ * re-inssert any breakpoints in the buffer range.

+ * ASSUMPTION: caller has temporarily diabled page-protection if necessary

  */

 void BreakpointsService::ReInsertBreakpointsAfterMemoryWrite(

 		const HANDLE& processHandle, ContextAddress address, char* memBuffer,

@@ -348,11 +360,23 @@
 	TID2BreakpointMap::iterator iter;

 	for (iter = sBreakPointMap.begin(); iter != sBreakPointMap.end(); iter++) {

 		TBreakpoint* bp = iter->second;

-		if (ACCESSMODE_EXECUTE == bp->accessMode

-			&& bp->process && processHandle == bp->process->GetProcessHandle()	// same process

+		if (bp->IsTypeBreakpoint() && bp->SameProcess(processHandle)

 			&& address <= bp->address && address+size > bp->address)	// bp falls in the buffer

 		{

 			InsertBreak(bp);

 		}

 	}

 }

+

+

+int BreakpointsService::RemoveProcessFromBreakpoints(const WinProcess* process) {

+	TID2BreakpointMap::iterator iter;

+	for (iter = sBreakPointMap.begin(); iter != sBreakPointMap.end(); iter++) {

+		TBreakpoint*& bp = iter->second;

+		if (bp && bp->process == process) {

+			bp->process = NULL;

+			bp->agentBreakID = AGENT_BREAK_UNSET;

+		}

+	}

+	return 0;

+}

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
index adb3740..f5a4e8f 100644
--- 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
@@ -36,8 +36,8 @@
 	ACCESSMODE_CHANGE	= 0x08,

 };

 

-typedef unsigned char HWBreakID;

-#define HWBREAK_NOT_SET 0

+typedef short AgentBreakID;	// 32768 ought to be enough watchpoints

+#define	AGENT_BREAK_UNSET (-1)

 

 //

 // To store the breakpoint info

@@ -51,17 +51,24 @@
 	unsigned char originalByte;	// original byte where we set the bp.

 	unsigned char size;			// for windows-x86, max is well below 255

 

-	TCFBreakpointType	bpType;	// ignored; always software for bkpt

-								// and always hardware for watchpoint

+	TCFBreakpointType	requestedType;

+	TCFBreakpointType	actualType;

 

 	TCFAccessMode		accessMode;	// _EXECUTE means bkpt; o/w -> watchpoint

-	HWBreakID			hwBreakID;

+	AgentBreakID		agentBreakID;

 

 	TBreakpoint()

 	  : process(NULL), address(0), enabled(true), originalByte(0),

-		size(0), bpType(type_Auto), accessMode(ACCESSMODE_READ),

-		hwBreakID(HWBREAK_NOT_SET)

+		size(0), requestedType(type_Auto), actualType(type_Auto),

+		accessMode(ACCESSMODE_READ), agentBreakID(AGENT_BREAK_UNSET)

 	{}

+

+	bool SameProcess(const HANDLE& procH) const;

+

+	inline bool IsTypeBreakpoint() const

+		{ return ACCESSMODE_EXECUTE == accessMode; }

+	inline bool IsTypeWatchpoint() const

+		{ return ACCESSMODE_EXECUTE != accessMode; }

 };

 

 typedef std::map<std::string, TBreakpoint*> TID2BreakpointMap;

@@ -89,6 +96,8 @@
 	static int InsertWatch(TBreakpoint*);

 	static int ClearWatch(TBreakpoint*);

 

+	static int RemoveProcessFromBreakpoints(const WinProcess*);

+

 	static TBreakpoint* FindBreakpointByAddress(const HANDLE& processHandle,

 			const ContextAddress);

 	static TBreakpoint* FindWatchpointByAddress(const HANDLE& processHandle,

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 421f090..68d6563 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
@@ -32,15 +32,16 @@
 void ResumeContextAction::Run() {

 	// Single step over a breakpoint (if any) at current PC.

 	//

-	TBreakpoint* bpAtStartAddress = BreakpointsService::FindBreakpointByAddress(process_.GetProcessHandle(), thread_.GetPCAddress());

+	TBreakpoint* bpAtStartAddress

+	   = BreakpointsService::FindBreakpointByAddress(process_.GetProcessHandle(), thread_.GetPCAddress());

 	if (bpAtStartAddress) {

 		BreakpointsService::ClearBreak(bpAtStartAddress);

 		thread_.EnableSingleStep();

-	}

-	else if (resumeMode_ == RM_STEP_INTO)

+	} else if (resumeMode_ == RM_STEP_INTO)

 		thread_.EnableSingleStep();

 

-	ContinueDebugEvent(process_.GetOSID(), thread_.GetOSID(), thread_.GetContinueStatus());

+	thread_.MarkResumed();

+	::ContinueDebugEvent(process_.GetOSID(), thread_.GetOSID(), thread_.GetContinueStatus());

 

 	// notify host the Resume action is done before

 	// any suspend event is reported.

@@ -49,7 +50,7 @@
 	if (bpAtStartAddress) {

 		DEBUG_EVENT debugEvent;

 

-		if (WaitForDebugEvent(&debugEvent, 200 /* ms */)) {

+		if (::WaitForDebugEvent(&debugEvent, 200 /* ms */)) {

 			// Done executing single instruction.

 			BreakpointsService::InsertBreak(bpAtStartAddress);	// restore the bp

 

@@ -57,23 +58,18 @@
 				if (resumeMode_ == RM_STEP_INTO)

 					// single-step done, report suspend event to host.

 					process_.GetMonitor()->HandleDebugEvent(debugEvent);

-				else {

+				else

 					// other resume modes

 					// Ignore the SINGLE_STEP event, go on to Resume again

-					ContinueDebugEvent(process_.GetOSID(), thread_.GetOSID(), DBG_CONTINUE);

-				}

-			}

-			else {

+					::ContinueDebugEvent(process_.GetOSID(), thread_.GetOSID(), DBG_CONTINUE);

+			} else {

 				// Other exceptions

 				// Handle the event, say, report to host.

 				process_.GetMonitor()->HandleDebugEvent(debugEvent);

 			}

-		}

-		else {

+		} else {

 			trace(LOG_ALWAYS, "Failed to execute one instruction. Error: %d", GetLastError());

 		}

 	}

-	else {

-		// the event loop of monitor thread would catch and report event.

-	}

+	// 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/SettingsService.cpp b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/SettingsService.cpp
index 0ec7b51..0a682ad 100644
--- a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/SettingsService.cpp
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/SettingsService.cpp
@@ -213,9 +213,9 @@
 	return enableDebugStringLogging;

 }

 

-bool SettingsService::reportExceptionEvent(const DEBUG_EVENT& debugEvent)

+bool SettingsService::reportExceptionEvent(const EXCEPTION_DEBUG_INFO& excInfo)

 {

-	switch (debugEvent.u.Exception.ExceptionRecord.ExceptionCode) {

+	switch (excInfo.ExceptionRecord.ExceptionCode) {

 

 	// as a debugger we always report these

 	case EXCEPTION_SINGLE_STEP:

@@ -282,8 +282,9 @@
 		// it's not one of the typical exceptions and we have no setting for it.

 		// if it's first chance, don't report it.  give it back for the process/os

 		// to handle.  otherwise we'll report it to the debugger.

-	    trace(LOG_ALWAYS, "\t -- first chance:%d, flags:%d", debugEvent.u.Exception.dwFirstChance, debugEvent.u.Exception.ExceptionRecord.ExceptionFlags);

-		if (debugEvent.u.Exception.dwFirstChance)

+	    trace(LOG_ALWAYS, "\t -- first chance:%d, flags:0x8.8%x",

+	    	  excInfo.dwFirstChance, excInfo.ExceptionRecord.ExceptionFlags);

+		if (excInfo.dwFirstChance)

 			return false;

 	}

 

diff --git a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/SettingsService.h b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/SettingsService.h
index 151dccb..e80568b 100644
--- a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/SettingsService.h
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/SettingsService.h
@@ -36,6 +36,6 @@
 

 	static bool reportDebugEventForModule(std::string module);

 	static bool reportDebugStringEvents();

-	static bool reportExceptionEvent(const DEBUG_EVENT& debugEvent);

+	static bool reportExceptionEvent(const EXCEPTION_DEBUG_INFO&);

 	static void debugSessionEnds();

 };

diff --git a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinDebugMonitor.cpp b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinDebugMonitor.cpp
index 1379b35..32c63d3 100644
--- a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinDebugMonitor.cpp
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinDebugMonitor.cpp
@@ -537,14 +537,12 @@
 

 void WinDebugMonitor::HandleExceptionEvent(DEBUG_EVENT& debugEvent)

 {

-	EXCEPTION_RECORD &e = debugEvent.u.Exception.ExceptionRecord;

+	const EXCEPTION_DEBUG_INFO& excInfo = debugEvent.u.Exception;

+	const EXCEPTION_RECORD& e = excInfo.ExceptionRecord;

+	const DWORD& excCode = e.ExceptionCode;

 	LogTrace("DebugProcessMonitor::HandleExceptionEvent", "Exception in thread %d at 0x%x: code 0x%x (%s)",

 			debugEvent.dwThreadId, e.ExceptionAddress, e.ExceptionCode,

-			GetDebugExceptionDescription(debugEvent.u.Exception).c_str());

-

-    WinThread* thread = WinThread::GetThreadByID(debugEvent.dwProcessId, debugEvent.dwThreadId);

-	if (!thread)

-		assert(false);

+			GetDebugExceptionDescription(excInfo).c_str());

 

 	// ignore initial breakpoint in NTDLL!DbgBreakPoint for newly launched process if necessary

 	if (!handledInitialDebugBreakpoint && e.ExceptionCode == EXCEPTION_BREAKPOINT)

@@ -557,12 +555,38 @@
 		return;

 	}

 

-	if (thread && SettingsService::reportExceptionEvent(debugEvent))

+	bool potentialProtectedPage = excCode == EXCEPTION_ACCESS_VIOLATION;

+	bool reportException = SettingsService::reportExceptionEvent(excInfo);

+	bool handled = false;

+	if (reportException || potentialProtectedPage)

 	{

-	    trace(LOG_ALWAYS, "\t -- reported to host debugger.");

-		thread->HandleException(debugEvent);

+		// wait to search for a threadByID until necessary

+		WinThread* thread = WinThread::GetThreadByID(debugEvent.dwProcessId, debugEvent.dwThreadId);

+		if (!thread)

+			assert(false);

+

+		if (thread && potentialProtectedPage)

+		{

+			trace(LOG_ALWAYS, "\t -- checking potential protected page.");

+			handled = thread->HandlePotentialProtctedPage(debugEvent);

+		}

+

+		if (thread && !handled)

+		{

+			if (reportException)

+			{

+				trace(LOG_ALWAYS, "\t -- reported to host debugger.");

+				thread->HandleException(debugEvent);

+				handled = true;

+			}

+			else

+			{

+				thread->MarkResumed();

+			}

+		}

 	}

-	else

+

+	if (!handled)

 	{

 		trace(LOG_ALWAYS, "\t -- ignored.");

 		// Note DBG_EXCEPTION_NOT_HANDLED is used here.

diff --git a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinHWBkptMgr.cpp b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinHWBkptMgr.cpp
index 74f70d4..3c3e7b1 100644
--- a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinHWBkptMgr.cpp
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinHWBkptMgr.cpp
@@ -64,18 +64,14 @@
 #include "WinProcess.h"

 #include "WinThread.h"

 

-static const WinHWBkptMgr::Mode

-  sDR7ModeBitsMap[9]

-	= { WinHWBkptMgr::invalid,

-		WinHWBkptMgr::invalid,

-		WinHWBkptMgr::write,

-		WinHWBkptMgr::readwrite,

-		WinHWBkptMgr::execute,

-		WinHWBkptMgr::invalid,

-		WinHWBkptMgr::invalid,

-		WinHWBkptMgr::invalid,

-		WinHWBkptMgr::invalid

-	  };

+inline

+WinHWBkptMgr::Mode WinHWBkptMgr::sDR7ModeBitsMap(unsigned char i) {

+static const Mode map[9]

+  = { invalid, invalid, write, readwrite, execute,

+		  	   invalid, invalid, invalid, invalid

+    };

+	return map[i];

+}

 

 // invalid bits in the following 2 masks

 #define XFF 0xFF

@@ -96,9 +92,12 @@
 #define SB4 0x0C

 #define SB8 0x08

 

-static const WinHWBkptMgr::SizeBits

-  sDR7SizeBitsMap[9]

-	= {XFF, SB1, SB2, XFF, SB4, XFF, XFF, XFF, SB8};

+inline

+WinHWBkptMgr::SizeBits WinHWBkptMgr::sDR7SizeBitsMap(unsigned char i) {

+static const WinHWBkptMgr::SizeBits map[9]

+  = {XFF, SB1, SB2, XFF, SB4, XFF, XFF, XFF, SB8};

+	return map[i];

+}

 

 /*

  * the following table represents a mapping of

@@ -158,8 +157,9 @@
 		{  4,XFF,XFF,XFF,XFF,XFF,XFF,XFF},	// 32

 	  };

 

-WinHWBkptMgr::DRMask WinHWBkptMgr::inUse = 0;

-WinHWBkptMgr::HWBreakInfo WinHWBkptMgr::hwBkpt[4];

+WinHWBkptMgr::WinHWBkptMgr() {

+	inUse = 0;

+}

 

 unsigned char WinHWBkptMgr::InUseCount() {

 	return (DR0 & inUse)

@@ -198,6 +198,12 @@
 		return ERR_HWBRK_NOT_SET;

 	}

 

+	if (bp->accessMode > ACCESSMODE_CHANGE)

+		return ERR_HWBRK_INVALID_MODE;

+	Mode hwMode = sDR7ModeBitsMap(bp->accessMode);

+	if (hwMode == invalid)

+		return ERR_HWBRK_INVALID_MODE;

+

 	unsigned char locSize = bp->size;

 	if (locSize > 32)

 		return ERR_HWBRK_INVALID_SIZE;

@@ -212,9 +218,10 @@
 		return ERR_HWBRK_NO_RESOURCES;

 

 	unsigned char wp = GetUnusedWatchpoint();

-	hwBkpt[wp].address = locAddr;

-	hwBkpt[wp].size = locSize;

-	hwBkpt[wp].accessMode = sDR7ModeBitsMap[bp->accessMode];

+	if (wp == XFF)	// shouldn't happen with inUse check above

+		return ERR_HWBRK_NO_RESOURCES;

+	hwBkpt[wp].tcfBp = bp;

+	hwBkpt[wp].accessMode = hwMode;

 	for (;reqdRegs > 0;--reqdRegs) {

 		DRMask dr = UseUnusedRegister();

 		hwBkpt[wp].inUse |= dr;

@@ -231,7 +238,7 @@
 		}

 

 		// these are shifted inside based on the reg used

-		DRFlags dr7bits = sDR7SizeBitsMap[drSz] | hwBkpt[wp].accessMode;

+		DRFlags dr7bits = sDR7SizeBitsMap(drSz) | hwBkpt[wp].accessMode;

 

 		bp->process->SetDebugRegister(dr, locAddr, dr7bits);

 

@@ -239,14 +246,16 @@
 		locSize -= drSz;

 	}

 

-	bp->hwBreakID = wp;

+	bp->agentBreakID = wp;

 	return 0;

 }

 

 int WinHWBkptMgr::ClearHardwareBreak(TBreakpoint* bp) {

 	if (!bp->process)

 		return ERR_INV_CONTEXT;

-	unsigned char& wp = bp->hwBreakID;

+	AgentBreakID& wp = bp->agentBreakID;

+	if (wp == AGENT_BREAK_UNSET)

+		return ERR_HWBRK_NOT_SET;

 	for (int i = 0; i < MAX_HWBP; ++i) {

 		DRMask dr = 1 << i;

 		if (hwBkpt[wp].inUse & dr) {

@@ -255,7 +264,9 @@
 		}

 	}

 

+	hwBkpt[wp].tcfBp = NULL;

+	hwBkpt[wp].inUse = 0;

 	bp->process = NULL;

-	wp = 0;

+	wp = AGENT_BREAK_UNSET;

 	return 0;

 }

diff --git a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinHWBkptMgr.h b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinHWBkptMgr.h
index eee839e..930f303 100644
--- a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinHWBkptMgr.h
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinHWBkptMgr.h
@@ -65,42 +65,44 @@
 struct TBreakpoint;

 

 class WinHWBkptMgr {

-  public:

+

+	friend class WinProcess;

+	friend class WinThread;

+

+		WinHWBkptMgr();

 

 	typedef unsigned char DRMask;

 	typedef unsigned char DRFlags;

 

-	static int SetHardwareBreak(TBreakpoint*);

-	static int ClearHardwareBreak(TBreakpoint*);

-

-  public: // would like these to be private, but static initializers require otherwise

+	int SetHardwareBreak(TBreakpoint*);

+	int ClearHardwareBreak(TBreakpoint*);

 

 	typedef unsigned char Mode;

 	typedef unsigned char SizeBits;

 

-	static const Mode execute		= 0x00;

+	static const Mode execute	= 0x00;

 	static const Mode write		= 0x01;

 	//	0x02 is defined to mean break on I/O read/write, unsupported

 	static const Mode readwrite	= 0x03;

-	static const Mode invalid		= 0x04;

+	static const Mode invalid	= 0x04;

 

-  private:

-

-	typedef struct {

-		ContextAddress	address;	// address of the full HW break

+	struct HWBreakInfo {

+		TBreakpoint*	tcfBp;

 		DRMask			inUse;		// mask of the regs used for this hw-break

 		Mode			accessMode;	// accessMode to use for all regs used

-		unsigned char	size;		// combined size of HW breaks in bits of all DRegs

-	} HWBreakInfo;

+		HWBreakInfo() : tcfBp(NULL), inUse(0) {}

+	};

 

-	static DRMask			inUse;

-	static unsigned char	InUseCount();

-	static unsigned char	UnusedCount();

-	static DRMask			UseUnusedRegister();

+	DRMask			inUse;

+	unsigned char	InUseCount();

+	unsigned char	UnusedCount();

+	DRMask			UseUnusedRegister();

 

+	HWBreakInfo		hwBkpt[MAX_HWBP];

+	unsigned char	GetUnusedWatchpoint();

 

-	static HWBreakInfo		hwBkpt[MAX_HWBP];

-	static unsigned char	GetUnusedWatchpoint();

+	static Mode		sDR7ModeBitsMap(unsigned char i);

+	static SizeBits	sDR7SizeBitsMap(unsigned char i);

 };

 

 #endif /* WINHWBKPTMGR_H_ */

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 fe082de..feeae09 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
@@ -75,6 +75,7 @@
 }

 

 WinProcess::~WinProcess(void) {

+	BreakpointsService::RemoveProcessFromBreakpoints(this);

 

 	processIDMap.erase(GetOSID());

 

@@ -96,8 +97,11 @@
 	return iter->second;

 }

 

-int WinProcess::ReadMemory(const ReadWriteMemoryParams& params) throw (AgentException) {

-	int result = 0;

+int WinProcess::ReadMemory(const ReadWriteMemoryParams& params)

+		throw (AgentException) {

+	int result = hwPageProtMgr.DisableForPagesContainingAddress(

+				   processHandle_, params.address, params.size, PAGE_READONLY);

+	bool reprotect = (ERR_PGPRO_NO_ADDR != result);

 

 	BOOL success

 	  = ::ReadProcessMemory(processHandle_, (LPCVOID) params.address,

@@ -105,22 +109,37 @@
 	if (!success)

 		result = ::GetLastError();

 	else

-		BreakpointsService::RemoveBreakpointsFromMemoryRead(processHandle_, params.address, params.memBuffer, params.size);

+		BreakpointsService::RemoveBreakpointsFromMemoryRead(processHandle_,

+				params.address, params.memBuffer, params.size),

+		result = 0;

+

+	if (reprotect)

+		hwPageProtMgr.EnableForPagesContainingAddress(processHandle_,

+				params.address, params.size, PAGE_READONLY);

 

 	return result;

 }

 

-int WinProcess::WriteMemory(const ReadWriteMemoryParams& params) throw (AgentException) {

-	int result = 0;

+int WinProcess::WriteMemory(const ReadWriteMemoryParams& params)

+		throw (AgentException) {

+	int result = hwPageProtMgr.DisableForPagesContainingAddress(

+					processHandle_, params.address, params.size);

+	bool reprotect = (ERR_PGPRO_NO_ADDR != result);

 

 	BOOL success

 	  = ::WriteProcessMemory(processHandle_, (LPVOID) params.address,

 			  	  	  	  	 params.memBuffer, params.size, params.sizeTransferred);

 	if (!success)

 		result = ::GetLastError();

-	else {

-		BreakpointsService::ReInsertBreakpointsAfterMemoryWrite(processHandle_, params.address, params.memBuffer, params.size);

-	}

+	else

+		BreakpointsService::ReInsertBreakpointsAfterMemoryWrite(

+				processHandle_, params.address, params.memBuffer, params.size),

+		result = 0;

+

+	if (reprotect)

+		hwPageProtMgr.EnableForPagesContainingAddress(processHandle_,

+				params.address, params.size);

+

 	return result;

 }

 

@@ -145,6 +164,34 @@
 	return executablesByAddress_;

 }

 

+int WinProcess::SetWatchpoint(TBreakpoint* wp) {

+	int err = ERR_OTHER;

+	if (wp->requestedType != type_Software		// i.e. user-forced softare type

+		&& wp->accessMode != ACCESSMODE_READ)	// can't do read-only WPs w/hw-bkpts

+		err = hwBkptMgr.SetHardwareBreak(wp);

+	if (err == 0)

+		wp->actualType = type_Hardware;

+	else if (wp->requestedType != type_Hardware) {

+		err = hwPageProtMgr.SetPageProtectWatchpoint(wp);

+		if (err == 0)

+			wp->actualType = type_Software;

+	}

+	return err;

+}

+

+int WinProcess::ClearWatchpoint(TBreakpoint* wp) {

+	int err;

+	if (wp->actualType == type_Hardware)

+		err = hwBkptMgr.ClearHardwareBreak(wp);

+	else

+		err = hwPageProtMgr.ClearPageProtectWatchpoint(wp);

+	return err;

+}

+

+size_t WinProcess::SoftwareWatchpointCount() const {

+	return hwPageProtMgr.watchpoints.size();

+}

+

 void WinProcess::SetDebugRegister(WinHWBkptMgr::DRMask drMask, ContextAddress addr, WinHWBkptMgr::DRFlags flags) {

 	const std::list<Context*>& children = GetChildren();

 	std::list<Context*>::const_iterator c;

diff --git a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinProcess.h b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinProcess.h
index 57356e7..49423a3 100644
--- a/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinProcess.h
+++ b/org.eclipse.cdt.debug.edc.windows.agent/src/win_agent/WinProcess.h
@@ -10,14 +10,16 @@
  *******************************************************************************/

 #pragma once

 

+#include "stdafx.h"

+

 #include <vector>

 #include <set>

-#include "stdafx.h"

-#include "ProcessContext.h"

-#include "WinHWBkptMgr.h"

-#include "WinDebugMonitor.h"

 

-class WinThread;

+#include "ProcessContext.h"

+#include "WinDebugMonitor.h"

+#include "WinHWPageProtMgr.h"

+#include "WinThread.h"

+

 class WinDebugMonitor;

 

 class WinProcess : public ProcessContext {

@@ -45,11 +47,18 @@
 

 	std::map<int, Properties>& GetExecutablesByAddress();

 

-	void SetDebugRegister(WinHWBkptMgr::DRMask, ContextAddress, WinHWBkptMgr::DRFlags);

-	void ClearDebugRegister(WinHWBkptMgr::DRMask);

+	int	SetWatchpoint(TBreakpoint*);

+	int ClearWatchpoint(TBreakpoint*);

+	size_t SoftwareWatchpointCount() const;

+

   private:

 	void Initialize();

 

+	friend int WinHWBkptMgr::SetHardwareBreak(TBreakpoint*);

+	void SetDebugRegister(WinHWBkptMgr::DRMask, ContextAddress, WinHWBkptMgr::DRFlags);

+	friend int WinHWBkptMgr::ClearHardwareBreak(TBreakpoint*);

+	void ClearDebugRegister(WinHWBkptMgr::DRMask);

+

 	bool isRoot_;

 	HANDLE processHandle_;

 	std::string processName_;

@@ -57,4 +66,10 @@
 	std::map<int, Properties> executablesByAddress_;

 

 	static std::map<int, WinProcess*> processIDMap;

+

+	WinHWBkptMgr		hwBkptMgr;

+

+	friend bool WinThread::HandlePotentialProtctedPage(const DEBUG_EVENT&);

+	friend int WinThread::HandleRestoringProtectedPage();

+	WinHWPageProtMgr	hwPageProtMgr;

 };

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 83494cb..f4ce51b 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
@@ -50,6 +50,8 @@
 	isSuspended_ = false;

 	isTerminating_ = false;

 	isUserSuspended_ = false;

+	isWatchpointStepping_ = false;

+	wpSteppingSavedWP = NULL;

 

 	// just to ensure that new threads are resumed with DBG_CONTINUE.  this is normally set/changed

 	// in HandleException

@@ -137,22 +139,117 @@
 	threadContextValid_ = false;

 }

 

-void WinThread::HandleException(DEBUG_EVENT& debugEvent) {

-	exceptionInfo_ = debugEvent.u.Exception;

+void WinThread::MarkResumed() {

+	isSuspended_ = false;

+	threadContextValid_ = false;

+}

+

+int WinThread::HandleRestoringProtectedPage() {

+	isWatchpointStepping_ = false;

+	const HANDLE& procH = parentProcess_.GetProcessHandle();

+	WinHWPageProtMgr& protMgr = parentProcess_.hwPageProtMgr;

+	return protMgr.EnableForPagesContainingAddress(procH, wpSteppingAddr_);

+}

+

+void WinThread::SendWatchpointNotification(const TBreakpoint* wp) {

+	std::ostringstream wpAddr; wpAddr << std::hex << wp->address;

+	EventClientNotifier::SendContextSuspended(this,

+			GetPCAddress(), REASON_WATCHPOINT, wpAddr.str());

+}

+

+void WinThread::HandleException(const DEBUG_EVENT& debugEvent) {

 	MarkSuspended();

 	EnsureValidContextInfo();

 

-	if (threadContextInfo_.Dr6 & 0xF) {	// one will be set if a HW bkpt triggered

-		HandleHardwareBreak();

+	bool hardwareBreakTriggered = threadContextInfo_.Dr6 & 0xF;

+	exceptionInfo_ = debugEvent.u.Exception;

+	if (isWatchpointStepping_) {

+		HandleRestoringProtectedPage();

+		if (!wpSteppingSavedWP && !hardwareBreakTriggered

+			&& exceptionInfo_.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP)

+		{

+			MarkResumed();

+			::ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);

+			return;

+		}

+	}

 

-		// always reset to this for the next time through.

-		threadContextInfo_.Dr6 = 0xFFFF0FF0;

-		::SetThreadContext(handle_, &threadContextInfo_);

+	if (hardwareBreakTriggered) {

+		HandleHardwareBreak();

+	} else if (wpSteppingSavedWP) {

+		SendWatchpointNotification(wpSteppingSavedWP);

 	} else {

 		AdjustPC();

 		EventClientNotifier::SendContextSuspended(this,

 				GetPCAddress(), GetSuspendReason(), GetExceptionMessage());

 	}

+	wpSteppingSavedWP = NULL;

+}

+

+void WinThread::HandleHardwareBreak() {

+	const HANDLE& procH = parentProcess_.GetProcessHandle();

+	ContextAddress* dr = (ContextAddress*)&(threadContextInfo_.Dr0);

+	for (int i = 0; i < 4; ++i) {

+		if (threadContextInfo_.Dr6 & (1 << i)) {

+			TBreakpoint* wp

+			  = BreakpointsService::FindWatchpointByAddress(procH, dr[i]);

+			if (wp) {

+				SendWatchpointNotification(wp);

+				break;

+			}

+		}

+	}

+

+	// always reset to this for the next time through.

+	threadContextInfo_.Dr6 = 0xFFFF0FF0;

+	::SetThreadContext(handle_, &threadContextInfo_);

+}

+

+bool WinThread::HandlePotentialProtctedPage(const DEBUG_EVENT& debugEvent) {

+	if (!parentProcess_.SoftwareWatchpointCount())

+		return false;

+

+	exceptionInfo_ = debugEvent.u.Exception;

+	WinHWPageProtMgr& protMgr = parentProcess_.hwPageProtMgr;

+	wpSteppingAddr_ = exceptionInfo_.ExceptionRecord.ExceptionInformation[1];

+	if (!protMgr.IsAddressInProtectedPage(wpSteppingAddr_))

+		return false;

+

+	isWatchpointStepping_ = true;

+

+	const HANDLE& procH = parentProcess_.GetProcessHandle();

+	protMgr.DisableForPagesContainingAddress(procH, wpSteppingAddr_);

+	TBreakpoint* wp = protMgr.FindWatchpointForAddress(procH, wpSteppingAddr_);

+	if (wp) {

+		bool accessW = exceptionInfo_.ExceptionRecord.ExceptionInformation[0] ? true : false;

+		if ((accessW && ACCESSMODE_WRITE & wp->accessMode)

+			|| (!accessW && ACCESSMODE_READ & wp->accessMode)) {

+			wpSteppingSavedWP = wp;

+		}

+	}

+

+	/*

+	 *	regardless of whether or not a WP was found & saved … single-step,

+	 *	and then WinThread::HandleException() will handle with the state

+	 *	member vars set herein.

+	 *	the point in doing this: if a page-protection access violation

+	 *	occurred at the WP address, it did so because the exception

+	 *	occurred before the instr was executed, and thus before the EIP

+	 *	moved.  by performing single-step unprotected & executing the

+	 *	instr that caused the access/protection violation, the EIP ends

+	 *	up where it would after the access, just like a HW bkpt trigger.

+	 *	and if the page-protection access violation occurred at an

+	 *	address other than the watchpoint, we still need to step once

+	 *	here in unprotected mode, and then re-protect the page and

+	 *	continue upon handling the single-step in HandleException.

+	 */

+

+	MarkSuspended();			// needed so EnsureValidContextInfo() works

+	EnsureValidContextInfo();	// needed so EnableSingleStep() works

+	EnableSingleStep();			// needed so watchpoint stepping works

+	MarkResumed();				// needed to prevent inadvertent context info access

+	::ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);

+	return true;

 }

 

 /*

@@ -532,7 +629,7 @@
 		break;

 	case DR3:

 		threadContextInfo_.Dr3 = addr;

-		DR7 = (DR7 & ~0xF0000030) | (dr7bits<<28) | 0x40;

+		DR7 = (DR7 & ~0xF00000C0) | (dr7bits<<28) | 0x40;

 		break;

 	default:

 		return;

@@ -556,24 +653,6 @@
 		return;

 	}

 	::SetThreadContext(handle_, &threadContextInfo_);

-	::SetThreadContext(handle_, &threadContextInfo_);

 	if (!suspended)

 		Resume();

 }

-

-void WinThread::HandleHardwareBreak() {

-	const HANDLE& procHandle = parentProcess_.GetProcessHandle();

-	ContextAddress* dr = (ContextAddress*)&(threadContextInfo_.Dr0);

-	for (int i = 0; i < 4; ++i) {

-		if (threadContextInfo_.Dr6 & (1 << i)) {

-			TBreakpoint* wp

-			  = BreakpointsService::FindWatchpointByAddress(procHandle, dr[i]);

-			if (wp) {

-				std::ostringstream wpAddr; wpAddr << std::hex << wp->address;

-				EventClientNotifier::SendContextSuspended(this,

-						GetPCAddress(), REASON_WATCHPOINT, wpAddr.str());

-				break;

-			}

-		}

-	}

-}

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 a525c2a..ff96362 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
@@ -60,14 +60,17 @@
 	

 	void PrepareForTermination(const AgentActionParams&) throw (AgentException);

 

-	void HandleException(DEBUG_EVENT& debugEvent);

+	void HandleException(const DEBUG_EVENT& debugEvent);

 	void HandleExecutableEvent(bool isLoaded, const std::string& exePath,

 			unsigned long baseAddress, unsigned long codeSize);

+	bool HandlePotentialProtctedPage(const DEBUG_EVENT&);

+	int HandleRestoringProtectedPage();

 

 	/* Address where suspend is reported */

 	ContextAddress GetPCAddress() const;

 

 	void EnableSingleStep();

+	void MarkResumed();

 

 	DWORD GetContinueStatus() const;

 

@@ -95,6 +98,7 @@
 	void* GetRegisterValueBuffer(const std::string& regName) const;

 

 	void HandleHardwareBreak();

+	void SendWatchpointNotification(const TBreakpoint*);

 

 	std::pair<int, int> threadLookupPair_;

 

@@ -102,6 +106,14 @@
 	bool isSuspended_;

 	bool isTerminating_;

 	bool isUserSuspended_;

+

+	bool isWatchpointStepping_;

+	DWORD wpSteppingAddr_;			// only valid if isWatchpointStepping_

+

+	// if a page-protection occurs, this will hold the

+	// watchpoint associated with the address, if any

+	TBreakpoint* wpSteppingSavedWP;	// only valid if isWatchpointStepping_

+

 	CONTEXT threadContextInfo_;

 	EXCEPTION_DEBUG_INFO exceptionInfo_;

 	std::map<std::string, std::string> registerValueCache_;