VBoxDbgConsole.cpp revision 43747b1f0bc8302a238fb35e55857a5e9aa1933d
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * VBox Debugger GUI - Console.
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * Copyright (C) 2006-2010 Oracle Corporation
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * available from http://www.virtualbox.org. This file is free software;
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * you can redistribute it and/or modify it under the terms of the GNU
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * General Public License (GPL) as published by the Free Software
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/*******************************************************************************
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync* Header Files *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync*******************************************************************************/
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * V B o x D b g C o n s o l e O u t p u t
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * V B o x D b g C o n s o l e O u t p u t
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * V B o x D b g C o n s o l e O u t p u t
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVBoxDbgConsoleOutput::VBoxDbgConsoleOutput(QWidget *pParent/* = NULL*/, const char *pszName/* = NULL*/)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync : QTextEdit(pParent), m_uCurLine(0), m_uCurPos(0), m_hGUIThread(RTThreadNativeSelf())
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync setTextInteractionFlags(Qt::TextBrowserInteraction);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* green on black */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Pal.setColor(QPalette::All, QPalette::Base, QColor(Qt::black));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVBoxDbgConsoleOutput::appendText(const QString &rStr)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (rStr.isEmpty() || rStr.isNull() || !rStr.length())
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Insert all in one go and make sure it's visible.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync moveCursor(QTextCursor::End); /* make sure we append the text */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * V B o x D b g C o n s o l e I n p u t
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * V B o x D b g C o n s o l e I n p u t
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * V B o x D b g C o n s o l e I n p u t
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVBoxDbgConsoleInput::VBoxDbgConsoleInput(QWidget *pParent/* = NULL*/, const char *pszName/* = NULL*/)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync : QComboBox(pParent), m_iBlankItem(0), m_hGUIThread(RTThreadNativeSelf())
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync connect(pEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync connect(pEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* deal with the current command. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* update the history and clear the entry field */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync QString PrevStr = m_iBlankItem > 0 ? itemText(m_iBlankItem - 1) : "";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * V B o x D b g C o n s o l e
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * V B o x D b g C o n s o l e
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * V B o x D b g C o n s o l e
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVBoxDbgConsole::VBoxDbgConsole(VBoxDbgGui *a_pDbgGui, QWidget *a_pParent/* = NULL*/)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync : VBoxDbgBaseWindow(a_pDbgGui, a_pParent), m_pOutput(NULL), m_pInput(NULL), m_fInputRestoreFocus(false),
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync m_pszInputBuf(NULL), m_cbInputBuf(0), m_cbInputBufAlloc(0),
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync m_pszOutputBuf(NULL), m_cbOutputBuf(0), m_cbOutputBufAlloc(0),
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync m_pTimer(NULL), m_fUpdatePending(false), m_Thread(NIL_RTTHREAD), m_EventSem(NIL_RTSEMEVENT),
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Create the output text box.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* try figure a suitable size */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync QLabel *pLabel = new QLabel( "11111111111111111111111111111111111111111111111111111111111111111111111111111112222222222", this);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Create the input combo box (with a label).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync //pLayout->setSizeConstraint(QLayout::SetMaximumSize);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync connect(m_pInput, SIGNAL(commandSubmitted(const QString &)), this, SLOT(commandSubmitted(const QString &)));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync# if 0//def Q_WS_MAC
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pLabel->setMaximumSize(20, m_pInput->sizeHint().height() + 6);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pLabel->setMinimumSize(20, m_pInput->sizeHint().height() + 6);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync m_pInput->setEnabled(false); /* (we'll get a ready notification) */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Vertical layout box on the whole widget.
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * The tab order is from input to output, not the other way around as it is by default.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Setup the timer.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync connect(m_pTimer, SIGNAL(timeout()), SLOT(updateOutput()));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Init the backend structure.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Create the critical section, the event semaphore and the debug console thread.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = RTThreadCreate(&m_Thread, backThread, this, 0, RTTHREADTYPE_DEBUGGER, RTTHREADFLAGS_WAITABLE, "VBoxDbgC");
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Shortcuts.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync m_pFocusToInput->setShortcut(QKeySequence("Ctrl+L"));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync connect(m_pFocusToInput, SIGNAL(triggered(bool)), this, SLOT(actFocusToInput()));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync m_pFocusToOutput->setShortcut(QKeySequence("Ctrl+O"));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync connect(m_pFocusToOutput, SIGNAL(triggered(bool)), this, SLOT(actFocusToOutput()));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Wait for the thread.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Free resources.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVBoxDbgConsole::commandSubmitted(const QString &rCommand)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Make sure we've got space for the input.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync size_t cbNew = RT_ALIGN_Z(cb + m_cbInputBufAlloc + 1, 128);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Add the input and output it.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync m_fInputRestoreFocus = m_pInput->hasFocus(); /* dirty focus hack */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Log(("VBoxDbgConsole::commandSubmitted: %s (input-enabled=%RTbool)\n", psz, m_pInput->isEnabled()));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync m_pOutput->appendText(QString::fromUtf8((const char *)m_pszOutputBuf, (int)m_cbOutputBuf));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Lock the object.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Unlocks the object.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Checks if there is input.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns true if there is input ready.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns false if there not input ready.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pBack Pointer to VBoxDbgConsole::m_Back.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param cMillies Number of milliseconds to wait on input data.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVBoxDbgConsole::backInput(PDBGCBACK pBack, uint32_t cMillies)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync VBoxDbgConsole *pThis = VBOXDBGCONSOLE_FROM_DBGCBACK(pBack);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync bool fRc = true;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Wait outside the lock for the requested time, then check again.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Read input.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pBack Pointer to VBoxDbgConsole::m_Back.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pvBuf Where to put the bytes we read.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param cbBuf Maximum nymber of bytes to read.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pcbRead Where to store the number of bytes actually read.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * If NULL the entire buffer must be filled for a
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * successful return.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVBoxDbgConsole::backRead(PDBGCBACK pBack, void *pvBuf, size_t cbBuf, size_t *pcbRead)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync VBoxDbgConsole *pThis = VBOXDBGCONSOLE_FROM_DBGCBACK(pBack);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync size_t cbRead = RT_MIN(pThis->m_cbInputBuf, cbBuf);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync memmove(pThis->m_pszInputBuf, psz, pThis->m_cbInputBuf);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Write (output).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pBack Pointer to VBoxDbgConsole::m_Back.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pvBuf What to write.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param cbBuf Number of bytes to write.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pcbWritten Where to store the number of bytes actually written.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * If NULL the entire buffer must be successfully written.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVBoxDbgConsole::backWrite(PDBGCBACK pBack, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync VBoxDbgConsole *pThis = VBOXDBGCONSOLE_FROM_DBGCBACK(pBack);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (cbBuf + pThis->m_cbOutputBuf >= pThis->m_cbOutputBufAlloc)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync size_t cbNew = RT_ALIGN_Z(cbBuf + pThis->m_cbOutputBufAlloc + 1, 1024);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync void *pv = RTMemRealloc(pThis->m_pszOutputBuf, cbNew);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Add the output.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync memcpy(pThis->m_pszOutputBuf + pThis->m_cbOutputBuf, pvBuf, cbBuf);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pThis->m_pszOutputBuf[pThis->m_cbOutputBuf] = '\0';
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Tell the GUI thread to draw this text.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * We cannot do it from here without frequent crashes.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync QApplication::postEvent(pThis, new VBoxDbgConsoleEvent(VBoxDbgConsoleEvent::kUpdate));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVBoxDbgConsole::backSetReady(PDBGCBACK pBack, bool fReady)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync VBoxDbgConsole *pThis = VBOXDBGCONSOLE_FROM_DBGCBACK(pBack);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync QApplication::postEvent(pThis, new VBoxDbgConsoleEvent(VBoxDbgConsoleEvent::kInputEnable));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * The Debugger Console Thread
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code (ignored).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param Thread The thread handle.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pvUser Pointer to the VBoxDbgConsole object.s
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVBoxDbgConsole::backThread(RTTHREAD Thread, void *pvUser)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync LogFlow(("backThread: Thread=%p pvUser=%p\n", (void *)Thread, pvUser));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Create and execute the console.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync int rc = pThis->dbgcCreate(&pThis->m_Back.Core, 0);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync ASMAtomicUoWriteBool(&pThis->m_fThreadTerminated, true);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync QApplication::postEvent(pThis, new VBoxDbgConsoleEvent(rc == VINF_SUCCESS
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync LogFlow(("backThread: returns %Rrc (m_fTerminate=%RTbool)\n", rc, ASMAtomicUoReadBool(&pThis->m_fTerminate)));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (pGenEvent->type() == (QEvent::Type)VBoxDbgConsoleEvent::kEventNumber)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync VBoxDbgConsoleEvent *pEvent = (VBoxDbgConsoleEvent *)pGenEvent;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* make update pending. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* Re-enable the input field and restore focus. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Log(("VBoxDbgConsole: kInputEnable (input-enabled=%RTbool)\n", m_pInput->isEnabled()));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* The thread terminated by user command (exit, quit, bye). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Log(("VBoxDbgConsole: kTerminatedUser (input-enabled=%RTbool)\n", m_pInput->isEnabled()));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* The thread terminated for some unknown reason., disable input */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Log(("VBoxDbgConsole: kTerminatedOther (input-enabled=%RTbool)\n", m_pInput->isEnabled()));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* paranoia */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertMsgFailed(("command=%d\n", pEvent->command()));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return true;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVBoxDbgConsole::closeEvent(QCloseEvent *a_pCloseEvt)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync delete this;