VirtualBox

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

Last change on this file since 79812 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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