VirtualBox

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

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

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use