VirtualBox

source: vbox/trunk/src/VBox/Debugger/VBoxDbgConsole.cpp@ 2397

Last change on this file since 2397 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.4 KB
Line 
1/** @file
2 *
3 * VBox Debugger GUI - Console.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#include "VBoxDbgConsole.h"
27
28#include <qlabel.h>
29#include <qapplication.h>
30#include <qfont.h>
31#include <qtextview.h>
32#include <qlineedit.h>
33
34#include <VBox/dbg.h>
35#include <VBox/cfgm.h>
36#include <VBox/err.h>
37
38#include <iprt/thread.h>
39#include <iprt/tcp.h>
40#include <VBox/log.h>
41#include <iprt/assert.h>
42#include <iprt/asm.h>
43#include <iprt/alloc.h>
44#include <iprt/string.h>
45
46
47
48
49/*
50 *
51 * V B o x D b g C o n s o l e O u t p u t
52 * V B o x D b g C o n s o l e O u t p u t
53 * V B o x D b g C o n s o l e O u t p u t
54 *
55 *
56 */
57
58
59VBoxDbgConsoleOutput::VBoxDbgConsoleOutput(QWidget *pParent/* = NULL*/, const char *pszName/* = NULL*/)
60 : QTextEdit(pParent, pszName), m_uCurLine(0), m_uCurPos(0)
61{
62 setReadOnly(true);
63 setUndoRedoEnabled(false);
64 setOverwriteMode(true);
65 setTextFormat(PlainText); /* minimal HTML: setTextFormat(LogText); */
66
67 QFont Font = font();
68 Font.setStyleHint(QFont::TypeWriter);
69 Font.setFamily("Courier [Monotype]");
70 setFont(Font);
71}
72
73VBoxDbgConsoleOutput::~VBoxDbgConsoleOutput()
74{
75}
76
77void VBoxDbgConsoleOutput::appendText(const QString &rStr)
78{
79 if (rStr.isEmpty() || rStr.isNull() || !rStr.length())
80 return;
81
82 /*
83 * Insert line by line.
84 */
85 unsigned cch = rStr.length();
86 unsigned iPos = 0;
87 while (iPos < cch)
88 {
89 int iPosNL = rStr.find('\n', iPos);
90 int iPosEnd = iPosNL >= 0 ? iPosNL : cch;
91 if ((unsigned)iPosNL != iPos)
92 {
93 QString Str = rStr.mid(iPos, iPosEnd - iPos);
94 if (m_uCurPos == 0)
95 append(Str);
96 else
97 insertAt(Str, m_uCurLine, m_uCurPos);
98 if (iPosNL >= 0)
99 {
100 m_uCurLine++;
101 m_uCurPos = 0;
102 }
103 else
104 m_uCurPos += Str.length();
105 }
106 else
107 {
108 m_uCurLine++;
109 m_uCurPos = 0;
110 }
111 /* next */
112 iPos = iPosEnd + 1;
113 }
114}
115
116
117
118
119/*
120 *
121 * V B o x D b g C o n s o l e I n p u t
122 * V B o x D b g C o n s o l e I n p u t
123 * V B o x D b g C o n s o l e I n p u t
124 *
125 *
126 */
127
128
129VBoxDbgConsoleInput::VBoxDbgConsoleInput(QWidget *pParent/* = NULL*/, const char *pszName/* = NULL*/)
130 : QComboBox(true, pParent, pszName)
131{
132 insertItem("", 0);
133 setInsertionPolicy(AfterCurrent);
134 setMaxCount(50);
135 const QLineEdit *pEdit = lineEdit();
136 if (pEdit)
137 connect(pEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
138}
139
140VBoxDbgConsoleInput::~VBoxDbgConsoleInput()
141{
142}
143
144void VBoxDbgConsoleInput::setLineEdit(QLineEdit *pEdit)
145{
146 QComboBox::setLineEdit(pEdit);
147 if (lineEdit() == pEdit && pEdit)
148 connect(pEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
149}
150
151void VBoxDbgConsoleInput::returnPressed()
152{
153 QString Str = currentText();
154 emit commandSubmitted(Str);
155 clearEdit();
156 setCurrentItem(0);
157}
158
159
160
161
162
163
164/*
165 *
166 * V B o x D b g C o n s o l e
167 * V B o x D b g C o n s o l e
168 * V B o x D b g C o n s o l e
169 *
170 *
171 */
172
173
174VBoxDbgConsole::VBoxDbgConsole(PVM pVM, QWidget *pParent/* = NULL*/, const char *pszName/* = NULL*/)
175 : VBoxDbgBase(pVM), m_pOutput(NULL), m_pInput(NULL),
176 m_pszInputBuf(NULL), m_cbInputBuf(0), m_cbInputBufAlloc(0),
177 m_pszOutputBuf(NULL), m_cbOutputBuf(0), m_cbOutputBufAlloc(0),
178 m_Timer(), m_fUpdatePending(false), m_Thread(NIL_RTTHREAD), m_EventSem(NIL_RTSEMEVENT), m_fTerminate(false)
179{
180 setCaption("VBoxDbg - Console");
181
182 NOREF(pszName);
183 NOREF(pParent);
184
185 /*
186 * Create the output text box.
187 */
188 m_pOutput = new VBoxDbgConsoleOutput(this);
189
190 /* try figure a suitable size */
191 QLabel *pLabel = new QLabel(NULL, "11111111111111111111111111111111111111111111111111111111111111111111111111111112222222222", this);
192 pLabel->setFont(m_pOutput->font());
193 QSize Size = pLabel->sizeHint();
194 delete pLabel;
195 Size.setWidth((int)(Size.width() * 1.10));
196 Size.setHeight(Size.width() / 2);
197 resize(Size);
198
199 /*
200 * Create the input combo box (with a label).
201 */
202 QHBox *pHBox = new QHBox(this);
203
204 pLabel = new QLabel(NULL, " Command ", pHBox);
205 pLabel->setMaximumSize(pLabel->sizeHint());
206 pLabel->setAlignment(AlignHCenter | AlignVCenter);
207
208 m_pInput = new VBoxDbgConsoleInput(pHBox);
209 m_pInput->setDuplicatesEnabled(false);
210 connect(m_pInput, SIGNAL(commandSubmitted(const QString &)), this, SLOT(commandSubmitted(const QString &)));
211
212 /*
213 * The tab order is from input to output, not the otherway around as it is by default.
214 */
215 setTabOrder(m_pInput, m_pOutput);
216
217 /*
218 * Init the backend structure.
219 */
220 m_Back.Core.pfnInput = backInput;
221 m_Back.Core.pfnRead = backRead;
222 m_Back.Core.pfnWrite = backWrite;
223 m_Back.pSelf = this;
224
225 /*
226 * Create the critical section, the event semaphore and the debug console thread.
227 */
228 int rc = RTCritSectInit(&m_Lock);
229 AssertRC(rc);
230
231 rc = RTSemEventCreate(&m_EventSem);
232 AssertRC(rc);
233
234 rc = RTThreadCreate(&m_Thread, backThread, this, 0, RTTHREADTYPE_DEBUGGER, RTTHREADFLAGS_WAITABLE, "VBoxDbgC");
235 AssertRC(rc);
236 if (VBOX_FAILURE(rc))
237 m_Thread = NIL_RTTHREAD;
238}
239
240VBoxDbgConsole::~VBoxDbgConsole()
241{
242 /*
243 * Wait for the thread.
244 */
245 ASMAtomicXchgSize(&m_fTerminate, true);
246 RTSemEventSignal(m_EventSem);
247 if (m_Thread != NIL_RTTHREAD)
248 {
249 int rc = RTThreadWait(m_Thread, 15000, NULL);
250 AssertRC(rc);
251 m_Thread = NIL_RTTHREAD;
252 }
253
254 /*
255 * Free resources.
256 */
257 RTCritSectDelete(&m_Lock);
258 RTSemEventDestroy(m_EventSem);
259 m_EventSem = 0;
260 m_pOutput = NULL;
261 m_pInput = NULL;
262 if (m_pszInputBuf)
263 {
264 RTMemFree(m_pszInputBuf);
265 m_pszInputBuf = NULL;
266 }
267 m_cbInputBuf = 0;
268 m_cbInputBufAlloc = 0;
269}
270
271void VBoxDbgConsole::commandSubmitted(const QString &rCommand)
272{
273 lock();
274 RTSemEventSignal(m_EventSem);
275
276 const char *psz = rCommand;//.utf8();
277 size_t cb = strlen(psz);
278
279 /*
280 * Make sure we've got space for the input.
281 */
282 if (cb + m_cbInputBuf >= m_cbInputBufAlloc)
283 {
284 size_t cbNew = RT_ALIGN_Z(cb + m_cbInputBufAlloc + 1, 128);
285 void *pv = RTMemRealloc(m_pszInputBuf, cbNew);
286 if (!pv)
287 {
288 unlock();
289 return;
290 }
291 m_pszInputBuf = (char *)pv;
292 m_cbInputBufAlloc = cbNew;
293 }
294
295 /*
296 * Add the input and output it.
297 */
298 memcpy(m_pszInputBuf + m_cbInputBuf, psz, cb);
299 m_cbInputBuf += cb;
300 m_pszInputBuf[m_cbInputBuf++] = '\n';
301
302 m_pOutput->appendText(rCommand + "\n");
303 m_pOutput->scrollToBottom();
304
305 m_fInputRestoreFocus = m_pInput->hasFocus(); /* dirty focus hack */
306 m_pInput->setEnabled(false);
307
308 unlock();
309}
310
311void VBoxDbgConsole::updateOutput()
312{
313 lock();
314 m_fUpdatePending = false;
315 if (m_cbOutputBuf)
316 {
317 m_pOutput->appendText(QString::fromUtf8((const char *)m_pszOutputBuf, m_cbOutputBuf));
318 m_cbOutputBuf = 0;
319 }
320 unlock();
321}
322
323
324/**
325 * Lock the object.
326 */
327void VBoxDbgConsole::lock()
328{
329 RTCritSectEnter(&m_Lock);
330}
331
332/**
333 * Unlocks the object.
334 */
335void VBoxDbgConsole::unlock()
336{
337 RTCritSectLeave(&m_Lock);
338}
339
340
341
342/**
343 * Checks if there is input.
344 *
345 * @returns true if there is input ready.
346 * @returns false if there not input ready.
347 * @param pBack Pointer to VBoxDbgConsole::m_Back.
348 * @param cMillies Number of milliseconds to wait on input data.
349 */
350/*static*/ DECLCALLBACK(bool) VBoxDbgConsole::backInput(PDBGCBACK pBack, uint32_t cMillies)
351{
352 VBoxDbgConsole *pThis = VBOXDBGCONSOLE_FROM_DBGCBACK(pBack);
353 pThis->lock();
354
355 /* questing for input means it's done processing. */
356 pThis->m_pInput->setEnabled(true);
357 /* dirty focus hack: */
358 if (pThis->m_fInputRestoreFocus)
359 {
360 pThis->m_fInputRestoreFocus = false;
361 if (!pThis->m_pInput->hasFocus())
362 pThis->m_pInput->setFocus();
363 }
364
365 bool fRc = true;
366 if (!pThis->m_cbInputBuf)
367 {
368 pThis->unlock();
369 RTSemEventWait(pThis->m_EventSem, cMillies);
370 pThis->lock();
371 fRc = pThis->m_cbInputBuf || pThis->m_fTerminate;
372 }
373
374 pThis->unlock();
375 return fRc;
376}
377
378/**
379 * Read input.
380 *
381 * @returns VBox status code.
382 * @param pBack Pointer to VBoxDbgConsole::m_Back.
383 * @param pvBuf Where to put the bytes we read.
384 * @param cbBuf Maximum nymber of bytes to read.
385 * @param pcbRead Where to store the number of bytes actually read.
386 * If NULL the entire buffer must be filled for a
387 * successful return.
388 */
389/*static*/ DECLCALLBACK(int) VBoxDbgConsole::backRead(PDBGCBACK pBack, void *pvBuf, size_t cbBuf, size_t *pcbRead)
390{
391 VBoxDbgConsole *pThis = VBOXDBGCONSOLE_FROM_DBGCBACK(pBack);
392 Assert(pcbRead); /** @todo implement this bit */
393 if (pcbRead)
394 *pcbRead = 0;
395
396 pThis->lock();
397 int rc = VINF_SUCCESS;
398 if (!pThis->m_fTerminate)
399 {
400 if (pThis->m_cbInputBuf)
401 {
402 const char *psz = pThis->m_pszInputBuf;
403 size_t cbRead = RT_MIN(pThis->m_cbInputBuf, cbBuf);
404 memcpy(pvBuf, psz, cbRead);
405 psz += cbRead;
406 pThis->m_cbInputBuf -= cbRead;
407 if (*psz)
408 memmove(pThis->m_pszInputBuf, psz, pThis->m_cbInputBuf);
409 pThis->m_pszInputBuf[pThis->m_cbInputBuf] = '\0';
410 *pcbRead = cbRead;
411 }
412 }
413 else
414 rc = VERR_GENERAL_FAILURE;
415 pThis->unlock();
416 return rc;
417}
418
419/**
420 * Write (output).
421 *
422 * @returns VBox status code.
423 * @param pBack Pointer to VBoxDbgConsole::m_Back.
424 * @param pvBuf What to write.
425 * @param cbBuf Number of bytes to write.
426 * @param pcbWritten Where to store the number of bytes actually written.
427 * If NULL the entire buffer must be successfully written.
428 */
429/*static*/ DECLCALLBACK(int) VBoxDbgConsole::backWrite(PDBGCBACK pBack, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
430{
431 VBoxDbgConsole *pThis = VBOXDBGCONSOLE_FROM_DBGCBACK(pBack);
432 int rc = VINF_SUCCESS;
433
434 pThis->lock();
435 if (cbBuf + pThis->m_cbOutputBuf >= pThis->m_cbOutputBufAlloc)
436 {
437 size_t cbNew = RT_ALIGN_Z(cbBuf + pThis->m_cbOutputBufAlloc + 1, 1024);
438 void *pv = RTMemRealloc(pThis->m_pszOutputBuf, cbNew);
439 if (!pv)
440 {
441 pThis->unlock();
442 if (pcbWritten)
443 *pcbWritten = 0;
444 return VERR_NO_MEMORY;
445 }
446 pThis->m_pszOutputBuf = (char *)pv;
447 pThis->m_cbOutputBufAlloc = cbNew;
448 }
449
450 /*
451 * Add the output.
452 */
453 memcpy(pThis->m_pszOutputBuf + pThis->m_cbOutputBuf, pvBuf, cbBuf);
454 pThis->m_cbOutputBuf += cbBuf;
455 pThis->m_pszOutputBuf[pThis->m_cbOutputBuf] = '\0';
456 if (pcbWritten)
457 *pcbWritten = cbBuf;
458
459 if (pThis->m_fTerminate)
460 rc = VERR_GENERAL_FAILURE;
461
462 /*
463 * Tell the GUI thread to draw this text.
464 * We cannot do it from here without frequent crashes.
465 */
466 if (!pThis->m_fUpdatePending)
467 QApplication::postEvent(pThis, new QCustomEvent(QEvent::User, NULL));
468
469 pThis->unlock();
470
471 return rc;
472}
473
474/**
475 * The Debugger Console Thread
476 *
477 * @returns VBox status code (ignored).
478 * @param Thread The thread handle.
479 * @param pvUser Pointer to the VBoxDbgConsole object.s
480 */
481/*static*/ DECLCALLBACK(int) VBoxDbgConsole::backThread(RTTHREAD Thread, void *pvUser)
482{
483 VBoxDbgConsole *pThis = (VBoxDbgConsole *)pvUser;
484 LogFlow(("backThread: Thread=%p pvUser=%p\n", (void *)Thread, pvUser));
485
486 NOREF(Thread);
487
488 /*
489 * Create and execute the console.
490 */
491 int rc = pThis->dbgcCreate(&pThis->m_Back.Core, 0);
492 LogFlow(("backThread: returns %Vrc\n", rc));
493 if (!pThis->m_fTerminate)
494 QApplication::postEvent(pThis, new QCustomEvent(QEvent::User, (void *)1));
495 return rc;
496}
497
498void VBoxDbgConsole::customEvent(QCustomEvent *pEvent)
499{
500 if (pEvent->type() == QEvent::User)
501 {
502 uintptr_t u = (uintptr_t)pEvent->data(); /** @todo enum! */
503 switch (u)
504 {
505 /* make update pending. */
506 case 0:
507 if (!m_fUpdatePending)
508 {
509 m_fUpdatePending = true;
510 m_Timer.singleShot(10, this, SLOT(updateOutput()));
511 }
512 break;
513
514 /* the thread terminated */
515 case 1:
516 m_pInput->setEnabled(false);
517 break;
518
519 /* paranoia */
520 default:
521 AssertMsgFailed(("u=%d\n", u));
522 break;
523 }
524 }
525}
526
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette