Commits

spencercw  committed bdef40f

#9 Implement breakpoints on code addresses.

  • Participants
  • Parent commits 6545931

Comments (0)

Files changed (4)

File gb_debugger_msvs/breakpoints/pending_breakpoint.cpp

 	{
 		return hr;
 	}
-	if (!(requestInfo.dwFields & BPREQI_BPLOCATION) ||
-		requestInfo.bpLocation.bpLocationType != BPLT_CODE_FILE_LINE)
+	if (!(requestInfo.dwFields & BPREQI_BPLOCATION))
 	{
 		return E_FAIL;
 	}
 
-	BSTR filename;
-	hr = requestInfo.bpLocation.bpLocation.bplocCodeFileLine.pDocPos->GetFileName(&filename);
-	if (hr != S_OK)
+	if (requestInfo.bpLocation.bpLocationType == BPLT_CODE_FILE_LINE)
 	{
-		return hr;
+		// Source file line breakpoint
+		BSTR filename;
+		hr = requestInfo.bpLocation.bpLocation.bplocCodeFileLine.pDocPos->GetFileName(&filename);
+		if (hr != S_OK)
+		{
+			return hr;
+		}
+
+		TEXT_POSITION startPos, endPos;
+		hr = requestInfo.bpLocation.bpLocation.bplocCodeFileLine.pDocPos->
+			GetRange(&startPos, &endPos);
+		if (hr != S_OK)
+		{
+			return hr;
+		}
+		if (endPos.dwLine < startPos.dwLine)
+		{
+			return E_FAIL;
+		}
+
+		// Bind the breakpoint in the debugger (this is an asynchronous method; see
+		// OnBreakpointSet() for the callback)
+		gbd->setBreakpoint(wstring(filename), startPos.dwLine, endPos.dwLine - startPos.dwLine,
+			this);
+
+		// Clean up
+		SysFreeString(filename);
 	}
+	else if (requestInfo.bpLocation.bpLocationType == BPLT_CODE_CONTEXT)
+	{
+		// Code address breakpoint
+		CCodeContext *context = NULL;
+		HRESULT hr = requestInfo.bpLocation.bpLocation.bplocCodeContext.pCodeContext->
+			QueryInterface(IID_GbDebuggerMsvsCodeContext, reinterpret_cast<void **>(&context));
+		if (!SUCCEEDED(hr))
+		{
+			return hr;
+		}
 
-	TEXT_POSITION startPos, endPos;
-	hr = requestInfo.bpLocation.bpLocation.bplocCodeFileLine.pDocPos->GetRange(&startPos, &endPos);
-	if (hr != S_OK)
-	{
-		return hr;
+		uint32_t address = context->GetAddress();
+		context->Release();
+
+		// Bind the breakpoint
+		gbd->setBreakpoint(address, this);
 	}
-	if (endPos.dwLine < startPos.dwLine)
+	else
 	{
 		return E_FAIL;
 	}
 
-	// Bind the breakpoint in the debugger (this is an asynchronous method; see OnBreakpointSet()
-	// for the callback)
-	gbd->setBreakpoint(wstring(filename), startPos.dwLine, endPos.dwLine - startPos.dwLine, this);
-
-	// Clean up
-	SysFreeString(filename);
-
 	return S_OK;
 }
 
 	}
 	else
 	{
-		// Create the document context
-		CComObject<CDocumentContext> *documentContext;
-		CComObject<CDocumentContext>::CreateInstance(&documentContext);
-		documentContext->AddRef();
-		documentContext->Init(breakpoint->sourceFile, breakpoint->line);
+		// Create the document context if this is a source code breakpoint
+		CComObject<CDocumentContext> *documentContext = NULL;
+		if (breakpoint->sourceFile)
+		{
+			CComObject<CDocumentContext>::CreateInstance(&documentContext);
+			documentContext->AddRef();
+			documentContext->Init(breakpoint->sourceFile, breakpoint->line);
+		}
 
 		// Create the code context
 		CComObject<CCodeContext> *codeContext;
 		boundEvent->SendEvent(callback_, engine_, program_, thread_);
 
 		// Clean up
-		// TODO: We probably need to save something here for when the breakpoint is actually hit
 		resolution->Release();
 		codeContext->Release();
-		documentContext->Release();
+		if (documentContext)
+		{
+			documentContext->Release();
+		}
 	}
 }
 

File gb_debugger_msvs/program.cpp

 	{
 		return hr;
 	}
-	if (type != BPLT_CODE_FILE_LINE)
+	if (type != BPLT_CODE_FILE_LINE && type != BPLT_CODE_CONTEXT)
 	{
 		return E_NOTIMPL;
 	}

File gb_emulator/include/gb_emulator/gb_debugger.h

 	void setBreakpoint(const boost::filesystem::path &sourceFile, unsigned line, unsigned tolerance,
 		void *usrPtr);
 
+	//! Requests a breakpoint be set at the given code address.
+	/**
+	 * This will call Listener::onBreakpointSet() when the breakpoint has been set, or if there was
+	 * an error setting the breakpoint.
+	 * \param address Code address to set the breakpoint on.
+	 * \param usrPtr Opaque pointer that is passed to the event callback.
+	 */
+	void setBreakpoint(uint32_t address, void *usrPtr);
+
 	//! Deletes the given breakpoint.
 	/**
 	 * \param breakpoint The breakpoint that was passed to Listener::onBreakpointSet() to delete.
 	void doExecute();
 	void doSuspend();
 	void doStep(StepType type, StepUnit unit);
-	void doSetBreakpoint(boost::filesystem::path sourceFile, unsigned line, unsigned tolerance,
-		void *usrPtr);
+	void doSetBreakpointOnLine(boost::filesystem::path sourceFile, unsigned line,
+		unsigned tolerance, void *usrPtr);
+	void doSetBreakpointOnAddr(uint32_t address, void *usrPtr);
 	void doDeleteBreakpoint(boost::shared_ptr<GbBreakpoint> breakpoint);
 
 	void doModule();

File gb_emulator/src/gb_debugger.cpp

 void GbDebugger::setBreakpoint(const fs::path &sourceFile, unsigned line, unsigned tolerance,
 	void *usrPtr)
 {
-	ioService_.post(boost::bind(&GbDebugger::doSetBreakpoint, this, sourceFile, line, tolerance,
-		usrPtr));
+	ioService_.post(boost::bind(&GbDebugger::doSetBreakpointOnLine, this, sourceFile, line,
+		tolerance, usrPtr));
+}
+
+void GbDebugger::setBreakpoint(uint32_t address, void *usrPtr)
+{
+	ioService_.post(boost::bind(&GbDebugger::doSetBreakpointOnAddr, this, address, usrPtr));
 }
 
 DEFINE_WRAPPER_ARGS_NO_RET(deleteBreakpoint, DeleteBreakpoint, shared_ptr<GbBreakpoint> breakpoint,
 	stepFrame_ = stack_.size();
 }
 
-void GbDebugger::doSetBreakpoint(fs::path sourceFile, unsigned line, unsigned tolerance,
+void GbDebugger::doSetBreakpointOnLine(fs::path sourceFile, unsigned line, unsigned tolerance,
 	void *usrPtr)
 {
 	shared_ptr<GbBreakpoint> breakpoint;
 		}
 	}
 
-	// Send an event
+	// Send the event
+	for (set<Listener *>::const_iterator listener = listeners_.begin(), end = listeners_.end();
+		listener != end; ++listener)
+	{
+		(*listener)->onBreakpointSet(breakpoint, usrPtr);
+	}
+}
+
+void GbDebugger::doSetBreakpointOnAddr(uint32_t address, void *usrPtr)
+{
+	shared_ptr<GbBreakpoint> breakpoint;
+	if (address < gb_.rom_.size())
+	{
+		breakpoint.reset(new GbBreakpoint);
+		breakpoint->module = getModule();
+		breakpoint->line = 0;
+		breakpoint->address = address;
+		breakpoint->usrPtr = usrPtr;
+		breakpoints_.insert(breakpoint);
+	}
+
+	// Send the event
 	for (set<Listener *>::const_iterator listener = listeners_.begin(), end = listeners_.end();
 		listener != end; ++listener)
 	{