DBGF.cpp revision 50f998bb47f333d10515d4c12ad01a4e92a0747b
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * DBGF - Debugger Facility.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * Copyright (C) 2006-2007 Oracle Corporation
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * This file is part of VirtualBox Open Source Edition (OSE), as
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * available from http://www.virtualbox.org. This file is free software;
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * you can redistribute it and/or modify it under the terms of the GNU
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * General Public License (GPL) as published by the Free Software
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * Foundation, in version 2 as it comes in the "COPYING" file of the
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl/** @page pg_dbgf DBGF - The Debugger Facility
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * The purpose of the DBGF is to provide an interface for debuggers to
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * manipulate the VMM without having to mess up the source code for each of
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * them. The DBGF is always built in and will always work when a debugger
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * attaches to the VM. The DBGF provides the basic debugger features, such as
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * halting execution, handling breakpoints, single step execution, instruction
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * disassembly, info querying, OS specific diggers, symbol and module
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * management.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * The interface is working in a manner similar to the win32, linux and os2
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * debugger interfaces. The interface has an asynchronous nature. This comes
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * from the fact that the VMM and the Debugger are running in different threads.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * They are referred to as the "emulation thread" and the "debugger thread", or
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * as the "ping thread" and the "pong thread, respectivly. (The last set of
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * names comes from the use of the Ping-Pong synchronization construct from the
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * RTSem API.)
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * @see grp_dbgf
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * @section sec_dbgf_scenario Usage Scenario
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * The debugger starts by attaching to the VM. For practical reasons we limit the
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * number of concurrently attached debuggers to 1 per VM. The action of
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * attaching to the VM causes the VM to check and generate debug events.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * The debugger then will wait/poll for debug events and issue commands.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * The waiting and polling is done by the DBGFEventWait() function. It will wait
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * for the emulation thread to send a ping, thus indicating that there is an
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * event waiting to be processed.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * An event can be a response to a command issued previously, the hitting of a
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * breakpoint, or running into a bad/fatal VMM condition. The debugger now has
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * the ping and must respond to the event at hand - the VMM is waiting. This
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * usually means that the user of the debugger must do something, but it doesn't
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * have to. The debugger is free to call any DBGF function (nearly at least)
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * while processing the event.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * Typically the user will issue a request for the execution to be resumed, so
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * the debugger calls DBGFResume() and goes back to waiting/polling for events.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * When the user eventually terminates the debugging session or selects another
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * VM, the debugger detaches from the VM. This means that breakpoints are
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * disabled and that the emulation thread no longer polls for debugger commands.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl/*******************************************************************************
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl* Header Files *
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl*******************************************************************************/
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl/*******************************************************************************
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl* Internal Functions *
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl*******************************************************************************/
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristlstatic int dbgfR3VMMCmd(PVM pVM, DBGFCMD enmCmd, PDBGFCMDDATA pCmdData, bool *pfResumeExecution);
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristlstatic DECLCALLBACK(int) dbgfR3Attach(PVM pVM);
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * Sets the VMM Debug Command variable.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * @returns Previous command.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * @param pVM VM Handle.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * @param enmCmd The command.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias TristlDECLINLINE(DBGFCMD) dbgfR3SetCmd(PVM pVM, DBGFCMD enmCmd)
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl Log2(("DBGF: Setting command to %d (DBGFCMD_NO_COMMAND)\n", enmCmd));
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl rc = (DBGFCMD)ASMAtomicXchgU32((uint32_t volatile *)(void *)&pVM->dbgf.s.enmVMMCmd, enmCmd);
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl Log2(("DBGF: Setting command to %d\n", enmCmd));
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl AssertMsg(pVM->dbgf.s.enmVMMCmd == DBGFCMD_NO_COMMAND, ("enmCmd=%d enmVMMCmd=%d\n", enmCmd, pVM->dbgf.s.enmVMMCmd));
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl rc = (DBGFCMD)ASMAtomicXchgU32((uint32_t volatile *)(void *)&pVM->dbgf.s.enmVMMCmd, enmCmd);
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl VMR3NotifyGlobalFFU(pVM->pUVM, 0 /* didn't notify REM */);
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * Initializes the DBGF.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * @returns VBox status code.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * @param pVM VM handle.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * Terminates and cleans up resources allocated by the DBGF.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * @returns VBox status code.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * @param pVM VM Handle.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * Send a termination event to any attached debugger.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl /* wait to become the speaker (we should already be that). */
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl && RTSemPingShouldWait(&pVM->dbgf.s.PingPong))
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl /* now, send the event if we're the speaker. */
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl && RTSemPingIsSpeaker(&pVM->dbgf.s.PingPong))
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl DBGFCMD enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND);
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl /* the debugger beat us to initiating the detaching. */
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl /* ignore the command (if any). */
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_TERMINATING;
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_OTHER;
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * Process commands until we get a detached command.
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl while (RT_SUCCESS(rc) && enmCmd != DBGFCMD_DETACHED_DEBUGGER)
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl /* process command */
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl DBGFCMDDATA CmdData = pVM->dbgf.s.VMMCmdData;
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl rc = dbgfR3VMMCmd(pVM, enmCmd, &CmdData, &fResumeExecution);
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl /* wait for new command. */
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl rc = RTSemPingWait(&pVM->dbgf.s.PingPong, RT_INDEFINITE_WAIT);
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND);
8a0678903b06fbd3c9acf4f4cd137482e1dcd2aaMatthias Tristl * Terminate the other bits.
#ifndef RT_OS_L4
# if !defined(DEBUG) || defined(DEBUG_sandervl) || defined(DEBUG_frank) || defined(IEM_VERIFICATION_MODE)
RTStrmPrintf(g_pStdErr, "DBGF: No debugger attached, waiting %d second%s for one to attach (event=%d)\n",
while (cWait > 0)
cWait--;
bool fResumeExecution;
if (!fResumeExecution)
return rc;
switch (enmEvent)
case DBGFEVENT_STEPPED_HYPER:
case EMSTATE_RAW:
case EMSTATE_DEBUG_GUEST_RAW:
return DBGFEVENTCTX_RAW;
case EMSTATE_REM:
case EMSTATE_DEBUG_GUEST_REM:
return DBGFEVENTCTX_REM;
case EMSTATE_DEBUG_HYPER:
case EMSTATE_GURU_MEDITATION:
return DBGFEVENTCTX_HYPER;
return DBGFEVENTCTX_OTHER;
return VERR_DBGF_NOT_ATTACHED;
return VINF_SUCCESS;
/** @todo sync VMM -> REM after exitting the debugger. everything may change while in the debugger! */
return rc;
return rc;
VMMR3DECL(int) DBGFR3EventSrc(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, const char *pszFunction, const char *pszFormat, ...)
return rc;
VMMR3DECL(int) DBGFR3EventSrcV(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, const char *pszFunction, const char *pszFormat, va_list args)
return rc;
VMMR3DECL(int) DBGFR3EventAssertion(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszMsg1, const char *pszMsg2)
return rc;
return rc;
if (iBp != ~0U)
uint32_t cPollHack = 1; /** @todo this interface is horrible now that we're using lots of VMR3ReqCall stuff all over DBGF. */
int rc;
return rc;
cPollHack++;
switch (rc)
case VINF_EM_DBG_BREAKPOINT:
case VINF_EM_DBG_STEPPED:
case VINF_EM_DBG_STEP:
case VINF_EM_DBG_STOP:
case VINF_EM_TERMINATE:
case VINF_EM_OFF:
return rc;
case VINF_EM_RESET:
case VINF_EM_SUSPEND:
case VINF_EM_HALT:
case VINF_EM_RESUME:
case VINF_EM_RESCHEDULE:
case VINF_EM_RESCHEDULE_REM:
case VINF_EM_RESCHEDULE_RAW:
return rc;
bool fResumeExecution;
if (fResumeExecution)
return rcRet;
bool fSendEvent;
bool fResume;
switch (enmCmd)
case DBGFCMD_HALT:
fSendEvent = true;
fResume = false;
case DBGFCMD_GO:
fSendEvent = false;
fResume = true;
case DBGFCMD_DETACH_DEBUGGER:
fSendEvent = true;
fResume = true;
fSendEvent = false;
fResume = true;
case DBGFCMD_SINGLE_STEP:
fSendEvent = false;
fResume = true;
fSendEvent = true;
fResume = false;
if (fSendEvent)
*pfResumeExecution = true;
return rc2;
return rc;
return VERR_DBGF_ALREADY_ATTACHED;
return VINF_SUCCESS;
int rc;
return VINF_SUCCESS;
return VINF_SUCCESS;
return rc;
return VWRN_DBGF_ALREADY_HALTED;
return VINF_SUCCESS;
return rc;
return rc;
return VINF_EM_DBG_STEP;