/** * Sends the event in the event buffer. * * @returns VBox status code. * @param pVM Pointer to the VM. */ static int dbgfR3SendEvent(PVM pVM) { int rc = RTSemPing(&pVM->dbgf.s.PingPong); if (RT_SUCCESS(rc)) rc = dbgfR3VMMWait(pVM); pVM->dbgf.s.fStoppedInHyper = false; /** @todo sync VMM -> REM after exitting the debugger. everything may change while in the debugger! */ return rc; }
/** * Executes command from debugger. * The caller is responsible for waiting or resuming execution based on the * value returned in the *pfResumeExecution indicator. * * @returns VBox status. (clearify!) * @param pVM Pointer to the VM. * @param enmCmd The command in question. * @param pCmdData Pointer to the command data. * @param pfResumeExecution Where to store the resume execution / continue waiting indicator. */ static int dbgfR3VMMCmd(PVM pVM, DBGFCMD enmCmd, PDBGFCMDDATA pCmdData, bool *pfResumeExecution) { bool fSendEvent; bool fResume; int rc = VINF_SUCCESS; NOREF(pCmdData); /* for later */ switch (enmCmd) { /* * Halt is answered by an event say that we've halted. */ case DBGFCMD_HALT: { pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_HALT_DONE; pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM); fSendEvent = true; fResume = false; break; } /* * Resume is not answered we'll just resume execution. */ case DBGFCMD_GO: { fSendEvent = false; fResume = true; break; } /** @todo implement (and define) the rest of the commands. */ /* * Disable breakpoints and stuff. * Send an everythings cool event to the debugger thread and resume execution. */ case DBGFCMD_DETACH_DEBUGGER: { ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, false); pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_DETACH_DONE; pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_OTHER; fSendEvent = true; fResume = true; break; } /* * The debugger has detached successfully. * There is no reply to this event. */ case DBGFCMD_DETACHED_DEBUGGER: { fSendEvent = false; fResume = true; break; } /* * Single step, with trace into. */ case DBGFCMD_SINGLE_STEP: { Log2(("Single step\n")); rc = VINF_EM_DBG_STEP; /** @todo SMP */ PVMCPU pVCpu = VMMGetCpu0(pVM); pVCpu->dbgf.s.fSingleSteppingRaw = true; fSendEvent = false; fResume = true; break; } /* * Default is to send an invalid command event. */ default: { pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_INVALID_COMMAND; pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM); fSendEvent = true; fResume = false; break; } } /* * Send pending event. */ if (fSendEvent) { Log2(("DBGF: Emulation thread: sending event %d\n", pVM->dbgf.s.DbgEvent.enmType)); int rc2 = RTSemPing(&pVM->dbgf.s.PingPong); if (RT_FAILURE(rc2)) { AssertRC(rc2); *pfResumeExecution = true; return rc2; } } /* * Return. */ *pfResumeExecution = fResume; return rc; }
/** * Terminates and cleans up resources allocated by the DBGF. * * @returns VBox status code. * @param pVM Pointer to the VM. */ VMMR3DECL(int) DBGFR3Term(PVM pVM) { int rc; /* * Send a termination event to any attached debugger. */ /* wait to become the speaker (we should already be that). */ if ( pVM->dbgf.s.fAttached && RTSemPingShouldWait(&pVM->dbgf.s.PingPong)) RTSemPingWait(&pVM->dbgf.s.PingPong, 5000); /* now, send the event if we're the speaker. */ if ( pVM->dbgf.s.fAttached && RTSemPingIsSpeaker(&pVM->dbgf.s.PingPong)) { DBGFCMD enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND); if (enmCmd == DBGFCMD_DETACH_DEBUGGER) /* the debugger beat us to initiating the detaching. */ rc = VINF_SUCCESS; else { /* ignore the command (if any). */ enmCmd = DBGFCMD_NO_COMMAND; pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_TERMINATING; pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_OTHER; rc = RTSemPing(&pVM->dbgf.s.PingPong); } /* * Process commands until we get a detached command. */ while (RT_SUCCESS(rc) && enmCmd != DBGFCMD_DETACHED_DEBUGGER) { if (enmCmd != DBGFCMD_NO_COMMAND) { /* process command */ bool fResumeExecution; DBGFCMDDATA CmdData = pVM->dbgf.s.VMMCmdData; rc = dbgfR3VMMCmd(pVM, enmCmd, &CmdData, &fResumeExecution); enmCmd = DBGFCMD_NO_COMMAND; } else { /* wait for new command. */ rc = RTSemPingWait(&pVM->dbgf.s.PingPong, RT_INDEFINITE_WAIT); if (RT_SUCCESS(rc)) enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND); } } } /* * Terminate the other bits. */ dbgfR3OSTerm(pVM); dbgfR3AsTerm(pVM); dbgfR3RegTerm(pVM); dbgfR3TraceTerm(pVM); dbgfR3InfoTerm(pVM); return VINF_SUCCESS; }
int main() { RTR3Init(); /* * Create a ping pong and kick off a second thread which we'll * exchange TSTSEMPINGPONG_ITERATIONS messages with. */ RTPINGPONG PingPong; int rc = RTSemPingPongInit(&PingPong); if (RT_FAILURE(rc)) { RTPrintf("tstSemPingPong: FATAL ERROR - RTSemPingPongInit -> %Rrc\n", rc); return 1; } RTTHREAD hThread; rc = RTThreadCreate(&hThread, tstSemPingPongThread, &PingPong, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "PONG"); if (RT_FAILURE(rc)) { RTPrintf("tstSemPingPong: FATAL ERROR - RTSemPingPongInit -> %Rrc\n", rc); return 1; } RTPrintf("tstSemPingPong: TESTING - %u iterations...\n", TSTSEMPINGPONG_ITERATIONS); for (uint32_t i = 0; i < TSTSEMPINGPONG_ITERATIONS; i++) { if (!RTSemPingIsSpeaker(&PingPong)) { ASMAtomicIncU32(&g_cErrors); RTPrintf("tstSemPingPong: ERROR - RTSemPingIsSpeaker returned false before RTSemPing.\n"); } rc = RTSemPing(&PingPong); if (RT_FAILURE(rc)) { ASMAtomicIncU32(&g_cErrors); RTPrintf("tstSemPingPong: ERROR - RTSemPing -> %Rrc\n", rc); break; } if (!RTSemPingShouldWait(&PingPong)) { ASMAtomicIncU32(&g_cErrors); RTPrintf("tstSemPingPong: ERROR - RTSemPingShouldWait returned false before RTSemPingWait.\n"); } rc = RTSemPingWait(&PingPong, RT_INDEFINITE_WAIT); if (RT_FAILURE(rc)) { ASMAtomicIncU32(&g_cErrors); RTPrintf("tstSemPingPong: ERROR - RTSemPingWait -> %Rrc\n", rc); break; } } int rcThread; rc = RTThreadWait(hThread, 5000, &rcThread); if (RT_FAILURE(rc)) { ASMAtomicIncU32(&g_cErrors); RTPrintf("tstSemPingPong: ERROR - RTSemPingWait -> %Rrc\n", rc); } rc = RTSemPingPongDelete(&PingPong); if (RT_FAILURE(rc)) { ASMAtomicIncU32(&g_cErrors); RTPrintf("tstSemPingPong: ERROR - RTSemPingPongDestroy -> %Rrc\n", rc); } /* * Summary. */ uint32_t cErrors = ASMAtomicUoReadU32(&g_cErrors); if (cErrors) RTPrintf("tstSemPingPong: FAILED - %d errors\n", cErrors); else RTPrintf("tstSemPingPong: SUCCESS\n"); return cErrors ? 1 : 0; }