VirtualBox

source: vbox/trunk/src/VBox/Debugger/VBoxDbgBase.cpp@ 86327

Last change on this file since 86327 was 86327, checked in by vboxsync, 4 years ago

Debugger: Allow for different I/O providers instead of only TCP

So far TCP was the only option to communicate remotely with the internal debugger, the other option
was to use the console from the GUI directly. This commit reworks basic I/O to allow for different
providers where TCP is just one option. The second one being introduced is an IPC provider using a local
socket or named pipe depending on the platform. This allows for Windows kernel debugging over a pipe
using the KD stub in VirtualBox and WinDbg running on the host (not tested yet).

Furthermore this commit allows multiple stubs to be listening for connections at the same time, so
one can have a GDB stub listening on one TCP port and the native VBox debugger listening on another one
or even using a different I/O provider. Only one session can be active at a time though, because sharing
debugger states is impossible. To configure this the following CFGM keys need to be set for each listener:

"DBGC/<Some unique ID>/Provider" "tcp|ipc"
"DBGC/<Some unique ID>/StubType" "native|gdb|kd"
"DBGC/<Some unique ID>/Address" "<ip>|<local named pipe or socket path>"
"DBGC/<Some unique ID>/Port" "<port>" (for TCP only)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.8 KB
Line 
1/* $Id: VBoxDbgBase.cpp 86327 2020-09-28 16:20:50Z vboxsync $ */
2/** @file
3 * VBox Debugger GUI - Base classes.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
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 (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DBGG
23#include <iprt/errcore.h>
24#include <iprt/asm.h>
25#include <iprt/assert.h>
26#include <limits.h>
27#include "VBoxDbgBase.h"
28#include "VBoxDbgGui.h"
29
30#include <QApplication>
31#include <QWidgetList>
32
33
34
35VBoxDbgBase::VBoxDbgBase(VBoxDbgGui *a_pDbgGui)
36 : m_pDbgGui(a_pDbgGui), m_pUVM(NULL), m_hGUIThread(RTThreadNativeSelf())
37{
38 NOREF(m_pDbgGui); /* shut up warning. */
39
40 /*
41 * Register
42 */
43 m_pUVM = a_pDbgGui->getUvmHandle();
44 if (m_pUVM)
45 {
46 VMR3RetainUVM(m_pUVM);
47
48 int rc = VMR3AtStateRegister(m_pUVM, atStateChange, this);
49 AssertRC(rc);
50 }
51}
52
53
54VBoxDbgBase::~VBoxDbgBase()
55{
56 /*
57 * If the VM is still around.
58 */
59 /** @todo need to do some locking here? */
60 PUVM pUVM = ASMAtomicXchgPtrT(&m_pUVM, NULL, PUVM);
61 if (pUVM)
62 {
63 int rc = VMR3AtStateDeregister(pUVM, atStateChange, this);
64 AssertRC(rc);
65
66 VMR3ReleaseUVM(pUVM);
67 }
68}
69
70
71int
72VBoxDbgBase::stamReset(const QString &rPat)
73{
74 QByteArray Utf8Array = rPat.toUtf8();
75 const char *pszPat = !rPat.isEmpty() ? Utf8Array.constData() : NULL;
76 PUVM pUVM = m_pUVM;
77 if ( pUVM
78 && VMR3GetStateU(pUVM) < VMSTATE_DESTROYING)
79 return STAMR3Reset(pUVM, pszPat);
80 return VERR_INVALID_HANDLE;
81}
82
83
84int
85VBoxDbgBase::stamEnum(const QString &rPat, PFNSTAMR3ENUM pfnEnum, void *pvUser)
86{
87 QByteArray Utf8Array = rPat.toUtf8();
88 const char *pszPat = !rPat.isEmpty() ? Utf8Array.constData() : NULL;
89 PUVM pUVM = m_pUVM;
90 if ( pUVM
91 && VMR3GetStateU(pUVM) < VMSTATE_DESTROYING)
92 return STAMR3Enum(pUVM, pszPat, pfnEnum, pvUser);
93 return VERR_INVALID_HANDLE;
94}
95
96
97int
98VBoxDbgBase::dbgcCreate(PCDBGCIO pIo, unsigned fFlags)
99{
100 PUVM pUVM = m_pUVM;
101 if ( pUVM
102 && VMR3GetStateU(pUVM) < VMSTATE_DESTROYING)
103 return DBGCCreate(pUVM, pIo, fFlags);
104 return VERR_INVALID_HANDLE;
105}
106
107
108/*static*/ DECLCALLBACK(void)
109VBoxDbgBase::atStateChange(PUVM pUVM, VMSTATE enmState, VMSTATE /*enmOldState*/, void *pvUser)
110{
111 VBoxDbgBase *pThis = (VBoxDbgBase *)pvUser; NOREF(pUVM);
112 switch (enmState)
113 {
114 case VMSTATE_TERMINATED:
115 {
116 /** @todo need to do some locking here? */
117 PUVM pUVM2 = ASMAtomicXchgPtrT(&pThis->m_pUVM, NULL, PUVM);
118 if (pUVM2)
119 {
120 Assert(pUVM2 == pUVM);
121 pThis->sigTerminated();
122 VMR3ReleaseUVM(pUVM2);
123 }
124 break;
125 }
126
127 case VMSTATE_DESTROYING:
128 pThis->sigDestroying();
129 break;
130
131 default:
132 break;
133 }
134}
135
136
137void
138VBoxDbgBase::sigDestroying()
139{
140}
141
142
143void
144VBoxDbgBase::sigTerminated()
145{
146}
147
148
149
150
151//
152//
153//
154// V B o x D b g B a s e W i n d o w
155// V B o x D b g B a s e W i n d o w
156// V B o x D b g B a s e W i n d o w
157//
158//
159//
160
161unsigned VBoxDbgBaseWindow::m_cxBorder = 0;
162unsigned VBoxDbgBaseWindow::m_cyBorder = 0;
163
164
165VBoxDbgBaseWindow::VBoxDbgBaseWindow(VBoxDbgGui *a_pDbgGui, QWidget *a_pParent, const char *a_pszTitle)
166 : QWidget(a_pParent, Qt::Window), VBoxDbgBase(a_pDbgGui), m_pszTitle(a_pszTitle), m_fPolished(false)
167 , m_x(INT_MAX), m_y(INT_MAX), m_cx(0), m_cy(0)
168{
169 /* Set the title, using the parent one as prefix when possible: */
170 if (!parent())
171 {
172 QString strMachineName = a_pDbgGui->getMachineName();
173 if (strMachineName.isEmpty())
174 setWindowTitle(QString("VBoxDbg - %1").arg(m_pszTitle));
175 else
176 setWindowTitle(QString("%1 - VBoxDbg - %2").arg(strMachineName).arg(m_pszTitle));
177 }
178 else
179 {
180 setWindowTitle(QString("%1 - %2").arg(parentWidget()->windowTitle()).arg(m_pszTitle));
181
182 /* Install an event filter so we can make adjustments when the parent title changes: */
183 parent()->installEventFilter(this);
184 }
185}
186
187
188VBoxDbgBaseWindow::~VBoxDbgBaseWindow()
189{
190
191}
192
193
194void
195VBoxDbgBaseWindow::vShow()
196{
197 show();
198 /** @todo this ain't working right. HELP! */
199 setWindowState(windowState() & ~Qt::WindowMinimized);
200 //activateWindow();
201 //setFocus();
202 vPolishSizeAndPos();
203}
204
205
206void
207VBoxDbgBaseWindow::vReposition(int a_x, int a_y, unsigned a_cx, unsigned a_cy, bool a_fResize)
208{
209 if (a_fResize)
210 {
211 m_cx = a_cx;
212 m_cy = a_cy;
213
214 QSize BorderSize = frameSize() - size();
215 if (BorderSize == QSize(0,0))
216 BorderSize = vGuessBorderSizes();
217
218 resize(a_cx - BorderSize.width(), a_cy - BorderSize.height());
219 }
220
221 m_x = a_x;
222 m_y = a_y;
223 move(a_x, a_y);
224}
225
226
227bool
228VBoxDbgBaseWindow::event(QEvent *a_pEvt)
229{
230 bool fRc = QWidget::event(a_pEvt);
231 if ( a_pEvt->type() == QEvent::Paint
232 || a_pEvt->type() == QEvent::UpdateRequest
233 || a_pEvt->type() == QEvent::LayoutRequest) /** @todo Someone with Qt knowledge should figure out how to properly do this. */
234 vPolishSizeAndPos();
235 return fRc;
236}
237
238
239bool VBoxDbgBaseWindow::eventFilter(QObject *pWatched, QEvent *pEvent)
240{
241 /* We're only interested in title changes to the parent so we can amend our own title: */
242 if ( pWatched == parent()
243 && pEvent->type() == QEvent::WindowTitleChange)
244 setWindowTitle(QString("%1 - %2").arg(parentWidget()->windowTitle()).arg(m_pszTitle));
245
246 /* Forward to base-class: */
247 return QWidget::eventFilter(pWatched, pEvent);
248}
249
250
251void
252VBoxDbgBaseWindow::vPolishSizeAndPos()
253{
254 /* Ignore if already done or no size set. */
255 if ( m_fPolished
256 || (m_x == INT_MAX && m_y == INT_MAX))
257 return;
258
259 QSize BorderSize = frameSize() - size();
260 if (BorderSize != QSize(0,0))
261 m_fPolished = true;
262
263 vReposition(m_x, m_y, m_cx, m_cy, m_cx || m_cy);
264}
265
266
267QSize
268VBoxDbgBaseWindow::vGuessBorderSizes()
269{
270#ifdef Q_WS_X11 /* (from the qt gui) */
271 /*
272 * On X11, there is no way to determine frame geometry (including WM
273 * decorations) before the widget is shown for the first time. Stupidly
274 * enumerate other top level widgets to find the thickest frame.
275 */
276 if (!m_cxBorder && !m_cyBorder) /* (only till we're successful) */
277 {
278 int cxExtra = 0;
279 int cyExtra = 0;
280
281 QWidgetList WidgetList = QApplication::topLevelWidgets();
282 for (QListIterator<QWidget *> it(WidgetList); it.hasNext(); )
283 {
284 QWidget *pCurWidget = it.next();
285 if (pCurWidget->isVisible())
286 {
287 int const cxFrame = pCurWidget->frameGeometry().width() - pCurWidget->width();
288 cxExtra = qMax(cxExtra, cxFrame);
289 int const cyFrame = pCurWidget->frameGeometry().height() - pCurWidget->height();
290 cyExtra = qMax(cyExtra, cyFrame);
291 if (cyExtra && cxExtra)
292 break;
293 }
294 }
295
296 if (cxExtra || cyExtra)
297 {
298 m_cxBorder = cxExtra;
299 m_cyBorder = cyExtra;
300 }
301 }
302#endif /* X11 */
303 return QSize(m_cxBorder, m_cyBorder);
304}
305
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