VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/MachineDebuggerImpl.cpp@ 93444

Last change on this file since 93444 was 93444, checked in by vboxsync, 3 years ago

VMM,Main,HostServices: Use a function table for accessing the VBoxVMM.dll/so/dylib functionality, and load it dynamically when the Console object is initialized. Also converted a few drivers in Main to use device helpers to get config values and such. bugref:10074

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.8 KB
Line 
1/* $Id: MachineDebuggerImpl.cpp 93444 2022-01-26 18:01:15Z vboxsync $ */
2/** @file
3 * VBox IMachineDebugger COM class implementation (VBoxC).
4 */
5
6/*
7 * Copyright (C) 2006-2022 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_MAIN_MACHINEDEBUGGER
23#include "LoggingNew.h"
24
25#include "MachineDebuggerImpl.h"
26
27#include "Global.h"
28#include "ConsoleImpl.h"
29#include "ProgressImpl.h"
30
31#include "AutoCaller.h"
32
33#include <VBox/vmm/vmmr3vtable.h>
34#include <VBox/vmm/em.h>
35#include <VBox/vmm/uvm.h>
36#include <VBox/vmm/tm.h>
37#include <VBox/vmm/hm.h>
38#include <VBox/err.h>
39#include <iprt/cpp/utils.h>
40
41
42// constructor / destructor
43/////////////////////////////////////////////////////////////////////////////
44
45MachineDebugger::MachineDebugger()
46 : mParent(NULL)
47{
48}
49
50MachineDebugger::~MachineDebugger()
51{
52}
53
54HRESULT MachineDebugger::FinalConstruct()
55{
56 unconst(mParent) = NULL;
57 return BaseFinalConstruct();
58}
59
60void MachineDebugger::FinalRelease()
61{
62 uninit();
63 BaseFinalRelease();
64}
65
66// public initializer/uninitializer for internal purposes only
67/////////////////////////////////////////////////////////////////////////////
68
69/**
70 * Initializes the machine debugger object.
71 *
72 * @returns COM result indicator
73 * @param aParent handle of our parent object
74 */
75HRESULT MachineDebugger::init(Console *aParent)
76{
77 LogFlowThisFunc(("aParent=%p\n", aParent));
78
79 ComAssertRet(aParent, E_INVALIDARG);
80
81 /* Enclose the state transition NotReady->InInit->Ready */
82 AutoInitSpan autoInitSpan(this);
83 AssertReturn(autoInitSpan.isOk(), E_FAIL);
84
85 unconst(mParent) = aParent;
86
87 for (unsigned i = 0; i < RT_ELEMENTS(maiQueuedEmExecPolicyParams); i++)
88 maiQueuedEmExecPolicyParams[i] = UINT8_MAX;
89 mSingleStepQueued = -1;
90 mRecompileUserQueued = -1;
91 mRecompileSupervisorQueued = -1;
92 mPatmEnabledQueued = -1;
93 mCsamEnabledQueued = -1;
94 mLogEnabledQueued = -1;
95 mVirtualTimeRateQueued = UINT32_MAX;
96 mFlushMode = false;
97
98 m_hSampleReport = NULL;
99
100 /* Confirm a successful initialization */
101 autoInitSpan.setSucceeded();
102
103 return S_OK;
104}
105
106/**
107 * Uninitializes the instance and sets the ready flag to FALSE.
108 * Called either from FinalRelease() or by the parent when it gets destroyed.
109 */
110void MachineDebugger::uninit()
111{
112 LogFlowThisFunc(("\n"));
113
114 /* Enclose the state transition Ready->InUninit->NotReady */
115 AutoUninitSpan autoUninitSpan(this);
116 if (autoUninitSpan.uninitDone())
117 return;
118
119 unconst(mParent) = NULL;
120 mFlushMode = false;
121}
122
123/**
124 * @callback_method_impl{FNDBGFPROGRESS}
125 */
126/*static*/ DECLCALLBACK(int) MachineDebugger::i_dbgfProgressCallback(void *pvUser, unsigned uPercentage)
127{
128 MachineDebugger *pThis = (MachineDebugger *)pvUser;
129
130 int vrc = pThis->m_Progress->i_iprtProgressCallback(uPercentage, static_cast<Progress *>(pThis->m_Progress));
131 if ( RT_SUCCESS(vrc)
132 && uPercentage == 100)
133 {
134 PCVMMR3VTABLE const pVMM = pThis->mParent->i_getVMMVTable();
135 AssertPtrReturn(pVMM, VERR_INTERNAL_ERROR_3);
136
137 vrc = pVMM->pfnDBGFR3SampleReportDumpToFile(pThis->m_hSampleReport, pThis->m_strFilename.c_str());
138 pVMM->pfnDBGFR3SampleReportRelease(pThis->m_hSampleReport);
139 pThis->m_hSampleReport = NULL;
140 if (RT_SUCCESS(vrc))
141 pThis->m_Progress->i_notifyComplete(S_OK);
142 else
143 {
144 HRESULT hrc = pThis->setError(VBOX_E_IPRT_ERROR,
145 tr("Writing the sample report to '%s' failed with %Rrc"),
146 pThis->m_strFilename.c_str(), vrc);
147 pThis->m_Progress->i_notifyComplete(hrc);
148 }
149 pThis->m_Progress.setNull();
150 }
151 else if (vrc == VERR_CANCELLED)
152 vrc = VERR_DBGF_CANCELLED;
153
154 return vrc;
155}
156
157// IMachineDebugger properties
158/////////////////////////////////////////////////////////////////////////////
159
160/**
161 * Returns the current singlestepping flag.
162 *
163 * @returns COM status code
164 * @param aSingleStep Where to store the result.
165 */
166HRESULT MachineDebugger::getSingleStep(BOOL *aSingleStep)
167{
168 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
169 Console::SafeVMPtr ptrVM(mParent);
170 HRESULT hrc = ptrVM.rc();
171 if (SUCCEEDED(hrc))
172 {
173 RT_NOREF(aSingleStep); /** @todo */
174 ReturnComNotImplemented();
175 }
176 return hrc;
177}
178
179/**
180 * Sets the singlestepping flag.
181 *
182 * @returns COM status code
183 * @param aSingleStep The new state.
184 */
185HRESULT MachineDebugger::setSingleStep(BOOL aSingleStep)
186{
187 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
188 Console::SafeVMPtr ptrVM(mParent);
189 HRESULT hrc = ptrVM.rc();
190 if (SUCCEEDED(hrc))
191 {
192 NOREF(aSingleStep); /** @todo */
193 ReturnComNotImplemented();
194 }
195 return hrc;
196}
197
198/**
199 * Internal worker for getting an EM executable policy setting.
200 *
201 * @returns COM status code.
202 * @param enmPolicy Which EM policy.
203 * @param pfEnforced Where to return the policy setting.
204 */
205HRESULT MachineDebugger::i_getEmExecPolicyProperty(EMEXECPOLICY enmPolicy, BOOL *pfEnforced)
206{
207 CheckComArgOutPointerValid(pfEnforced);
208
209 AutoCaller autoCaller(this);
210 HRESULT hrc = autoCaller.rc();
211 if (SUCCEEDED(hrc))
212 {
213 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
214 if (i_queueSettings())
215 *pfEnforced = maiQueuedEmExecPolicyParams[enmPolicy] == 1;
216 else
217 {
218 bool fEnforced = false;
219 Console::SafeVMPtrQuiet ptrVM(mParent);
220 hrc = ptrVM.rc();
221 if (SUCCEEDED(hrc))
222 ptrVM.vtable()->pfnEMR3QueryExecutionPolicy(ptrVM.rawUVM(), enmPolicy, &fEnforced);
223 *pfEnforced = fEnforced;
224 }
225 }
226 return hrc;
227}
228
229/**
230 * Internal worker for setting an EM executable policy.
231 *
232 * @returns COM status code.
233 * @param enmPolicy Which policy to change.
234 * @param fEnforce Whether to enforce the policy or not.
235 */
236HRESULT MachineDebugger::i_setEmExecPolicyProperty(EMEXECPOLICY enmPolicy, BOOL fEnforce)
237{
238 AutoCaller autoCaller(this);
239 HRESULT hrc = autoCaller.rc();
240 if (SUCCEEDED(hrc))
241 {
242 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
243 if (i_queueSettings())
244 maiQueuedEmExecPolicyParams[enmPolicy] = fEnforce ? 1 : 0;
245 else
246 {
247 Console::SafeVMPtrQuiet ptrVM(mParent);
248 hrc = ptrVM.rc();
249 if (SUCCEEDED(hrc))
250 {
251 int vrc = ptrVM.vtable()->pfnEMR3SetExecutionPolicy(ptrVM.rawUVM(), enmPolicy, fEnforce != FALSE);
252 if (RT_FAILURE(vrc))
253 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("EMR3SetExecutionPolicy failed with %Rrc"), vrc);
254 }
255 }
256 }
257 return hrc;
258}
259
260/**
261 * Returns the current recompile user mode code flag.
262 *
263 * @returns COM status code
264 * @param aRecompileUser address of result variable
265 */
266HRESULT MachineDebugger::getRecompileUser(BOOL *aRecompileUser)
267{
268 return i_getEmExecPolicyProperty(EMEXECPOLICY_RECOMPILE_RING3, aRecompileUser);
269}
270
271/**
272 * Sets the recompile user mode code flag.
273 *
274 * @returns COM status
275 * @param aRecompileUser new user mode code recompile flag.
276 */
277HRESULT MachineDebugger::setRecompileUser(BOOL aRecompileUser)
278{
279 LogFlowThisFunc(("enable=%d\n", aRecompileUser));
280 return i_setEmExecPolicyProperty(EMEXECPOLICY_RECOMPILE_RING3, aRecompileUser);
281}
282
283/**
284 * Returns the current recompile supervisor code flag.
285 *
286 * @returns COM status code
287 * @param aRecompileSupervisor address of result variable
288 */
289HRESULT MachineDebugger::getRecompileSupervisor(BOOL *aRecompileSupervisor)
290{
291 return i_getEmExecPolicyProperty(EMEXECPOLICY_RECOMPILE_RING0, aRecompileSupervisor);
292}
293
294/**
295 * Sets the new recompile supervisor code flag.
296 *
297 * @returns COM status code
298 * @param aRecompileSupervisor new recompile supervisor code flag
299 */
300HRESULT MachineDebugger::setRecompileSupervisor(BOOL aRecompileSupervisor)
301{
302 LogFlowThisFunc(("enable=%d\n", aRecompileSupervisor));
303 return i_setEmExecPolicyProperty(EMEXECPOLICY_RECOMPILE_RING0, aRecompileSupervisor);
304}
305
306/**
307 * Returns the current execute-all-in-IEM setting.
308 *
309 * @returns COM status code
310 * @param aExecuteAllInIEM Address of result variable.
311 */
312HRESULT MachineDebugger::getExecuteAllInIEM(BOOL *aExecuteAllInIEM)
313{
314 return i_getEmExecPolicyProperty(EMEXECPOLICY_IEM_ALL, aExecuteAllInIEM);
315}
316
317/**
318 * Changes the execute-all-in-IEM setting.
319 *
320 * @returns COM status code
321 * @param aExecuteAllInIEM New setting.
322 */
323HRESULT MachineDebugger::setExecuteAllInIEM(BOOL aExecuteAllInIEM)
324{
325 LogFlowThisFunc(("enable=%d\n", aExecuteAllInIEM));
326 return i_setEmExecPolicyProperty(EMEXECPOLICY_IEM_ALL, aExecuteAllInIEM);
327}
328
329/**
330 * Returns the current patch manager enabled flag.
331 *
332 * @returns COM status code
333 * @param aPATMEnabled address of result variable
334 */
335HRESULT MachineDebugger::getPATMEnabled(BOOL *aPATMEnabled)
336{
337 *aPATMEnabled = false;
338 return S_OK;
339}
340
341/**
342 * Set the new patch manager enabled flag.
343 *
344 * @returns COM status code
345 * @param aPATMEnabled new patch manager enabled flag
346 */
347HRESULT MachineDebugger::setPATMEnabled(BOOL aPATMEnabled)
348{
349 LogFlowThisFunc(("enable=%d\n", aPATMEnabled));
350
351 if (aPATMEnabled)
352 return setErrorBoth(VBOX_E_VM_ERROR, VERR_RAW_MODE_NOT_SUPPORTED, tr("PATM not present"), VERR_NOT_SUPPORTED);
353 return S_OK;
354}
355
356/**
357 * Returns the current code scanner enabled flag.
358 *
359 * @returns COM status code
360 * @param aCSAMEnabled address of result variable
361 */
362HRESULT MachineDebugger::getCSAMEnabled(BOOL *aCSAMEnabled)
363{
364 *aCSAMEnabled = false;
365 return S_OK;
366}
367
368/**
369 * Sets the new code scanner enabled flag.
370 *
371 * @returns COM status code
372 * @param aCSAMEnabled new code scanner enabled flag
373 */
374HRESULT MachineDebugger::setCSAMEnabled(BOOL aCSAMEnabled)
375{
376 LogFlowThisFunc(("enable=%d\n", aCSAMEnabled));
377
378 if (aCSAMEnabled)
379 return setErrorBoth(VBOX_E_VM_ERROR, VERR_RAW_MODE_NOT_SUPPORTED, tr("CASM not present"));
380 return S_OK;
381}
382
383/**
384 * Returns the log enabled / disabled status.
385 *
386 * @returns COM status code
387 * @param aLogEnabled address of result variable
388 */
389HRESULT MachineDebugger::getLogEnabled(BOOL *aLogEnabled)
390{
391#ifdef LOG_ENABLED
392 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
393
394 const PRTLOGGER pLogInstance = RTLogDefaultInstance();
395 *aLogEnabled = pLogInstance && !(RTLogGetFlags(pLogInstance) & RTLOGFLAGS_DISABLED);
396#else
397 *aLogEnabled = false;
398#endif
399
400 return S_OK;
401}
402
403/**
404 * Enables or disables logging.
405 *
406 * @returns COM status code
407 * @param aLogEnabled The new code log state.
408 */
409HRESULT MachineDebugger::setLogEnabled(BOOL aLogEnabled)
410{
411 LogFlowThisFunc(("aLogEnabled=%d\n", aLogEnabled));
412
413 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
414
415 if (i_queueSettings())
416 {
417 // queue the request
418 mLogEnabledQueued = aLogEnabled;
419 return S_OK;
420 }
421
422 Console::SafeVMPtr ptrVM(mParent);
423 if (FAILED(ptrVM.rc())) return ptrVM.rc();
424
425#ifdef LOG_ENABLED
426 int vrc = ptrVM.vtable()->pfnDBGFR3LogModifyFlags(ptrVM.rawUVM(), aLogEnabled ? "enabled" : "disabled");
427 if (RT_FAILURE(vrc))
428 {
429 /** @todo handle error code. */
430 }
431#endif
432
433 return S_OK;
434}
435
436HRESULT MachineDebugger::i_logStringProps(PRTLOGGER pLogger, PFNLOGGETSTR pfnLogGetStr,
437 const char *pszLogGetStr, Utf8Str *pstrSettings)
438{
439 /* Make sure the VM is powered up. */
440 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
441 Console::SafeVMPtr ptrVM(mParent);
442 HRESULT hrc = ptrVM.rc();
443 if (FAILED(hrc))
444 return hrc;
445
446 /* Make sure we've got a logger. */
447 if (!pLogger)
448 {
449 *pstrSettings = "";
450 return S_OK;
451 }
452
453 /* Do the job. */
454 size_t cbBuf = _1K;
455 for (;;)
456 {
457 char *pszBuf = (char *)RTMemTmpAlloc(cbBuf);
458 AssertReturn(pszBuf, E_OUTOFMEMORY);
459 int vrc = pstrSettings->reserveNoThrow(cbBuf);
460 if (RT_SUCCESS(vrc))
461 {
462 vrc = pfnLogGetStr(pLogger, pstrSettings->mutableRaw(), cbBuf);
463 if (RT_SUCCESS(vrc))
464 {
465 pstrSettings->jolt();
466 return S_OK;
467 }
468 *pstrSettings = "";
469 AssertReturn(vrc == VERR_BUFFER_OVERFLOW,
470 setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("%s returned %Rrc"), pszLogGetStr, vrc));
471 }
472 else
473 return E_OUTOFMEMORY;
474
475 /* try again with a bigger buffer. */
476 cbBuf *= 2;
477 AssertReturn(cbBuf <= _256K, setError(E_FAIL, tr("%s returns too much data"), pszLogGetStr));
478 }
479}
480
481HRESULT MachineDebugger::getLogDbgFlags(com::Utf8Str &aLogDbgFlags)
482{
483 return i_logStringProps(RTLogGetDefaultInstance(), RTLogQueryFlags, "RTLogQueryFlags", &aLogDbgFlags);
484}
485
486HRESULT MachineDebugger::getLogDbgGroups(com::Utf8Str &aLogDbgGroups)
487{
488 return i_logStringProps(RTLogGetDefaultInstance(), RTLogQueryGroupSettings, "RTLogQueryGroupSettings", &aLogDbgGroups);
489}
490
491HRESULT MachineDebugger::getLogDbgDestinations(com::Utf8Str &aLogDbgDestinations)
492{
493 return i_logStringProps(RTLogGetDefaultInstance(), RTLogQueryDestinations, "RTLogQueryDestinations", &aLogDbgDestinations);
494}
495
496HRESULT MachineDebugger::getLogRelFlags(com::Utf8Str &aLogRelFlags)
497{
498 return i_logStringProps(RTLogRelGetDefaultInstance(), RTLogQueryFlags, "RTLogQueryFlags", &aLogRelFlags);
499}
500
501HRESULT MachineDebugger::getLogRelGroups(com::Utf8Str &aLogRelGroups)
502{
503 return i_logStringProps(RTLogRelGetDefaultInstance(), RTLogQueryGroupSettings, "RTLogQueryGroupSettings", &aLogRelGroups);
504}
505
506HRESULT MachineDebugger::getLogRelDestinations(com::Utf8Str &aLogRelDestinations)
507{
508 return i_logStringProps(RTLogRelGetDefaultInstance(), RTLogQueryDestinations, "RTLogQueryDestinations", &aLogRelDestinations);
509}
510
511/**
512 * Return the main execution engine of the VM.
513 *
514 * @returns COM status code
515 * @param apenmEngine Address of the result variable.
516 */
517HRESULT MachineDebugger::getExecutionEngine(VMExecutionEngine_T *apenmEngine)
518{
519 *apenmEngine = VMExecutionEngine_NotSet;
520
521 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
522 Console::SafeVMPtrQuiet ptrVM(mParent);
523 if (ptrVM.isOk())
524 {
525 uint8_t bEngine = UINT8_MAX;
526 int rc = ptrVM.vtable()->pfnEMR3QueryMainExecutionEngine(ptrVM.rawUVM(), &bEngine);
527 if (RT_SUCCESS(rc))
528 switch (bEngine)
529 {
530 case VM_EXEC_ENGINE_NOT_SET: *apenmEngine = VMExecutionEngine_NotSet; break;
531 case VM_EXEC_ENGINE_RAW_MODE: *apenmEngine = VMExecutionEngine_RawMode; break;
532 case VM_EXEC_ENGINE_HW_VIRT: *apenmEngine = VMExecutionEngine_HwVirt; break;
533 case VM_EXEC_ENGINE_NATIVE_API: *apenmEngine = VMExecutionEngine_NativeApi; break;
534 default: AssertMsgFailed(("bEngine=%d\n", bEngine));
535 }
536 }
537
538 return S_OK;
539}
540
541/**
542 * Returns the current hardware virtualization flag.
543 *
544 * @returns COM status code
545 * @param aHWVirtExEnabled address of result variable
546 */
547HRESULT MachineDebugger::getHWVirtExEnabled(BOOL *aHWVirtExEnabled)
548{
549 *aHWVirtExEnabled = false;
550
551 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
552 Console::SafeVMPtrQuiet ptrVM(mParent);
553 if (ptrVM.isOk())
554 {
555 uint8_t bEngine = UINT8_MAX;
556 int rc = ptrVM.vtable()->pfnEMR3QueryMainExecutionEngine(ptrVM.rawUVM(), &bEngine);
557 *aHWVirtExEnabled = RT_SUCCESS(rc) && bEngine == VM_EXEC_ENGINE_HW_VIRT;
558 }
559
560 return S_OK;
561}
562
563/**
564 * Returns the current nested paging flag.
565 *
566 * @returns COM status code
567 * @param aHWVirtExNestedPagingEnabled address of result variable
568 */
569HRESULT MachineDebugger::getHWVirtExNestedPagingEnabled(BOOL *aHWVirtExNestedPagingEnabled)
570{
571 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
572
573 Console::SafeVMPtrQuiet ptrVM(mParent);
574 if (ptrVM.isOk())
575 *aHWVirtExNestedPagingEnabled = ptrVM.vtable()->pfnHMR3IsNestedPagingActive(ptrVM.rawUVM());
576 else
577 *aHWVirtExNestedPagingEnabled = false;
578
579 return S_OK;
580}
581
582/**
583 * Returns the current VPID flag.
584 *
585 * @returns COM status code
586 * @param aHWVirtExVPIDEnabled address of result variable
587 */
588HRESULT MachineDebugger::getHWVirtExVPIDEnabled(BOOL *aHWVirtExVPIDEnabled)
589{
590 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
591
592 Console::SafeVMPtrQuiet ptrVM(mParent);
593 if (ptrVM.isOk())
594 *aHWVirtExVPIDEnabled = ptrVM.vtable()->pfnHMR3IsVpidActive(ptrVM.rawUVM());
595 else
596 *aHWVirtExVPIDEnabled = false;
597
598 return S_OK;
599}
600
601/**
602 * Returns the current unrestricted execution setting.
603 *
604 * @returns COM status code
605 * @param aHWVirtExUXEnabled address of result variable
606 */
607HRESULT MachineDebugger::getHWVirtExUXEnabled(BOOL *aHWVirtExUXEnabled)
608{
609 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
610
611 Console::SafeVMPtrQuiet ptrVM(mParent);
612 if (ptrVM.isOk())
613 *aHWVirtExUXEnabled = ptrVM.vtable()->pfnHMR3IsUXActive(ptrVM.rawUVM());
614 else
615 *aHWVirtExUXEnabled = false;
616
617 return S_OK;
618}
619
620HRESULT MachineDebugger::getOSName(com::Utf8Str &aOSName)
621{
622 LogFlowThisFunc(("\n"));
623 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
624
625 Console::SafeVMPtr ptrVM(mParent);
626 HRESULT hrc = ptrVM.rc();
627 if (SUCCEEDED(hrc))
628 {
629 /*
630 * Do the job and try convert the name.
631 */
632 char szName[64];
633 int vrc = ptrVM.vtable()->pfnDBGFR3OSQueryNameAndVersion(ptrVM.rawUVM(), szName, sizeof(szName), NULL, 0);
634 if (RT_SUCCESS(vrc))
635 hrc = aOSName.assignEx(szName);
636 else
637 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("DBGFR3OSQueryNameAndVersion failed with %Rrc"), vrc);
638 }
639 return hrc;
640}
641
642HRESULT MachineDebugger::getOSVersion(com::Utf8Str &aOSVersion)
643{
644 LogFlowThisFunc(("\n"));
645 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
646
647 Console::SafeVMPtr ptrVM(mParent);
648 HRESULT hrc = ptrVM.rc();
649 if (SUCCEEDED(hrc))
650 {
651 /*
652 * Do the job and try convert the name.
653 */
654 char szVersion[256];
655 int vrc = ptrVM.vtable()->pfnDBGFR3OSQueryNameAndVersion(ptrVM.rawUVM(), NULL, 0, szVersion, sizeof(szVersion));
656 if (RT_SUCCESS(vrc))
657 hrc = aOSVersion.assignEx(szVersion);
658 else
659 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("DBGFR3OSQueryNameAndVersion failed with %Rrc"), vrc);
660 }
661 return hrc;
662}
663
664/**
665 * Returns the current PAE flag.
666 *
667 * @returns COM status code
668 * @param aPAEEnabled address of result variable.
669 */
670HRESULT MachineDebugger::getPAEEnabled(BOOL *aPAEEnabled)
671{
672 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
673
674 Console::SafeVMPtrQuiet ptrVM(mParent);
675 if (ptrVM.isOk())
676 {
677 uint32_t cr4;
678 int rc = ptrVM.vtable()->pfnDBGFR3RegCpuQueryU32(ptrVM.rawUVM(), 0 /*idCpu*/, DBGFREG_CR4, &cr4); AssertRC(rc);
679 *aPAEEnabled = RT_BOOL(cr4 & X86_CR4_PAE);
680 }
681 else
682 *aPAEEnabled = false;
683
684 return S_OK;
685}
686
687/**
688 * Returns the current virtual time rate.
689 *
690 * @returns COM status code.
691 * @param aVirtualTimeRate Where to store the rate.
692 */
693HRESULT MachineDebugger::getVirtualTimeRate(ULONG *aVirtualTimeRate)
694{
695 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
696
697 Console::SafeVMPtr ptrVM(mParent);
698 HRESULT hrc = ptrVM.rc();
699 if (SUCCEEDED(hrc))
700 *aVirtualTimeRate = ptrVM.vtable()->pfnTMR3GetWarpDrive(ptrVM.rawUVM());
701
702 return hrc;
703}
704
705/**
706 * Set the virtual time rate.
707 *
708 * @returns COM status code.
709 * @param aVirtualTimeRate The new rate.
710 */
711HRESULT MachineDebugger::setVirtualTimeRate(ULONG aVirtualTimeRate)
712{
713 HRESULT hrc = S_OK;
714
715 if (aVirtualTimeRate < 2 || aVirtualTimeRate > 20000)
716 return setError(E_INVALIDARG, tr("%u is out of range [2..20000]"), aVirtualTimeRate);
717
718 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
719 if (i_queueSettings())
720 mVirtualTimeRateQueued = aVirtualTimeRate;
721 else
722 {
723 Console::SafeVMPtr ptrVM(mParent);
724 hrc = ptrVM.rc();
725 if (SUCCEEDED(hrc))
726 {
727 int vrc = ptrVM.vtable()->pfnTMR3SetWarpDrive(ptrVM.rawUVM(), aVirtualTimeRate);
728 if (RT_FAILURE(vrc))
729 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("TMR3SetWarpDrive(, %u) failed with rc=%Rrc"), aVirtualTimeRate, vrc);
730 }
731 }
732
733 return hrc;
734}
735
736/**
737 * Hack for getting the user mode VM handle (UVM).
738 *
739 * This is only temporary (promise) while prototyping the debugger.
740 *
741 * @returns COM status code
742 * @param aVM Where to store the vm handle. Since there is no
743 * uintptr_t in COM, we're using the max integer.
744 * (No, ULONG is not pointer sized!)
745 * @remarks The returned handle must be passed to VMR3ReleaseUVM()!
746 * @remarks Prior to 4.3 this returned PVM.
747 */
748HRESULT MachineDebugger::getVM(LONG64 *aVM)
749{
750 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
751
752 Console::SafeVMPtr ptrVM(mParent);
753 HRESULT hrc = ptrVM.rc();
754 if (SUCCEEDED(hrc))
755 {
756 ptrVM.vtable()->pfnVMR3RetainUVM(ptrVM.rawUVM());
757 *aVM = (intptr_t)ptrVM.rawUVM();
758 }
759
760 /*
761 * Note! ptrVM protection provided by SafeVMPtr is no long effective
762 * after we return from this method.
763 */
764 return hrc;
765}
766
767/**
768 * Get the VM uptime in milliseconds.
769 *
770 * @returns COM status code
771 * @param aUptime Where to store the uptime.
772 */
773HRESULT MachineDebugger::getUptime(LONG64 *aUptime)
774{
775 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
776
777 Console::SafeVMPtr ptrVM(mParent);
778 HRESULT hrc = ptrVM.rc();
779 if (SUCCEEDED(hrc))
780 *aUptime = (int64_t)ptrVM.vtable()->pfnTMR3TimeVirtGetMilli(ptrVM.rawUVM());
781
782 return hrc;
783}
784
785// IMachineDebugger methods
786/////////////////////////////////////////////////////////////////////////////
787
788HRESULT MachineDebugger::dumpGuestCore(const com::Utf8Str &aFilename, const com::Utf8Str &aCompression)
789{
790 if (aCompression.length())
791 return setError(E_INVALIDARG, tr("The compression parameter must be empty"));
792
793 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
794 Console::SafeVMPtr ptrVM(mParent);
795 HRESULT hrc = ptrVM.rc();
796 if (SUCCEEDED(hrc))
797 {
798 int vrc = ptrVM.vtable()->pfnDBGFR3CoreWrite(ptrVM.rawUVM(), aFilename.c_str(), false /*fReplaceFile*/);
799 if (RT_SUCCESS(vrc))
800 hrc = S_OK;
801 else
802 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3CoreWrite failed with %Rrc"), vrc);
803 }
804
805 return hrc;
806}
807
808HRESULT MachineDebugger::dumpHostProcessCore(const com::Utf8Str &aFilename, const com::Utf8Str &aCompression)
809{
810 RT_NOREF(aFilename, aCompression);
811 ReturnComNotImplemented();
812}
813
814/**
815 * Debug info string buffer formatter.
816 */
817typedef struct MACHINEDEBUGGERINOFHLP
818{
819 /** The core info helper structure. */
820 DBGFINFOHLP Core;
821 /** Pointer to the buffer. */
822 char *pszBuf;
823 /** The size of the buffer. */
824 size_t cbBuf;
825 /** The offset into the buffer */
826 size_t offBuf;
827 /** Indicates an out-of-memory condition. */
828 bool fOutOfMemory;
829} MACHINEDEBUGGERINOFHLP;
830/** Pointer to a Debug info string buffer formatter. */
831typedef MACHINEDEBUGGERINOFHLP *PMACHINEDEBUGGERINOFHLP;
832
833
834/**
835 * @callback_method_impl{FNRTSTROUTPUT}
836 */
837static DECLCALLBACK(size_t) MachineDebuggerInfoOutput(void *pvArg, const char *pachChars, size_t cbChars)
838{
839 PMACHINEDEBUGGERINOFHLP pHlp = (PMACHINEDEBUGGERINOFHLP)pvArg;
840
841 /*
842 * Grow the buffer if required.
843 */
844 size_t const cbRequired = cbChars + pHlp->offBuf + 1;
845 if (cbRequired > pHlp->cbBuf)
846 {
847 if (RT_UNLIKELY(pHlp->fOutOfMemory))
848 return 0;
849
850 size_t cbBufNew = pHlp->cbBuf * 2;
851 if (cbRequired > cbBufNew)
852 cbBufNew = RT_ALIGN_Z(cbRequired, 256);
853 void *pvBufNew = RTMemRealloc(pHlp->pszBuf, cbBufNew);
854 if (RT_UNLIKELY(!pvBufNew))
855 {
856 pHlp->fOutOfMemory = true;
857 RTMemFree(pHlp->pszBuf);
858 pHlp->pszBuf = NULL;
859 pHlp->cbBuf = 0;
860 pHlp->offBuf = 0;
861 return 0;
862 }
863
864 pHlp->pszBuf = (char *)pvBufNew;
865 pHlp->cbBuf = cbBufNew;
866 }
867
868 /*
869 * Copy the bytes into the buffer and terminate it.
870 */
871 if (cbChars)
872 {
873 memcpy(&pHlp->pszBuf[pHlp->offBuf], pachChars, cbChars);
874 pHlp->offBuf += cbChars;
875 }
876 pHlp->pszBuf[pHlp->offBuf] = '\0';
877 Assert(pHlp->offBuf < pHlp->cbBuf);
878 return cbChars;
879}
880
881/**
882 * @interface_method_impl{DBGFINFOHLP,pfnPrintfV}
883 */
884static DECLCALLBACK(void) MachineDebuggerInfoPrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
885{
886 RTStrFormatV(MachineDebuggerInfoOutput, (void *)pHlp, NULL, NULL, pszFormat, args);
887}
888
889/**
890 * @interface_method_impl{DBGFINFOHLP,pfnPrintf}
891 */
892static DECLCALLBACK(void) MachineDebuggerInfoPrintf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
893{
894 va_list va;
895 va_start(va, pszFormat);
896 MachineDebuggerInfoPrintfV(pHlp, pszFormat, va);
897 va_end(va);
898}
899
900/**
901 * Initializes the debug info string buffer formatter
902 *
903 * @param pHlp The help structure to init.
904 */
905static void MachineDebuggerInfoInit(PMACHINEDEBUGGERINOFHLP pHlp, PCVMMR3VTABLE pVMM)
906{
907 pHlp->Core.pfnPrintf = MachineDebuggerInfoPrintf;
908 pHlp->Core.pfnPrintfV = MachineDebuggerInfoPrintfV;
909 pHlp->Core.pfnGetOptError = pVMM->pfnDBGFR3InfoGenericGetOptError;
910 pHlp->pszBuf = NULL;
911 pHlp->cbBuf = 0;
912 pHlp->offBuf = 0;
913 pHlp->fOutOfMemory = false;
914}
915
916/**
917 * Deletes the debug info string buffer formatter.
918 * @param pHlp The helper structure to delete.
919 */
920static void MachineDebuggerInfoDelete(PMACHINEDEBUGGERINOFHLP pHlp)
921{
922 RTMemFree(pHlp->pszBuf);
923 pHlp->pszBuf = NULL;
924}
925
926HRESULT MachineDebugger::info(const com::Utf8Str &aName, const com::Utf8Str &aArgs, com::Utf8Str &aInfo)
927{
928 LogFlowThisFunc(("\n"));
929
930 /*
931 * Do the autocaller and lock bits.
932 */
933 AutoCaller autoCaller(this);
934 HRESULT hrc = autoCaller.rc();
935 if (SUCCEEDED(hrc))
936 {
937 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
938 Console::SafeVMPtr ptrVM(mParent);
939 hrc = ptrVM.rc();
940 if (SUCCEEDED(hrc))
941 {
942 /*
943 * Create a helper and call DBGFR3Info.
944 */
945 MACHINEDEBUGGERINOFHLP Hlp;
946 MachineDebuggerInfoInit(&Hlp, ptrVM.vtable());
947 int vrc = ptrVM.vtable()->pfnDBGFR3Info(ptrVM.rawUVM(), aName.c_str(), aArgs.c_str(), &Hlp.Core);
948 if (RT_SUCCESS(vrc))
949 {
950 if (!Hlp.fOutOfMemory)
951 hrc = aInfo.assignEx(Hlp.pszBuf);
952 else
953 hrc = E_OUTOFMEMORY;
954 }
955 else
956 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("DBGFR3Info failed with %Rrc"), vrc);
957 MachineDebuggerInfoDelete(&Hlp);
958 }
959 }
960 return hrc;
961}
962
963HRESULT MachineDebugger::injectNMI()
964{
965 LogFlowThisFunc(("\n"));
966
967 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
968 Console::SafeVMPtr ptrVM(mParent);
969 HRESULT hrc = ptrVM.rc();
970 if (SUCCEEDED(hrc))
971 {
972 int vrc = ptrVM.vtable()->pfnDBGFR3InjectNMI(ptrVM.rawUVM(), 0);
973 if (RT_SUCCESS(vrc))
974 hrc = S_OK;
975 else
976 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3InjectNMI failed with %Rrc"), vrc);
977 }
978 return hrc;
979}
980
981HRESULT MachineDebugger::modifyLogFlags(const com::Utf8Str &aSettings)
982{
983 LogFlowThisFunc(("aSettings=%s\n", aSettings.c_str()));
984 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
985 Console::SafeVMPtr ptrVM(mParent);
986 HRESULT hrc = ptrVM.rc();
987 if (SUCCEEDED(hrc))
988 {
989 int vrc = ptrVM.vtable()->pfnDBGFR3LogModifyFlags(ptrVM.rawUVM(), aSettings.c_str());
990 if (RT_SUCCESS(vrc))
991 hrc = S_OK;
992 else
993 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3LogModifyFlags failed with %Rrc"), vrc);
994 }
995 return hrc;
996}
997
998HRESULT MachineDebugger::modifyLogGroups(const com::Utf8Str &aSettings)
999{
1000 LogFlowThisFunc(("aSettings=%s\n", aSettings.c_str()));
1001 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1002 Console::SafeVMPtr ptrVM(mParent);
1003 HRESULT hrc = ptrVM.rc();
1004 if (SUCCEEDED(hrc))
1005 {
1006 int vrc = ptrVM.vtable()->pfnDBGFR3LogModifyGroups(ptrVM.rawUVM(), aSettings.c_str());
1007 if (RT_SUCCESS(vrc))
1008 hrc = S_OK;
1009 else
1010 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3LogModifyGroups failed with %Rrc"), vrc);
1011 }
1012 return hrc;
1013}
1014
1015HRESULT MachineDebugger::modifyLogDestinations(const com::Utf8Str &aSettings)
1016{
1017 LogFlowThisFunc(("aSettings=%s\n", aSettings.c_str()));
1018 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1019 Console::SafeVMPtr ptrVM(mParent);
1020 HRESULT hrc = ptrVM.rc();
1021 if (SUCCEEDED(hrc))
1022 {
1023 int vrc = ptrVM.vtable()->pfnDBGFR3LogModifyDestinations(ptrVM.rawUVM(), aSettings.c_str());
1024 if (RT_SUCCESS(vrc))
1025 hrc = S_OK;
1026 else
1027 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3LogModifyDestinations failed with %Rrc"), vrc);
1028 }
1029 return hrc;
1030}
1031
1032HRESULT MachineDebugger::readPhysicalMemory(LONG64 aAddress, ULONG aSize, std::vector<BYTE> &aBytes)
1033{
1034 RT_NOREF(aAddress, aSize, aBytes);
1035 ReturnComNotImplemented();
1036}
1037
1038HRESULT MachineDebugger::writePhysicalMemory(LONG64 aAddress, ULONG aSize, const std::vector<BYTE> &aBytes)
1039{
1040 RT_NOREF(aAddress, aSize, aBytes);
1041 ReturnComNotImplemented();
1042}
1043
1044HRESULT MachineDebugger::readVirtualMemory(ULONG aCpuId, LONG64 aAddress, ULONG aSize, std::vector<BYTE> &aBytes)
1045{
1046 RT_NOREF(aCpuId, aAddress, aSize, aBytes);
1047 ReturnComNotImplemented();
1048}
1049
1050HRESULT MachineDebugger::writeVirtualMemory(ULONG aCpuId, LONG64 aAddress, ULONG aSize, const std::vector<BYTE> &aBytes)
1051{
1052 RT_NOREF(aCpuId, aAddress, aSize, aBytes);
1053 ReturnComNotImplemented();
1054}
1055
1056HRESULT MachineDebugger::loadPlugIn(const com::Utf8Str &aName, com::Utf8Str &aPlugInName)
1057{
1058 /*
1059 * Lock the debugger and get the VM pointer
1060 */
1061 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1062 Console::SafeVMPtr ptrVM(mParent);
1063 HRESULT hrc = ptrVM.rc();
1064 if (SUCCEEDED(hrc))
1065 {
1066 /*
1067 * Do the job and try convert the name.
1068 */
1069 if (aName.equals("all"))
1070 {
1071 ptrVM.vtable()->pfnDBGFR3PlugInLoadAll(ptrVM.rawUVM());
1072 hrc = aPlugInName.assignEx("all");
1073 }
1074 else
1075 {
1076 RTERRINFOSTATIC ErrInfo;
1077 char szName[80];
1078 int vrc = ptrVM.vtable()->pfnDBGFR3PlugInLoad(ptrVM.rawUVM(), aName.c_str(), szName, sizeof(szName), RTErrInfoInitStatic(&ErrInfo));
1079 if (RT_SUCCESS(vrc))
1080 hrc = aPlugInName.assignEx(szName);
1081 else
1082 hrc = setErrorVrc(vrc, "%s", ErrInfo.szMsg);
1083 }
1084 }
1085 return hrc;
1086
1087}
1088
1089HRESULT MachineDebugger::unloadPlugIn(const com::Utf8Str &aName)
1090{
1091 /*
1092 * Lock the debugger and get the VM pointer
1093 */
1094 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1095 Console::SafeVMPtr ptrVM(mParent);
1096 HRESULT hrc = ptrVM.rc();
1097 if (SUCCEEDED(hrc))
1098 {
1099 /*
1100 * Do the job and try convert the name.
1101 */
1102 if (aName.equals("all"))
1103 {
1104 ptrVM.vtable()->pfnDBGFR3PlugInUnloadAll(ptrVM.rawUVM());
1105 hrc = S_OK;
1106 }
1107 else
1108 {
1109 int vrc = ptrVM.vtable()->pfnDBGFR3PlugInUnload(ptrVM.rawUVM(), aName.c_str());
1110 if (RT_SUCCESS(vrc))
1111 hrc = S_OK;
1112 else if (vrc == VERR_NOT_FOUND)
1113 hrc = setErrorBoth(E_FAIL, vrc, tr("Plug-in '%s' was not found"), aName.c_str());
1114 else
1115 hrc = setErrorVrc(vrc, tr("Error unloading '%s': %Rrc"), aName.c_str(), vrc);
1116 }
1117 }
1118 return hrc;
1119
1120}
1121
1122HRESULT MachineDebugger::detectOS(com::Utf8Str &aOs)
1123{
1124 LogFlowThisFunc(("\n"));
1125
1126 /*
1127 * Lock the debugger and get the VM pointer
1128 */
1129 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1130 Console::SafeVMPtr ptrVM(mParent);
1131 HRESULT hrc = ptrVM.rc();
1132 if (SUCCEEDED(hrc))
1133 {
1134 /*
1135 * Do the job.
1136 */
1137 char szName[64];
1138 int vrc = ptrVM.vtable()->pfnDBGFR3OSDetect(ptrVM.rawUVM(), szName, sizeof(szName));
1139 if (RT_SUCCESS(vrc) && vrc != VINF_DBGF_OS_NOT_DETCTED)
1140 hrc = aOs.assignEx(szName);
1141 else
1142 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("DBGFR3OSDetect failed with %Rrc"), vrc);
1143 }
1144 return hrc;
1145}
1146
1147HRESULT MachineDebugger::queryOSKernelLog(ULONG aMaxMessages, com::Utf8Str &aDmesg)
1148{
1149 /*
1150 * Lock the debugger and get the VM pointer
1151 */
1152 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1153 Console::SafeVMPtr ptrVM(mParent);
1154 HRESULT hrc = ptrVM.rc();
1155 if (SUCCEEDED(hrc))
1156 {
1157 PDBGFOSIDMESG pDmesg = (PDBGFOSIDMESG)ptrVM.vtable()->pfnDBGFR3OSQueryInterface(ptrVM.rawUVM(), DBGFOSINTERFACE_DMESG);
1158 if (pDmesg)
1159 {
1160 size_t cbActual;
1161 size_t cbBuf = _512K;
1162 int vrc = aDmesg.reserveNoThrow(cbBuf);
1163 if (RT_SUCCESS(vrc))
1164 {
1165 uint32_t cMessages = aMaxMessages == 0 ? UINT32_MAX : aMaxMessages;
1166 vrc = pDmesg->pfnQueryKernelLog(pDmesg, ptrVM.rawUVM(), 0 /*fFlags*/, cMessages,
1167 aDmesg.mutableRaw(), cbBuf, &cbActual);
1168
1169 uint32_t cTries = 10;
1170 while (vrc == VERR_BUFFER_OVERFLOW && cbBuf < 16*_1M && cTries-- > 0)
1171 {
1172 cbBuf = RT_ALIGN_Z(cbActual + _4K, _4K);
1173 vrc = aDmesg.reserveNoThrow(cbBuf);
1174 if (RT_SUCCESS(vrc))
1175 vrc = pDmesg->pfnQueryKernelLog(pDmesg, ptrVM.rawUVM(), 0 /*fFlags*/, cMessages,
1176 aDmesg.mutableRaw(), cbBuf, &cbActual);
1177 }
1178 if (RT_SUCCESS(vrc))
1179 aDmesg.jolt();
1180 else if (vrc == VERR_BUFFER_OVERFLOW)
1181 hrc = setError(E_FAIL, tr("Too much log available, must use the maxMessages parameter to restrict."));
1182 else
1183 hrc = setErrorVrc(vrc);
1184 }
1185 else
1186 hrc = setErrorBoth(E_OUTOFMEMORY, vrc);
1187 }
1188 else
1189 hrc = setError(E_FAIL, tr("The dmesg interface isn't implemented by guest OS digger, or detectOS() has not been called."));
1190 }
1191 return hrc;
1192}
1193
1194HRESULT MachineDebugger::getRegister(ULONG aCpuId, const com::Utf8Str &aName, com::Utf8Str &aValue)
1195{
1196 /*
1197 * The prologue.
1198 */
1199 LogFlowThisFunc(("\n"));
1200 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1201 Console::SafeVMPtr ptrVM(mParent);
1202 HRESULT hrc = ptrVM.rc();
1203 if (SUCCEEDED(hrc))
1204 {
1205 /*
1206 * Real work.
1207 */
1208 DBGFREGVAL Value;
1209 DBGFREGVALTYPE enmType;
1210 int vrc = ptrVM.vtable()->pfnDBGFR3RegNmQuery(ptrVM.rawUVM(), aCpuId, aName.c_str(), &Value, &enmType);
1211 if (RT_SUCCESS(vrc))
1212 {
1213 char szHex[160];
1214 ssize_t cch = ptrVM.vtable()->pfnDBGFR3RegFormatValue(szHex, sizeof(szHex), &Value, enmType, true /*fSpecial*/);
1215 if (cch > 0)
1216 hrc = aValue.assignEx(szHex);
1217 else
1218 hrc = E_UNEXPECTED;
1219 }
1220 else if (vrc == VERR_DBGF_REGISTER_NOT_FOUND)
1221 hrc = setErrorBoth(E_FAIL, vrc, tr("Register '%s' was not found"), aName.c_str());
1222 else if (vrc == VERR_INVALID_CPU_ID)
1223 hrc = setErrorBoth(E_FAIL, vrc, tr("Invalid CPU ID: %u"), aCpuId);
1224 else
1225 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc,
1226 tr("DBGFR3RegNmQuery failed with rc=%Rrc querying register '%s' with default cpu set to %u"),
1227 vrc, aName.c_str(), aCpuId);
1228 }
1229
1230 return hrc;
1231}
1232
1233HRESULT MachineDebugger::getRegisters(ULONG aCpuId, std::vector<com::Utf8Str> &aNames, std::vector<com::Utf8Str> &aValues)
1234{
1235 RT_NOREF(aCpuId); /** @todo fix missing aCpuId usage! */
1236
1237 /*
1238 * The prologue.
1239 */
1240 LogFlowThisFunc(("\n"));
1241 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1242 Console::SafeVMPtr ptrVM(mParent);
1243 HRESULT hrc = ptrVM.rc();
1244 if (SUCCEEDED(hrc))
1245 {
1246 /*
1247 * Real work.
1248 */
1249 size_t cRegs;
1250 int vrc = ptrVM.vtable()->pfnDBGFR3RegNmQueryAllCount(ptrVM.rawUVM(), &cRegs);
1251 if (RT_SUCCESS(vrc))
1252 {
1253 PDBGFREGENTRYNM paRegs = (PDBGFREGENTRYNM)RTMemAllocZ(sizeof(paRegs[0]) * cRegs);
1254 if (paRegs)
1255 {
1256 vrc = ptrVM.vtable()->pfnDBGFR3RegNmQueryAll(ptrVM.rawUVM(), paRegs, cRegs);
1257 if (RT_SUCCESS(vrc))
1258 {
1259 try
1260 {
1261 aValues.resize(cRegs);
1262 aNames.resize(cRegs);
1263 for (uint32_t iReg = 0; iReg < cRegs; iReg++)
1264 {
1265 char szHex[160];
1266 szHex[159] = szHex[0] = '\0';
1267 ssize_t cch = ptrVM.vtable()->pfnDBGFR3RegFormatValue(szHex, sizeof(szHex), &paRegs[iReg].Val,
1268 paRegs[iReg].enmType, true /*fSpecial*/);
1269 Assert(cch > 0); NOREF(cch);
1270 aNames[iReg] = paRegs[iReg].pszName;
1271 aValues[iReg] = szHex;
1272 }
1273 }
1274 catch (std::bad_alloc &)
1275 {
1276 hrc = E_OUTOFMEMORY;
1277 }
1278 }
1279 else
1280 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3RegNmQueryAll failed with %Rrc"), vrc);
1281
1282 RTMemFree(paRegs);
1283 }
1284 else
1285 hrc = E_OUTOFMEMORY;
1286 }
1287 else
1288 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3RegNmQueryAllCount failed with %Rrc"), vrc);
1289 }
1290 return hrc;
1291}
1292
1293HRESULT MachineDebugger::setRegister(ULONG aCpuId, const com::Utf8Str &aName, const com::Utf8Str &aValue)
1294{
1295 RT_NOREF(aCpuId, aName, aValue);
1296 ReturnComNotImplemented();
1297}
1298
1299HRESULT MachineDebugger::setRegisters(ULONG aCpuId, const std::vector<com::Utf8Str> &aNames,
1300 const std::vector<com::Utf8Str> &aValues)
1301{
1302 RT_NOREF(aCpuId, aNames, aValues);
1303 ReturnComNotImplemented();
1304}
1305
1306HRESULT MachineDebugger::dumpGuestStack(ULONG aCpuId, com::Utf8Str &aStack)
1307{
1308 /*
1309 * The prologue.
1310 */
1311 LogFlowThisFunc(("\n"));
1312 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1313 Console::SafeVMPtr ptrVM(mParent);
1314 HRESULT hrc = ptrVM.rc();
1315 if (SUCCEEDED(hrc))
1316 {
1317 /*
1318 * There is currently a problem with the windows diggers and SMP, where
1319 * guest driver memory is being read from CPU zero in order to ensure that
1320 * we've got a consisten virtual memory view. If one of the other CPUs
1321 * initiates a rendezvous while we're unwinding the stack and trying to
1322 * read guest driver memory, we will deadlock.
1323 *
1324 * So, check the VM state and maybe suspend the VM before we continue.
1325 */
1326 int vrc = VINF_SUCCESS;
1327 bool fPaused = false;
1328 if (aCpuId != 0)
1329 {
1330 VMSTATE enmVmState = ptrVM.vtable()->pfnVMR3GetStateU(ptrVM.rawUVM());
1331 if ( enmVmState == VMSTATE_RUNNING
1332 || enmVmState == VMSTATE_RUNNING_LS)
1333 {
1334 alock.release();
1335 vrc = ptrVM.vtable()->pfnVMR3Suspend(ptrVM.rawUVM(), VMSUSPENDREASON_USER);
1336 alock.acquire();
1337 fPaused = RT_SUCCESS(vrc);
1338 }
1339 }
1340 if (RT_SUCCESS(vrc))
1341 {
1342 PCDBGFSTACKFRAME pFirstFrame;
1343 vrc = ptrVM.vtable()->pfnDBGFR3StackWalkBegin(ptrVM.rawUVM(), aCpuId, DBGFCODETYPE_GUEST, &pFirstFrame);
1344 if (RT_SUCCESS(vrc))
1345 {
1346 /*
1347 * Print header.
1348 */
1349 try
1350 {
1351 uint32_t fBitFlags = 0;
1352 for (PCDBGFSTACKFRAME pFrame = pFirstFrame;
1353 pFrame;
1354 pFrame = ptrVM.vtable()->pfnDBGFR3StackWalkNext(pFrame))
1355 {
1356 uint32_t const fCurBitFlags = pFrame->fFlags & (DBGFSTACKFRAME_FLAGS_16BIT | DBGFSTACKFRAME_FLAGS_32BIT | DBGFSTACKFRAME_FLAGS_64BIT);
1357 if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_16BIT)
1358 {
1359 if (fCurBitFlags != fBitFlags)
1360 aStack.append("SS:BP Ret SS:BP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n");
1361 aStack.appendPrintf("%04RX16:%04RX16 %04RX16:%04RX16 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
1362 pFrame->AddrFrame.Sel,
1363 (uint16_t)pFrame->AddrFrame.off,
1364 pFrame->AddrReturnFrame.Sel,
1365 (uint16_t)pFrame->AddrReturnFrame.off,
1366 (uint32_t)pFrame->AddrReturnPC.Sel,
1367 (uint32_t)pFrame->AddrReturnPC.off,
1368 pFrame->Args.au32[0],
1369 pFrame->Args.au32[1],
1370 pFrame->Args.au32[2],
1371 pFrame->Args.au32[3]);
1372 }
1373 else if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_32BIT)
1374 {
1375 if (fCurBitFlags != fBitFlags)
1376 aStack.append("EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n");
1377 aStack.appendPrintf("%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
1378 (uint32_t)pFrame->AddrFrame.off,
1379 (uint32_t)pFrame->AddrReturnFrame.off,
1380 (uint32_t)pFrame->AddrReturnPC.Sel,
1381 (uint32_t)pFrame->AddrReturnPC.off,
1382 pFrame->Args.au32[0],
1383 pFrame->Args.au32[1],
1384 pFrame->Args.au32[2],
1385 pFrame->Args.au32[3]);
1386 }
1387 else if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_64BIT)
1388 {
1389 if (fCurBitFlags != fBitFlags)
1390 aStack.append("RBP Ret SS:RBP Ret RIP CS:RIP / Symbol [line]\n");
1391 aStack.appendPrintf("%016RX64 %04RX16:%016RX64 %016RX64",
1392 (uint64_t)pFrame->AddrFrame.off,
1393 pFrame->AddrReturnFrame.Sel,
1394 (uint64_t)pFrame->AddrReturnFrame.off,
1395 (uint64_t)pFrame->AddrReturnPC.off);
1396 }
1397
1398 if (!pFrame->pSymPC)
1399 aStack.appendPrintf(fCurBitFlags & DBGFSTACKFRAME_FLAGS_64BIT
1400 ? " %RTsel:%016RGv"
1401 : fCurBitFlags & DBGFSTACKFRAME_FLAGS_32BIT
1402 ? " %RTsel:%08RGv"
1403 : " %RTsel:%04RGv"
1404 , pFrame->AddrPC.Sel, pFrame->AddrPC.off);
1405 else
1406 {
1407 RTGCINTPTR offDisp = pFrame->AddrPC.FlatPtr - pFrame->pSymPC->Value; /** @todo this isn't 100% correct for segmented stuff. */
1408 if (offDisp > 0)
1409 aStack.appendPrintf(" %s+%llx", pFrame->pSymPC->szName, (int64_t)offDisp);
1410 else if (offDisp < 0)
1411 aStack.appendPrintf(" %s-%llx", pFrame->pSymPC->szName, -(int64_t)offDisp);
1412 else
1413 aStack.appendPrintf(" %s", pFrame->pSymPC->szName);
1414 }
1415 if (pFrame->pLinePC)
1416 aStack.appendPrintf(" [%s @ 0i%d]", pFrame->pLinePC->szFilename, pFrame->pLinePC->uLineNo);
1417 aStack.append("\n");
1418
1419 fBitFlags = fCurBitFlags;
1420 }
1421 }
1422 catch (std::bad_alloc &)
1423 {
1424 hrc = E_OUTOFMEMORY;
1425 }
1426
1427 ptrVM.vtable()->pfnDBGFR3StackWalkEnd(pFirstFrame);
1428 }
1429 else
1430 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3StackWalkBegin failed with %Rrc"), vrc);
1431
1432 /*
1433 * Resume the VM if we suspended it.
1434 */
1435 if (fPaused)
1436 {
1437 alock.release();
1438 ptrVM.vtable()->pfnVMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_USER);
1439 }
1440 }
1441 else
1442 hrc = setErrorBoth(E_FAIL, vrc, tr("Suspending the VM failed with %Rrc\n"), vrc);
1443 }
1444
1445 return hrc;
1446}
1447
1448/**
1449 * Resets VM statistics.
1450 *
1451 * @returns COM status code.
1452 * @param aPattern The selection pattern. A bit similar to filename globbing.
1453 */
1454HRESULT MachineDebugger::resetStats(const com::Utf8Str &aPattern)
1455{
1456 Console::SafeVMPtrQuiet ptrVM(mParent);
1457 if (!ptrVM.isOk())
1458 return setError(VBOX_E_INVALID_VM_STATE, tr("Machine is not running"));
1459
1460 ptrVM.vtable()->pfnSTAMR3Reset(ptrVM.rawUVM(), aPattern.c_str());
1461
1462 return S_OK;
1463}
1464
1465/**
1466 * Dumps VM statistics to the log.
1467 *
1468 * @returns COM status code.
1469 * @param aPattern The selection pattern. A bit similar to filename globbing.
1470 */
1471HRESULT MachineDebugger::dumpStats(const com::Utf8Str &aPattern)
1472{
1473 Console::SafeVMPtrQuiet ptrVM(mParent);
1474 if (!ptrVM.isOk())
1475 return setError(VBOX_E_INVALID_VM_STATE, tr("Machine is not running"));
1476
1477 ptrVM.vtable()->pfnSTAMR3Dump(ptrVM.rawUVM(), aPattern.c_str());
1478
1479 return S_OK;
1480}
1481
1482/**
1483 * Get the VM statistics in an XML format.
1484 *
1485 * @returns COM status code.
1486 * @param aPattern The selection pattern. A bit similar to filename globbing.
1487 * @param aWithDescriptions Whether to include the descriptions.
1488 * @param aStats The XML document containing the statistics.
1489 */
1490HRESULT MachineDebugger::getStats(const com::Utf8Str &aPattern, BOOL aWithDescriptions, com::Utf8Str &aStats)
1491{
1492 Console::SafeVMPtrQuiet ptrVM(mParent);
1493 if (!ptrVM.isOk())
1494 return setError(VBOX_E_INVALID_VM_STATE, tr("Machine is not running"));
1495
1496 char *pszSnapshot;
1497 int vrc = ptrVM.vtable()->pfnSTAMR3Snapshot(ptrVM.rawUVM(), aPattern.c_str(), &pszSnapshot, NULL, !!aWithDescriptions);
1498 if (RT_FAILURE(vrc))
1499 return vrc == VERR_NO_MEMORY ? E_OUTOFMEMORY : E_FAIL;
1500
1501 /** @todo this is horribly inefficient! And it's kinda difficult to tell whether it failed...
1502 * Must use UTF-8 or ASCII here and completely avoid these two extra copy operations.
1503 * Until that's done, this method is kind of useless for debugger statistics GUI because
1504 * of the amount statistics in a debug build. */
1505 HRESULT hrc = aStats.assignEx(pszSnapshot);
1506 ptrVM.vtable()->pfnSTAMR3SnapshotFree(ptrVM.rawUVM(), pszSnapshot);
1507
1508 return hrc;
1509}
1510
1511
1512/** Wrapper around TMR3GetCpuLoadPercents. */
1513HRESULT MachineDebugger::getCPULoad(ULONG aCpuId, ULONG *aPctExecuting, ULONG *aPctHalted, ULONG *aPctOther, LONG64 *aMsInterval)
1514{
1515 HRESULT hrc;
1516 Console::SafeVMPtrQuiet ptrVM(mParent);
1517 if (ptrVM.isOk())
1518 {
1519 uint8_t uPctExecuting = 0;
1520 uint8_t uPctHalted = 0;
1521 uint8_t uPctOther = 0;
1522 uint64_t msInterval = 0;
1523 int vrc = ptrVM.vtable()->pfnTMR3GetCpuLoadPercents(ptrVM.rawUVM(), aCpuId >= UINT32_MAX / 2 ? VMCPUID_ALL : aCpuId,
1524 &msInterval, &uPctExecuting, &uPctHalted, &uPctOther);
1525 if (RT_SUCCESS(vrc))
1526 {
1527 *aPctExecuting = uPctExecuting;
1528 *aPctHalted = uPctHalted;
1529 *aPctOther = uPctOther;
1530 *aMsInterval = msInterval;
1531 hrc = S_OK;
1532 }
1533 else
1534 hrc = setErrorVrc(vrc);
1535 }
1536 else
1537 hrc = setError(VBOX_E_INVALID_VM_STATE, tr("Machine is not running"));
1538 return hrc;
1539}
1540
1541
1542HRESULT MachineDebugger::takeGuestSample(const com::Utf8Str &aFilename, ULONG aUsInterval, LONG64 aUsSampleTime, ComPtr<IProgress> &pProgress)
1543{
1544 /*
1545 * The prologue.
1546 */
1547 LogFlowThisFunc(("\n"));
1548 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1549 Console::SafeVMPtr ptrVM(mParent);
1550 HRESULT hrc = ptrVM.rc();
1551 if (SUCCEEDED(hrc))
1552 {
1553 if (!m_hSampleReport)
1554 {
1555 m_strFilename = aFilename;
1556
1557 int vrc = ptrVM.vtable()->pfnDBGFR3SampleReportCreate(ptrVM.rawUVM(), aUsInterval,
1558 DBGF_SAMPLE_REPORT_F_STACK_REVERSE, &m_hSampleReport);
1559 if (RT_SUCCESS(vrc))
1560 {
1561 hrc = m_Progress.createObject();
1562 if (SUCCEEDED(hrc))
1563 {
1564 hrc = m_Progress->init(static_cast<IMachineDebugger*>(this),
1565 tr("Creating guest sample report..."),
1566 TRUE /* aCancelable */);
1567 if (SUCCEEDED(hrc))
1568 {
1569 vrc = ptrVM.vtable()->pfnDBGFR3SampleReportStart(m_hSampleReport, aUsSampleTime, i_dbgfProgressCallback,
1570 static_cast<MachineDebugger*>(this));
1571 if (RT_SUCCESS(vrc))
1572 hrc = m_Progress.queryInterfaceTo(pProgress.asOutParam());
1573 else
1574 hrc = setErrorVrc(vrc);
1575 }
1576 }
1577
1578 if (FAILED(hrc))
1579 {
1580 ptrVM.vtable()->pfnDBGFR3SampleReportRelease(m_hSampleReport);
1581 m_hSampleReport = NULL;
1582 }
1583 }
1584 else
1585 hrc = setErrorVrc(vrc);
1586 }
1587 else
1588 hrc = setError(VBOX_E_INVALID_VM_STATE, tr("A sample report is already in progress"));
1589 }
1590
1591 return hrc;
1592}
1593
1594
1595// public methods only for internal purposes
1596/////////////////////////////////////////////////////////////////////////////
1597
1598void MachineDebugger::i_flushQueuedSettings()
1599{
1600 mFlushMode = true;
1601 if (mSingleStepQueued != -1)
1602 {
1603 COMSETTER(SingleStep)(mSingleStepQueued);
1604 mSingleStepQueued = -1;
1605 }
1606 for (unsigned i = 0; i < EMEXECPOLICY_END; i++)
1607 if (maiQueuedEmExecPolicyParams[i] != UINT8_MAX)
1608 {
1609 i_setEmExecPolicyProperty((EMEXECPOLICY)i, RT_BOOL(maiQueuedEmExecPolicyParams[i]));
1610 maiQueuedEmExecPolicyParams[i] = UINT8_MAX;
1611 }
1612 if (mPatmEnabledQueued != -1)
1613 {
1614 COMSETTER(PATMEnabled)(mPatmEnabledQueued);
1615 mPatmEnabledQueued = -1;
1616 }
1617 if (mCsamEnabledQueued != -1)
1618 {
1619 COMSETTER(CSAMEnabled)(mCsamEnabledQueued);
1620 mCsamEnabledQueued = -1;
1621 }
1622 if (mLogEnabledQueued != -1)
1623 {
1624 COMSETTER(LogEnabled)(mLogEnabledQueued);
1625 mLogEnabledQueued = -1;
1626 }
1627 if (mVirtualTimeRateQueued != UINT32_MAX)
1628 {
1629 COMSETTER(VirtualTimeRate)(mVirtualTimeRateQueued);
1630 mVirtualTimeRateQueued = UINT32_MAX;
1631 }
1632 mFlushMode = false;
1633}
1634
1635// private methods
1636/////////////////////////////////////////////////////////////////////////////
1637
1638bool MachineDebugger::i_queueSettings() const
1639{
1640 if (!mFlushMode)
1641 {
1642 // check if the machine is running
1643 MachineState_T machineState;
1644 mParent->COMGETTER(State)(&machineState);
1645 switch (machineState)
1646 {
1647 // queue the request
1648 default:
1649 return true;
1650
1651 case MachineState_Running:
1652 case MachineState_Paused:
1653 case MachineState_Stuck:
1654 case MachineState_LiveSnapshotting:
1655 case MachineState_Teleporting:
1656 break;
1657 }
1658 }
1659 return false;
1660}
1661/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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