VirtualBox

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

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

include,Main: build fixes. 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 93445 2022-01-26 18:24:49Z 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 * @param pVMM The VMM vtable.
905 */
906static void MachineDebuggerInfoInit(PMACHINEDEBUGGERINOFHLP pHlp, PCVMMR3VTABLE pVMM)
907{
908 pHlp->Core.pfnPrintf = MachineDebuggerInfoPrintf;
909 pHlp->Core.pfnPrintfV = MachineDebuggerInfoPrintfV;
910 pHlp->Core.pfnGetOptError = pVMM->pfnDBGFR3InfoGenericGetOptError;
911 pHlp->pszBuf = NULL;
912 pHlp->cbBuf = 0;
913 pHlp->offBuf = 0;
914 pHlp->fOutOfMemory = false;
915}
916
917/**
918 * Deletes the debug info string buffer formatter.
919 * @param pHlp The helper structure to delete.
920 */
921static void MachineDebuggerInfoDelete(PMACHINEDEBUGGERINOFHLP pHlp)
922{
923 RTMemFree(pHlp->pszBuf);
924 pHlp->pszBuf = NULL;
925}
926
927HRESULT MachineDebugger::info(const com::Utf8Str &aName, const com::Utf8Str &aArgs, com::Utf8Str &aInfo)
928{
929 LogFlowThisFunc(("\n"));
930
931 /*
932 * Do the autocaller and lock bits.
933 */
934 AutoCaller autoCaller(this);
935 HRESULT hrc = autoCaller.rc();
936 if (SUCCEEDED(hrc))
937 {
938 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
939 Console::SafeVMPtr ptrVM(mParent);
940 hrc = ptrVM.rc();
941 if (SUCCEEDED(hrc))
942 {
943 /*
944 * Create a helper and call DBGFR3Info.
945 */
946 MACHINEDEBUGGERINOFHLP Hlp;
947 MachineDebuggerInfoInit(&Hlp, ptrVM.vtable());
948 int vrc = ptrVM.vtable()->pfnDBGFR3Info(ptrVM.rawUVM(), aName.c_str(), aArgs.c_str(), &Hlp.Core);
949 if (RT_SUCCESS(vrc))
950 {
951 if (!Hlp.fOutOfMemory)
952 hrc = aInfo.assignEx(Hlp.pszBuf);
953 else
954 hrc = E_OUTOFMEMORY;
955 }
956 else
957 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("DBGFR3Info failed with %Rrc"), vrc);
958 MachineDebuggerInfoDelete(&Hlp);
959 }
960 }
961 return hrc;
962}
963
964HRESULT MachineDebugger::injectNMI()
965{
966 LogFlowThisFunc(("\n"));
967
968 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
969 Console::SafeVMPtr ptrVM(mParent);
970 HRESULT hrc = ptrVM.rc();
971 if (SUCCEEDED(hrc))
972 {
973 int vrc = ptrVM.vtable()->pfnDBGFR3InjectNMI(ptrVM.rawUVM(), 0);
974 if (RT_SUCCESS(vrc))
975 hrc = S_OK;
976 else
977 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3InjectNMI failed with %Rrc"), vrc);
978 }
979 return hrc;
980}
981
982HRESULT MachineDebugger::modifyLogFlags(const com::Utf8Str &aSettings)
983{
984 LogFlowThisFunc(("aSettings=%s\n", aSettings.c_str()));
985 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
986 Console::SafeVMPtr ptrVM(mParent);
987 HRESULT hrc = ptrVM.rc();
988 if (SUCCEEDED(hrc))
989 {
990 int vrc = ptrVM.vtable()->pfnDBGFR3LogModifyFlags(ptrVM.rawUVM(), aSettings.c_str());
991 if (RT_SUCCESS(vrc))
992 hrc = S_OK;
993 else
994 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3LogModifyFlags failed with %Rrc"), vrc);
995 }
996 return hrc;
997}
998
999HRESULT MachineDebugger::modifyLogGroups(const com::Utf8Str &aSettings)
1000{
1001 LogFlowThisFunc(("aSettings=%s\n", aSettings.c_str()));
1002 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1003 Console::SafeVMPtr ptrVM(mParent);
1004 HRESULT hrc = ptrVM.rc();
1005 if (SUCCEEDED(hrc))
1006 {
1007 int vrc = ptrVM.vtable()->pfnDBGFR3LogModifyGroups(ptrVM.rawUVM(), aSettings.c_str());
1008 if (RT_SUCCESS(vrc))
1009 hrc = S_OK;
1010 else
1011 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3LogModifyGroups failed with %Rrc"), vrc);
1012 }
1013 return hrc;
1014}
1015
1016HRESULT MachineDebugger::modifyLogDestinations(const com::Utf8Str &aSettings)
1017{
1018 LogFlowThisFunc(("aSettings=%s\n", aSettings.c_str()));
1019 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1020 Console::SafeVMPtr ptrVM(mParent);
1021 HRESULT hrc = ptrVM.rc();
1022 if (SUCCEEDED(hrc))
1023 {
1024 int vrc = ptrVM.vtable()->pfnDBGFR3LogModifyDestinations(ptrVM.rawUVM(), aSettings.c_str());
1025 if (RT_SUCCESS(vrc))
1026 hrc = S_OK;
1027 else
1028 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3LogModifyDestinations failed with %Rrc"), vrc);
1029 }
1030 return hrc;
1031}
1032
1033HRESULT MachineDebugger::readPhysicalMemory(LONG64 aAddress, ULONG aSize, std::vector<BYTE> &aBytes)
1034{
1035 RT_NOREF(aAddress, aSize, aBytes);
1036 ReturnComNotImplemented();
1037}
1038
1039HRESULT MachineDebugger::writePhysicalMemory(LONG64 aAddress, ULONG aSize, const std::vector<BYTE> &aBytes)
1040{
1041 RT_NOREF(aAddress, aSize, aBytes);
1042 ReturnComNotImplemented();
1043}
1044
1045HRESULT MachineDebugger::readVirtualMemory(ULONG aCpuId, LONG64 aAddress, ULONG aSize, std::vector<BYTE> &aBytes)
1046{
1047 RT_NOREF(aCpuId, aAddress, aSize, aBytes);
1048 ReturnComNotImplemented();
1049}
1050
1051HRESULT MachineDebugger::writeVirtualMemory(ULONG aCpuId, LONG64 aAddress, ULONG aSize, const std::vector<BYTE> &aBytes)
1052{
1053 RT_NOREF(aCpuId, aAddress, aSize, aBytes);
1054 ReturnComNotImplemented();
1055}
1056
1057HRESULT MachineDebugger::loadPlugIn(const com::Utf8Str &aName, com::Utf8Str &aPlugInName)
1058{
1059 /*
1060 * Lock the debugger and get the VM pointer
1061 */
1062 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1063 Console::SafeVMPtr ptrVM(mParent);
1064 HRESULT hrc = ptrVM.rc();
1065 if (SUCCEEDED(hrc))
1066 {
1067 /*
1068 * Do the job and try convert the name.
1069 */
1070 if (aName.equals("all"))
1071 {
1072 ptrVM.vtable()->pfnDBGFR3PlugInLoadAll(ptrVM.rawUVM());
1073 hrc = aPlugInName.assignEx("all");
1074 }
1075 else
1076 {
1077 RTERRINFOSTATIC ErrInfo;
1078 char szName[80];
1079 int vrc = ptrVM.vtable()->pfnDBGFR3PlugInLoad(ptrVM.rawUVM(), aName.c_str(), szName, sizeof(szName), RTErrInfoInitStatic(&ErrInfo));
1080 if (RT_SUCCESS(vrc))
1081 hrc = aPlugInName.assignEx(szName);
1082 else
1083 hrc = setErrorVrc(vrc, "%s", ErrInfo.szMsg);
1084 }
1085 }
1086 return hrc;
1087
1088}
1089
1090HRESULT MachineDebugger::unloadPlugIn(const com::Utf8Str &aName)
1091{
1092 /*
1093 * Lock the debugger and get the VM pointer
1094 */
1095 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1096 Console::SafeVMPtr ptrVM(mParent);
1097 HRESULT hrc = ptrVM.rc();
1098 if (SUCCEEDED(hrc))
1099 {
1100 /*
1101 * Do the job and try convert the name.
1102 */
1103 if (aName.equals("all"))
1104 {
1105 ptrVM.vtable()->pfnDBGFR3PlugInUnloadAll(ptrVM.rawUVM());
1106 hrc = S_OK;
1107 }
1108 else
1109 {
1110 int vrc = ptrVM.vtable()->pfnDBGFR3PlugInUnload(ptrVM.rawUVM(), aName.c_str());
1111 if (RT_SUCCESS(vrc))
1112 hrc = S_OK;
1113 else if (vrc == VERR_NOT_FOUND)
1114 hrc = setErrorBoth(E_FAIL, vrc, tr("Plug-in '%s' was not found"), aName.c_str());
1115 else
1116 hrc = setErrorVrc(vrc, tr("Error unloading '%s': %Rrc"), aName.c_str(), vrc);
1117 }
1118 }
1119 return hrc;
1120
1121}
1122
1123HRESULT MachineDebugger::detectOS(com::Utf8Str &aOs)
1124{
1125 LogFlowThisFunc(("\n"));
1126
1127 /*
1128 * Lock the debugger and get the VM pointer
1129 */
1130 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1131 Console::SafeVMPtr ptrVM(mParent);
1132 HRESULT hrc = ptrVM.rc();
1133 if (SUCCEEDED(hrc))
1134 {
1135 /*
1136 * Do the job.
1137 */
1138 char szName[64];
1139 int vrc = ptrVM.vtable()->pfnDBGFR3OSDetect(ptrVM.rawUVM(), szName, sizeof(szName));
1140 if (RT_SUCCESS(vrc) && vrc != VINF_DBGF_OS_NOT_DETCTED)
1141 hrc = aOs.assignEx(szName);
1142 else
1143 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("DBGFR3OSDetect failed with %Rrc"), vrc);
1144 }
1145 return hrc;
1146}
1147
1148HRESULT MachineDebugger::queryOSKernelLog(ULONG aMaxMessages, com::Utf8Str &aDmesg)
1149{
1150 /*
1151 * Lock the debugger and get the VM pointer
1152 */
1153 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1154 Console::SafeVMPtr ptrVM(mParent);
1155 HRESULT hrc = ptrVM.rc();
1156 if (SUCCEEDED(hrc))
1157 {
1158 PDBGFOSIDMESG pDmesg = (PDBGFOSIDMESG)ptrVM.vtable()->pfnDBGFR3OSQueryInterface(ptrVM.rawUVM(), DBGFOSINTERFACE_DMESG);
1159 if (pDmesg)
1160 {
1161 size_t cbActual;
1162 size_t cbBuf = _512K;
1163 int vrc = aDmesg.reserveNoThrow(cbBuf);
1164 if (RT_SUCCESS(vrc))
1165 {
1166 uint32_t cMessages = aMaxMessages == 0 ? UINT32_MAX : aMaxMessages;
1167 vrc = pDmesg->pfnQueryKernelLog(pDmesg, ptrVM.rawUVM(), 0 /*fFlags*/, cMessages,
1168 aDmesg.mutableRaw(), cbBuf, &cbActual);
1169
1170 uint32_t cTries = 10;
1171 while (vrc == VERR_BUFFER_OVERFLOW && cbBuf < 16*_1M && cTries-- > 0)
1172 {
1173 cbBuf = RT_ALIGN_Z(cbActual + _4K, _4K);
1174 vrc = aDmesg.reserveNoThrow(cbBuf);
1175 if (RT_SUCCESS(vrc))
1176 vrc = pDmesg->pfnQueryKernelLog(pDmesg, ptrVM.rawUVM(), 0 /*fFlags*/, cMessages,
1177 aDmesg.mutableRaw(), cbBuf, &cbActual);
1178 }
1179 if (RT_SUCCESS(vrc))
1180 aDmesg.jolt();
1181 else if (vrc == VERR_BUFFER_OVERFLOW)
1182 hrc = setError(E_FAIL, tr("Too much log available, must use the maxMessages parameter to restrict."));
1183 else
1184 hrc = setErrorVrc(vrc);
1185 }
1186 else
1187 hrc = setErrorBoth(E_OUTOFMEMORY, vrc);
1188 }
1189 else
1190 hrc = setError(E_FAIL, tr("The dmesg interface isn't implemented by guest OS digger, or detectOS() has not been called."));
1191 }
1192 return hrc;
1193}
1194
1195HRESULT MachineDebugger::getRegister(ULONG aCpuId, const com::Utf8Str &aName, com::Utf8Str &aValue)
1196{
1197 /*
1198 * The prologue.
1199 */
1200 LogFlowThisFunc(("\n"));
1201 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1202 Console::SafeVMPtr ptrVM(mParent);
1203 HRESULT hrc = ptrVM.rc();
1204 if (SUCCEEDED(hrc))
1205 {
1206 /*
1207 * Real work.
1208 */
1209 DBGFREGVAL Value;
1210 DBGFREGVALTYPE enmType;
1211 int vrc = ptrVM.vtable()->pfnDBGFR3RegNmQuery(ptrVM.rawUVM(), aCpuId, aName.c_str(), &Value, &enmType);
1212 if (RT_SUCCESS(vrc))
1213 {
1214 char szHex[160];
1215 ssize_t cch = ptrVM.vtable()->pfnDBGFR3RegFormatValue(szHex, sizeof(szHex), &Value, enmType, true /*fSpecial*/);
1216 if (cch > 0)
1217 hrc = aValue.assignEx(szHex);
1218 else
1219 hrc = E_UNEXPECTED;
1220 }
1221 else if (vrc == VERR_DBGF_REGISTER_NOT_FOUND)
1222 hrc = setErrorBoth(E_FAIL, vrc, tr("Register '%s' was not found"), aName.c_str());
1223 else if (vrc == VERR_INVALID_CPU_ID)
1224 hrc = setErrorBoth(E_FAIL, vrc, tr("Invalid CPU ID: %u"), aCpuId);
1225 else
1226 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc,
1227 tr("DBGFR3RegNmQuery failed with rc=%Rrc querying register '%s' with default cpu set to %u"),
1228 vrc, aName.c_str(), aCpuId);
1229 }
1230
1231 return hrc;
1232}
1233
1234HRESULT MachineDebugger::getRegisters(ULONG aCpuId, std::vector<com::Utf8Str> &aNames, std::vector<com::Utf8Str> &aValues)
1235{
1236 RT_NOREF(aCpuId); /** @todo fix missing aCpuId usage! */
1237
1238 /*
1239 * The prologue.
1240 */
1241 LogFlowThisFunc(("\n"));
1242 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1243 Console::SafeVMPtr ptrVM(mParent);
1244 HRESULT hrc = ptrVM.rc();
1245 if (SUCCEEDED(hrc))
1246 {
1247 /*
1248 * Real work.
1249 */
1250 size_t cRegs;
1251 int vrc = ptrVM.vtable()->pfnDBGFR3RegNmQueryAllCount(ptrVM.rawUVM(), &cRegs);
1252 if (RT_SUCCESS(vrc))
1253 {
1254 PDBGFREGENTRYNM paRegs = (PDBGFREGENTRYNM)RTMemAllocZ(sizeof(paRegs[0]) * cRegs);
1255 if (paRegs)
1256 {
1257 vrc = ptrVM.vtable()->pfnDBGFR3RegNmQueryAll(ptrVM.rawUVM(), paRegs, cRegs);
1258 if (RT_SUCCESS(vrc))
1259 {
1260 try
1261 {
1262 aValues.resize(cRegs);
1263 aNames.resize(cRegs);
1264 for (uint32_t iReg = 0; iReg < cRegs; iReg++)
1265 {
1266 char szHex[160];
1267 szHex[159] = szHex[0] = '\0';
1268 ssize_t cch = ptrVM.vtable()->pfnDBGFR3RegFormatValue(szHex, sizeof(szHex), &paRegs[iReg].Val,
1269 paRegs[iReg].enmType, true /*fSpecial*/);
1270 Assert(cch > 0); NOREF(cch);
1271 aNames[iReg] = paRegs[iReg].pszName;
1272 aValues[iReg] = szHex;
1273 }
1274 }
1275 catch (std::bad_alloc &)
1276 {
1277 hrc = E_OUTOFMEMORY;
1278 }
1279 }
1280 else
1281 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3RegNmQueryAll failed with %Rrc"), vrc);
1282
1283 RTMemFree(paRegs);
1284 }
1285 else
1286 hrc = E_OUTOFMEMORY;
1287 }
1288 else
1289 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3RegNmQueryAllCount failed with %Rrc"), vrc);
1290 }
1291 return hrc;
1292}
1293
1294HRESULT MachineDebugger::setRegister(ULONG aCpuId, const com::Utf8Str &aName, const com::Utf8Str &aValue)
1295{
1296 RT_NOREF(aCpuId, aName, aValue);
1297 ReturnComNotImplemented();
1298}
1299
1300HRESULT MachineDebugger::setRegisters(ULONG aCpuId, const std::vector<com::Utf8Str> &aNames,
1301 const std::vector<com::Utf8Str> &aValues)
1302{
1303 RT_NOREF(aCpuId, aNames, aValues);
1304 ReturnComNotImplemented();
1305}
1306
1307HRESULT MachineDebugger::dumpGuestStack(ULONG aCpuId, com::Utf8Str &aStack)
1308{
1309 /*
1310 * The prologue.
1311 */
1312 LogFlowThisFunc(("\n"));
1313 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1314 Console::SafeVMPtr ptrVM(mParent);
1315 HRESULT hrc = ptrVM.rc();
1316 if (SUCCEEDED(hrc))
1317 {
1318 /*
1319 * There is currently a problem with the windows diggers and SMP, where
1320 * guest driver memory is being read from CPU zero in order to ensure that
1321 * we've got a consisten virtual memory view. If one of the other CPUs
1322 * initiates a rendezvous while we're unwinding the stack and trying to
1323 * read guest driver memory, we will deadlock.
1324 *
1325 * So, check the VM state and maybe suspend the VM before we continue.
1326 */
1327 int vrc = VINF_SUCCESS;
1328 bool fPaused = false;
1329 if (aCpuId != 0)
1330 {
1331 VMSTATE enmVmState = ptrVM.vtable()->pfnVMR3GetStateU(ptrVM.rawUVM());
1332 if ( enmVmState == VMSTATE_RUNNING
1333 || enmVmState == VMSTATE_RUNNING_LS)
1334 {
1335 alock.release();
1336 vrc = ptrVM.vtable()->pfnVMR3Suspend(ptrVM.rawUVM(), VMSUSPENDREASON_USER);
1337 alock.acquire();
1338 fPaused = RT_SUCCESS(vrc);
1339 }
1340 }
1341 if (RT_SUCCESS(vrc))
1342 {
1343 PCDBGFSTACKFRAME pFirstFrame;
1344 vrc = ptrVM.vtable()->pfnDBGFR3StackWalkBegin(ptrVM.rawUVM(), aCpuId, DBGFCODETYPE_GUEST, &pFirstFrame);
1345 if (RT_SUCCESS(vrc))
1346 {
1347 /*
1348 * Print header.
1349 */
1350 try
1351 {
1352 uint32_t fBitFlags = 0;
1353 for (PCDBGFSTACKFRAME pFrame = pFirstFrame;
1354 pFrame;
1355 pFrame = ptrVM.vtable()->pfnDBGFR3StackWalkNext(pFrame))
1356 {
1357 uint32_t const fCurBitFlags = pFrame->fFlags & (DBGFSTACKFRAME_FLAGS_16BIT | DBGFSTACKFRAME_FLAGS_32BIT | DBGFSTACKFRAME_FLAGS_64BIT);
1358 if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_16BIT)
1359 {
1360 if (fCurBitFlags != fBitFlags)
1361 aStack.append("SS:BP Ret SS:BP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n");
1362 aStack.appendPrintf("%04RX16:%04RX16 %04RX16:%04RX16 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
1363 pFrame->AddrFrame.Sel,
1364 (uint16_t)pFrame->AddrFrame.off,
1365 pFrame->AddrReturnFrame.Sel,
1366 (uint16_t)pFrame->AddrReturnFrame.off,
1367 (uint32_t)pFrame->AddrReturnPC.Sel,
1368 (uint32_t)pFrame->AddrReturnPC.off,
1369 pFrame->Args.au32[0],
1370 pFrame->Args.au32[1],
1371 pFrame->Args.au32[2],
1372 pFrame->Args.au32[3]);
1373 }
1374 else if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_32BIT)
1375 {
1376 if (fCurBitFlags != fBitFlags)
1377 aStack.append("EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n");
1378 aStack.appendPrintf("%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
1379 (uint32_t)pFrame->AddrFrame.off,
1380 (uint32_t)pFrame->AddrReturnFrame.off,
1381 (uint32_t)pFrame->AddrReturnPC.Sel,
1382 (uint32_t)pFrame->AddrReturnPC.off,
1383 pFrame->Args.au32[0],
1384 pFrame->Args.au32[1],
1385 pFrame->Args.au32[2],
1386 pFrame->Args.au32[3]);
1387 }
1388 else if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_64BIT)
1389 {
1390 if (fCurBitFlags != fBitFlags)
1391 aStack.append("RBP Ret SS:RBP Ret RIP CS:RIP / Symbol [line]\n");
1392 aStack.appendPrintf("%016RX64 %04RX16:%016RX64 %016RX64",
1393 (uint64_t)pFrame->AddrFrame.off,
1394 pFrame->AddrReturnFrame.Sel,
1395 (uint64_t)pFrame->AddrReturnFrame.off,
1396 (uint64_t)pFrame->AddrReturnPC.off);
1397 }
1398
1399 if (!pFrame->pSymPC)
1400 aStack.appendPrintf(fCurBitFlags & DBGFSTACKFRAME_FLAGS_64BIT
1401 ? " %RTsel:%016RGv"
1402 : fCurBitFlags & DBGFSTACKFRAME_FLAGS_32BIT
1403 ? " %RTsel:%08RGv"
1404 : " %RTsel:%04RGv"
1405 , pFrame->AddrPC.Sel, pFrame->AddrPC.off);
1406 else
1407 {
1408 RTGCINTPTR offDisp = pFrame->AddrPC.FlatPtr - pFrame->pSymPC->Value; /** @todo this isn't 100% correct for segmented stuff. */
1409 if (offDisp > 0)
1410 aStack.appendPrintf(" %s+%llx", pFrame->pSymPC->szName, (int64_t)offDisp);
1411 else if (offDisp < 0)
1412 aStack.appendPrintf(" %s-%llx", pFrame->pSymPC->szName, -(int64_t)offDisp);
1413 else
1414 aStack.appendPrintf(" %s", pFrame->pSymPC->szName);
1415 }
1416 if (pFrame->pLinePC)
1417 aStack.appendPrintf(" [%s @ 0i%d]", pFrame->pLinePC->szFilename, pFrame->pLinePC->uLineNo);
1418 aStack.append("\n");
1419
1420 fBitFlags = fCurBitFlags;
1421 }
1422 }
1423 catch (std::bad_alloc &)
1424 {
1425 hrc = E_OUTOFMEMORY;
1426 }
1427
1428 ptrVM.vtable()->pfnDBGFR3StackWalkEnd(pFirstFrame);
1429 }
1430 else
1431 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3StackWalkBegin failed with %Rrc"), vrc);
1432
1433 /*
1434 * Resume the VM if we suspended it.
1435 */
1436 if (fPaused)
1437 {
1438 alock.release();
1439 ptrVM.vtable()->pfnVMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_USER);
1440 }
1441 }
1442 else
1443 hrc = setErrorBoth(E_FAIL, vrc, tr("Suspending the VM failed with %Rrc\n"), vrc);
1444 }
1445
1446 return hrc;
1447}
1448
1449/**
1450 * Resets VM statistics.
1451 *
1452 * @returns COM status code.
1453 * @param aPattern The selection pattern. A bit similar to filename globbing.
1454 */
1455HRESULT MachineDebugger::resetStats(const com::Utf8Str &aPattern)
1456{
1457 Console::SafeVMPtrQuiet ptrVM(mParent);
1458 if (!ptrVM.isOk())
1459 return setError(VBOX_E_INVALID_VM_STATE, tr("Machine is not running"));
1460
1461 ptrVM.vtable()->pfnSTAMR3Reset(ptrVM.rawUVM(), aPattern.c_str());
1462
1463 return S_OK;
1464}
1465
1466/**
1467 * Dumps VM statistics to the log.
1468 *
1469 * @returns COM status code.
1470 * @param aPattern The selection pattern. A bit similar to filename globbing.
1471 */
1472HRESULT MachineDebugger::dumpStats(const com::Utf8Str &aPattern)
1473{
1474 Console::SafeVMPtrQuiet ptrVM(mParent);
1475 if (!ptrVM.isOk())
1476 return setError(VBOX_E_INVALID_VM_STATE, tr("Machine is not running"));
1477
1478 ptrVM.vtable()->pfnSTAMR3Dump(ptrVM.rawUVM(), aPattern.c_str());
1479
1480 return S_OK;
1481}
1482
1483/**
1484 * Get the VM statistics in an XML format.
1485 *
1486 * @returns COM status code.
1487 * @param aPattern The selection pattern. A bit similar to filename globbing.
1488 * @param aWithDescriptions Whether to include the descriptions.
1489 * @param aStats The XML document containing the statistics.
1490 */
1491HRESULT MachineDebugger::getStats(const com::Utf8Str &aPattern, BOOL aWithDescriptions, com::Utf8Str &aStats)
1492{
1493 Console::SafeVMPtrQuiet ptrVM(mParent);
1494 if (!ptrVM.isOk())
1495 return setError(VBOX_E_INVALID_VM_STATE, tr("Machine is not running"));
1496
1497 char *pszSnapshot;
1498 int vrc = ptrVM.vtable()->pfnSTAMR3Snapshot(ptrVM.rawUVM(), aPattern.c_str(), &pszSnapshot, NULL, !!aWithDescriptions);
1499 if (RT_FAILURE(vrc))
1500 return vrc == VERR_NO_MEMORY ? E_OUTOFMEMORY : E_FAIL;
1501
1502 /** @todo this is horribly inefficient! And it's kinda difficult to tell whether it failed...
1503 * Must use UTF-8 or ASCII here and completely avoid these two extra copy operations.
1504 * Until that's done, this method is kind of useless for debugger statistics GUI because
1505 * of the amount statistics in a debug build. */
1506 HRESULT hrc = aStats.assignEx(pszSnapshot);
1507 ptrVM.vtable()->pfnSTAMR3SnapshotFree(ptrVM.rawUVM(), pszSnapshot);
1508
1509 return hrc;
1510}
1511
1512
1513/** Wrapper around TMR3GetCpuLoadPercents. */
1514HRESULT MachineDebugger::getCPULoad(ULONG aCpuId, ULONG *aPctExecuting, ULONG *aPctHalted, ULONG *aPctOther, LONG64 *aMsInterval)
1515{
1516 HRESULT hrc;
1517 Console::SafeVMPtrQuiet ptrVM(mParent);
1518 if (ptrVM.isOk())
1519 {
1520 uint8_t uPctExecuting = 0;
1521 uint8_t uPctHalted = 0;
1522 uint8_t uPctOther = 0;
1523 uint64_t msInterval = 0;
1524 int vrc = ptrVM.vtable()->pfnTMR3GetCpuLoadPercents(ptrVM.rawUVM(), aCpuId >= UINT32_MAX / 2 ? VMCPUID_ALL : aCpuId,
1525 &msInterval, &uPctExecuting, &uPctHalted, &uPctOther);
1526 if (RT_SUCCESS(vrc))
1527 {
1528 *aPctExecuting = uPctExecuting;
1529 *aPctHalted = uPctHalted;
1530 *aPctOther = uPctOther;
1531 *aMsInterval = msInterval;
1532 hrc = S_OK;
1533 }
1534 else
1535 hrc = setErrorVrc(vrc);
1536 }
1537 else
1538 hrc = setError(VBOX_E_INVALID_VM_STATE, tr("Machine is not running"));
1539 return hrc;
1540}
1541
1542
1543HRESULT MachineDebugger::takeGuestSample(const com::Utf8Str &aFilename, ULONG aUsInterval, LONG64 aUsSampleTime, ComPtr<IProgress> &pProgress)
1544{
1545 /*
1546 * The prologue.
1547 */
1548 LogFlowThisFunc(("\n"));
1549 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1550 Console::SafeVMPtr ptrVM(mParent);
1551 HRESULT hrc = ptrVM.rc();
1552 if (SUCCEEDED(hrc))
1553 {
1554 if (!m_hSampleReport)
1555 {
1556 m_strFilename = aFilename;
1557
1558 int vrc = ptrVM.vtable()->pfnDBGFR3SampleReportCreate(ptrVM.rawUVM(), aUsInterval,
1559 DBGF_SAMPLE_REPORT_F_STACK_REVERSE, &m_hSampleReport);
1560 if (RT_SUCCESS(vrc))
1561 {
1562 hrc = m_Progress.createObject();
1563 if (SUCCEEDED(hrc))
1564 {
1565 hrc = m_Progress->init(static_cast<IMachineDebugger*>(this),
1566 tr("Creating guest sample report..."),
1567 TRUE /* aCancelable */);
1568 if (SUCCEEDED(hrc))
1569 {
1570 vrc = ptrVM.vtable()->pfnDBGFR3SampleReportStart(m_hSampleReport, aUsSampleTime, i_dbgfProgressCallback,
1571 static_cast<MachineDebugger*>(this));
1572 if (RT_SUCCESS(vrc))
1573 hrc = m_Progress.queryInterfaceTo(pProgress.asOutParam());
1574 else
1575 hrc = setErrorVrc(vrc);
1576 }
1577 }
1578
1579 if (FAILED(hrc))
1580 {
1581 ptrVM.vtable()->pfnDBGFR3SampleReportRelease(m_hSampleReport);
1582 m_hSampleReport = NULL;
1583 }
1584 }
1585 else
1586 hrc = setErrorVrc(vrc);
1587 }
1588 else
1589 hrc = setError(VBOX_E_INVALID_VM_STATE, tr("A sample report is already in progress"));
1590 }
1591
1592 return hrc;
1593}
1594
1595
1596// public methods only for internal purposes
1597/////////////////////////////////////////////////////////////////////////////
1598
1599void MachineDebugger::i_flushQueuedSettings()
1600{
1601 mFlushMode = true;
1602 if (mSingleStepQueued != -1)
1603 {
1604 COMSETTER(SingleStep)(mSingleStepQueued);
1605 mSingleStepQueued = -1;
1606 }
1607 for (unsigned i = 0; i < EMEXECPOLICY_END; i++)
1608 if (maiQueuedEmExecPolicyParams[i] != UINT8_MAX)
1609 {
1610 i_setEmExecPolicyProperty((EMEXECPOLICY)i, RT_BOOL(maiQueuedEmExecPolicyParams[i]));
1611 maiQueuedEmExecPolicyParams[i] = UINT8_MAX;
1612 }
1613 if (mPatmEnabledQueued != -1)
1614 {
1615 COMSETTER(PATMEnabled)(mPatmEnabledQueued);
1616 mPatmEnabledQueued = -1;
1617 }
1618 if (mCsamEnabledQueued != -1)
1619 {
1620 COMSETTER(CSAMEnabled)(mCsamEnabledQueued);
1621 mCsamEnabledQueued = -1;
1622 }
1623 if (mLogEnabledQueued != -1)
1624 {
1625 COMSETTER(LogEnabled)(mLogEnabledQueued);
1626 mLogEnabledQueued = -1;
1627 }
1628 if (mVirtualTimeRateQueued != UINT32_MAX)
1629 {
1630 COMSETTER(VirtualTimeRate)(mVirtualTimeRateQueued);
1631 mVirtualTimeRateQueued = UINT32_MAX;
1632 }
1633 mFlushMode = false;
1634}
1635
1636// private methods
1637/////////////////////////////////////////////////////////////////////////////
1638
1639bool MachineDebugger::i_queueSettings() const
1640{
1641 if (!mFlushMode)
1642 {
1643 // check if the machine is running
1644 MachineState_T machineState;
1645 mParent->COMGETTER(State)(&machineState);
1646 switch (machineState)
1647 {
1648 // queue the request
1649 default:
1650 return true;
1651
1652 case MachineState_Running:
1653 case MachineState_Paused:
1654 case MachineState_Stuck:
1655 case MachineState_LiveSnapshotting:
1656 case MachineState_Teleporting:
1657 break;
1658 }
1659 }
1660 return false;
1661}
1662/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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