VirtualBox

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

Last change on this file since 72372 was 72328, checked in by vboxsync, 7 years ago

Main: Added read-only ExecutionEngine attribute to IMachineDebugger to expose VM::bMainExecutionEngine to API clients. bugref:9044

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 51.1 KB
Line 
1/* $Id: MachineDebuggerImpl.cpp 72328 2018-05-24 19:29:45Z vboxsync $ */
2/** @file
3 * VBox IMachineDebugger COM class implementation (VBoxC).
4 */
5
6/*
7 * Copyright (C) 2006-2017 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 = setError(VBOX_E_VM_ERROR, 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 setError(VBOX_E_VM_ERROR, tr("PATMR3AllowPatching returned %Rrc"), vrc);
341
342#else /* !VBOX_WITH_RAW_MODE */
343 if (aPATMEnabled)
344 return setError(VBOX_E_VM_ERROR, 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 setError(VBOX_E_VM_ERROR, tr("CSAMR3SetScanningEnabled returned %Rrc"), vrc);
398
399#else /* !VBOX_WITH_RAW_MODE */
400 if (aCSAMEnabled)
401 return setError(VBOX_E_VM_ERROR, tr("CASM not present"), VERR_NOT_SUPPORTED);
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, setError(VBOX_E_IPRT_ERROR, tr("%s returned %Rrc"), pszLogGetStr, vrc));
493 }
494 else
495 return E_OUTOFMEMORY;
496
497 /* try again with a bigger buffer. */
498 cbBuf *= 2;
499 AssertReturn(cbBuf <= _256K, setError(E_FAIL, tr("%s returns too much data"), pszLogGetStr));
500 }
501}
502
503HRESULT MachineDebugger::getLogDbgFlags(com::Utf8Str &aLogDbgFlags)
504{
505 return i_logStringProps(RTLogGetDefaultInstance(), RTLogGetFlags, "RTGetFlags", &aLogDbgFlags);
506}
507
508HRESULT MachineDebugger::getLogDbgGroups(com::Utf8Str &aLogDbgGroups)
509{
510 return i_logStringProps(RTLogGetDefaultInstance(), RTLogGetGroupSettings, "RTLogGetGroupSettings", &aLogDbgGroups);
511}
512
513HRESULT MachineDebugger::getLogDbgDestinations(com::Utf8Str &aLogDbgDestinations)
514{
515 return i_logStringProps(RTLogGetDefaultInstance(), RTLogGetDestinations, "RTLogGetDestinations", &aLogDbgDestinations);
516}
517
518HRESULT MachineDebugger::getLogRelFlags(com::Utf8Str &aLogRelFlags)
519{
520 return i_logStringProps(RTLogRelGetDefaultInstance(), RTLogGetFlags, "RTGetFlags", &aLogRelFlags);
521}
522
523HRESULT MachineDebugger::getLogRelGroups(com::Utf8Str &aLogRelGroups)
524{
525 return i_logStringProps(RTLogRelGetDefaultInstance(), RTLogGetGroupSettings, "RTLogGetGroupSettings", &aLogRelGroups);
526}
527
528HRESULT MachineDebugger::getLogRelDestinations(com::Utf8Str &aLogRelDestinations)
529{
530 return i_logStringProps(RTLogRelGetDefaultInstance(), RTLogGetDestinations, "RTLogGetDestinations", &aLogRelDestinations);
531}
532
533/**
534 * Return the main execution engine of the VM.
535 *
536 * @returns COM status code
537 * @param apenmEngine Address of the result variable.
538 */
539HRESULT MachineDebugger::getExecutionEngine(VMExecutionEngine_T *apenmEngine)
540{
541 *apenmEngine = VMExecutionEngine_NotSet;
542
543 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
544 Console::SafeVMPtrQuiet ptrVM(mParent);
545 if (ptrVM.isOk())
546 {
547 uint8_t bEngine = UINT8_MAX;
548 int rc = EMR3QueryMainExecutionEngine(ptrVM.rawUVM(), &bEngine);
549 if (RT_SUCCESS(rc))
550 switch (bEngine)
551 {
552 case VM_EXEC_ENGINE_NOT_SET: *apenmEngine = VMExecutionEngine_NotSet; break;
553 case VM_EXEC_ENGINE_RAW_MODE: *apenmEngine = VMExecutionEngine_RawMode; break;
554 case VM_EXEC_ENGINE_HW_VIRT: *apenmEngine = VMExecutionEngine_HwVirt; break;
555 case VM_EXEC_ENGINE_NATIVE_API: *apenmEngine = VMExecutionEngine_NativeApi; break;
556 default: AssertMsgFailed(("bEngine=%d\n", bEngine));
557 }
558 }
559
560 return S_OK;
561}
562
563/**
564 * Returns the current hardware virtualization flag.
565 *
566 * @returns COM status code
567 * @param aHWVirtExEnabled address of result variable
568 */
569HRESULT MachineDebugger::getHWVirtExEnabled(BOOL *aHWVirtExEnabled)
570{
571 *aHWVirtExEnabled = false;
572
573 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
574 Console::SafeVMPtrQuiet ptrVM(mParent);
575 if (ptrVM.isOk())
576 {
577 uint8_t bEngine = UINT8_MAX;
578 int rc = EMR3QueryMainExecutionEngine(ptrVM.rawUVM(), &bEngine);
579 *aHWVirtExEnabled = RT_SUCCESS(rc) && bEngine == VM_EXEC_ENGINE_HW_VIRT;
580 }
581
582 return S_OK;
583}
584
585/**
586 * Returns the current nested paging flag.
587 *
588 * @returns COM status code
589 * @param aHWVirtExNestedPagingEnabled address of result variable
590 */
591HRESULT MachineDebugger::getHWVirtExNestedPagingEnabled(BOOL *aHWVirtExNestedPagingEnabled)
592{
593 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
594
595 Console::SafeVMPtrQuiet ptrVM(mParent);
596
597 if (ptrVM.isOk())
598 *aHWVirtExNestedPagingEnabled = HMR3IsNestedPagingActive(ptrVM.rawUVM());
599 else
600 *aHWVirtExNestedPagingEnabled = false;
601
602 return S_OK;
603}
604
605/**
606 * Returns the current VPID flag.
607 *
608 * @returns COM status code
609 * @param aHWVirtExVPIDEnabled address of result variable
610 */
611HRESULT MachineDebugger::getHWVirtExVPIDEnabled(BOOL *aHWVirtExVPIDEnabled)
612{
613 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
614
615 Console::SafeVMPtrQuiet ptrVM(mParent);
616
617 if (ptrVM.isOk())
618 *aHWVirtExVPIDEnabled = HMR3IsVpidActive(ptrVM.rawUVM());
619 else
620 *aHWVirtExVPIDEnabled = false;
621
622 return S_OK;
623}
624
625/**
626 * Returns the current unrestricted execution setting.
627 *
628 * @returns COM status code
629 * @param aHWVirtExUXEnabled address of result variable
630 */
631HRESULT MachineDebugger::getHWVirtExUXEnabled(BOOL *aHWVirtExUXEnabled)
632{
633 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
634
635 Console::SafeVMPtrQuiet ptrVM(mParent);
636
637 if (ptrVM.isOk())
638 *aHWVirtExUXEnabled = HMR3IsUXActive(ptrVM.rawUVM());
639 else
640 *aHWVirtExUXEnabled = false;
641
642 return S_OK;
643}
644
645HRESULT MachineDebugger::getOSName(com::Utf8Str &aOSName)
646{
647 LogFlowThisFunc(("\n"));
648 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
649 Console::SafeVMPtr ptrVM(mParent);
650 HRESULT hrc = ptrVM.rc();
651 if (SUCCEEDED(hrc))
652 {
653 /*
654 * Do the job and try convert the name.
655 */
656 char szName[64];
657 int vrc = DBGFR3OSQueryNameAndVersion(ptrVM.rawUVM(), szName, sizeof(szName), NULL, 0);
658 if (RT_SUCCESS(vrc))
659 {
660 try
661 {
662 Bstr bstrName(szName);
663 aOSName = Utf8Str(bstrName);
664 }
665 catch (std::bad_alloc)
666 {
667 hrc = E_OUTOFMEMORY;
668 }
669 }
670 else
671 hrc = setError(VBOX_E_VM_ERROR, tr("DBGFR3OSQueryNameAndVersion failed with %Rrc"), vrc);
672 }
673 return hrc;
674}
675
676HRESULT MachineDebugger::getOSVersion(com::Utf8Str &aOSVersion)
677{
678 LogFlowThisFunc(("\n"));
679 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
680 Console::SafeVMPtr ptrVM(mParent);
681 HRESULT hrc = ptrVM.rc();
682 if (SUCCEEDED(hrc))
683 {
684 /*
685 * Do the job and try convert the name.
686 */
687 char szVersion[256];
688 int vrc = DBGFR3OSQueryNameAndVersion(ptrVM.rawUVM(), NULL, 0, szVersion, sizeof(szVersion));
689 if (RT_SUCCESS(vrc))
690 {
691 try
692 {
693 Bstr bstrVersion(szVersion);
694 aOSVersion = Utf8Str(bstrVersion);
695 }
696 catch (std::bad_alloc)
697 {
698 hrc = E_OUTOFMEMORY;
699 }
700 }
701 else
702 hrc = setError(VBOX_E_VM_ERROR, tr("DBGFR3OSQueryNameAndVersion failed with %Rrc"), vrc);
703 }
704 return hrc;
705}
706
707/**
708 * Returns the current PAE flag.
709 *
710 * @returns COM status code
711 * @param aPAEEnabled address of result variable.
712 */
713HRESULT MachineDebugger::getPAEEnabled(BOOL *aPAEEnabled)
714{
715 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
716
717 Console::SafeVMPtrQuiet ptrVM(mParent);
718
719 if (ptrVM.isOk())
720 {
721 uint32_t cr4;
722 int rc = DBGFR3RegCpuQueryU32(ptrVM.rawUVM(), 0 /*idCpu*/, DBGFREG_CR4, &cr4); AssertRC(rc);
723 *aPAEEnabled = RT_BOOL(cr4 & X86_CR4_PAE);
724 }
725 else
726 *aPAEEnabled = false;
727
728 return S_OK;
729}
730
731/**
732 * Returns the current virtual time rate.
733 *
734 * @returns COM status code.
735 * @param aVirtualTimeRate Where to store the rate.
736 */
737HRESULT MachineDebugger::getVirtualTimeRate(ULONG *aVirtualTimeRate)
738{
739 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
740
741 Console::SafeVMPtr ptrVM(mParent);
742 HRESULT hrc = ptrVM.rc();
743 if (SUCCEEDED(hrc))
744 *aVirtualTimeRate = TMR3GetWarpDrive(ptrVM.rawUVM());
745
746 return hrc;
747}
748
749/**
750 * Set the virtual time rate.
751 *
752 * @returns COM status code.
753 * @param aVirtualTimeRate The new rate.
754 */
755HRESULT MachineDebugger::setVirtualTimeRate(ULONG aVirtualTimeRate)
756{
757 HRESULT hrc = S_OK;
758
759 if (aVirtualTimeRate < 2 || aVirtualTimeRate > 20000)
760 return setError(E_INVALIDARG, tr("%u is out of range [2..20000]"), aVirtualTimeRate);
761
762 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
763 if (i_queueSettings())
764 mVirtualTimeRateQueued = aVirtualTimeRate;
765 else
766 {
767 Console::SafeVMPtr ptrVM(mParent);
768 hrc = ptrVM.rc();
769 if (SUCCEEDED(hrc))
770 {
771 int vrc = TMR3SetWarpDrive(ptrVM.rawUVM(), aVirtualTimeRate);
772 if (RT_FAILURE(vrc))
773 hrc = setError(VBOX_E_VM_ERROR, tr("TMR3SetWarpDrive(, %u) failed with rc=%Rrc"), aVirtualTimeRate, vrc);
774 }
775 }
776
777 return hrc;
778}
779
780/**
781 * Hack for getting the user mode VM handle (UVM).
782 *
783 * This is only temporary (promise) while prototyping the debugger.
784 *
785 * @returns COM status code
786 * @param aVM Where to store the vm handle. Since there is no
787 * uintptr_t in COM, we're using the max integer.
788 * (No, ULONG is not pointer sized!)
789 * @remarks The returned handle must be passed to VMR3ReleaseUVM()!
790 * @remarks Prior to 4.3 this returned PVM.
791 */
792HRESULT MachineDebugger::getVM(LONG64 *aVM)
793{
794 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
795
796 Console::SafeVMPtr ptrVM(mParent);
797 HRESULT hrc = ptrVM.rc();
798 if (SUCCEEDED(hrc))
799 {
800 VMR3RetainUVM(ptrVM.rawUVM());
801 *aVM = (intptr_t)ptrVM.rawUVM();
802 }
803
804 /*
805 * Note! ptrVM protection provided by SafeVMPtr is no long effective
806 * after we return from this method.
807 */
808 return hrc;
809}
810
811/**
812 * Get the VM uptime in milliseconds.
813 *
814 * @returns COM status code
815 * @param aUptime Where to store the uptime.
816 */
817HRESULT MachineDebugger::getUptime(LONG64 *aUptime)
818{
819 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
820
821 Console::SafeVMPtr ptrVM(mParent);
822 HRESULT hrc = ptrVM.rc();
823 if (SUCCEEDED(hrc))
824 *aUptime = (int64_t)TMR3TimeVirtGetMilli(ptrVM.rawUVM());
825
826 return hrc;
827}
828
829// IMachineDebugger methods
830/////////////////////////////////////////////////////////////////////////////
831
832HRESULT MachineDebugger::dumpGuestCore(const com::Utf8Str &aFilename, const com::Utf8Str &aCompression)
833{
834 if (aCompression.length())
835 return setError(E_INVALIDARG, tr("The compression parameter must be empty"));
836
837 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
838 Console::SafeVMPtr ptrVM(mParent);
839 HRESULT hrc = ptrVM.rc();
840 if (SUCCEEDED(hrc))
841 {
842 int vrc = DBGFR3CoreWrite(ptrVM.rawUVM(), aFilename.c_str(), false /*fReplaceFile*/);
843 if (RT_SUCCESS(vrc))
844 hrc = S_OK;
845 else
846 hrc = setError(E_FAIL, tr("DBGFR3CoreWrite failed with %Rrc"), vrc);
847 }
848
849 return hrc;
850}
851
852HRESULT MachineDebugger::dumpHostProcessCore(const com::Utf8Str &aFilename, const com::Utf8Str &aCompression)
853{
854 RT_NOREF(aFilename, aCompression);
855 ReturnComNotImplemented();
856}
857
858/**
859 * Debug info string buffer formatter.
860 */
861typedef struct MACHINEDEBUGGERINOFHLP
862{
863 /** The core info helper structure. */
864 DBGFINFOHLP Core;
865 /** Pointer to the buffer. */
866 char *pszBuf;
867 /** The size of the buffer. */
868 size_t cbBuf;
869 /** The offset into the buffer */
870 size_t offBuf;
871 /** Indicates an out-of-memory condition. */
872 bool fOutOfMemory;
873} MACHINEDEBUGGERINOFHLP;
874/** Pointer to a Debug info string buffer formatter. */
875typedef MACHINEDEBUGGERINOFHLP *PMACHINEDEBUGGERINOFHLP;
876
877
878/**
879 * @callback_method_impl{FNRTSTROUTPUT}
880 */
881static DECLCALLBACK(size_t) MachineDebuggerInfoOutput(void *pvArg, const char *pachChars, size_t cbChars)
882{
883 PMACHINEDEBUGGERINOFHLP pHlp = (PMACHINEDEBUGGERINOFHLP)pvArg;
884
885 /*
886 * Grow the buffer if required.
887 */
888 size_t const cbRequired = cbChars + pHlp->offBuf + 1;
889 if (cbRequired > pHlp->cbBuf)
890 {
891 if (RT_UNLIKELY(pHlp->fOutOfMemory))
892 return 0;
893
894 size_t cbBufNew = pHlp->cbBuf * 2;
895 if (cbRequired > cbBufNew)
896 cbBufNew = RT_ALIGN_Z(cbRequired, 256);
897 void *pvBufNew = RTMemRealloc(pHlp->pszBuf, cbBufNew);
898 if (RT_UNLIKELY(!pvBufNew))
899 {
900 pHlp->fOutOfMemory = true;
901 RTMemFree(pHlp->pszBuf);
902 pHlp->pszBuf = NULL;
903 pHlp->cbBuf = 0;
904 pHlp->offBuf = 0;
905 return 0;
906 }
907
908 pHlp->pszBuf = (char *)pvBufNew;
909 pHlp->cbBuf = cbBufNew;
910 }
911
912 /*
913 * Copy the bytes into the buffer and terminate it.
914 */
915 if (cbChars)
916 {
917 memcpy(&pHlp->pszBuf[pHlp->offBuf], pachChars, cbChars);
918 pHlp->offBuf += cbChars;
919 }
920 pHlp->pszBuf[pHlp->offBuf] = '\0';
921 Assert(pHlp->offBuf < pHlp->cbBuf);
922 return cbChars;
923}
924
925/**
926 * @interface_method_impl{DBGFINFOHLP,pfnPrintfV}
927 */
928static DECLCALLBACK(void) MachineDebuggerInfoPrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
929{
930 RTStrFormatV(MachineDebuggerInfoOutput, (void *)pHlp, NULL, NULL, pszFormat, args);
931}
932
933/**
934 * @interface_method_impl{DBGFINFOHLP,pfnPrintf}
935 */
936static DECLCALLBACK(void) MachineDebuggerInfoPrintf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
937{
938 va_list va;
939 va_start(va, pszFormat);
940 MachineDebuggerInfoPrintfV(pHlp, pszFormat, va);
941 va_end(va);
942}
943
944/**
945 * Initializes the debug info string buffer formatter
946 *
947 * @param pHlp The help structure to init.
948 */
949static void MachineDebuggerInfoInit(PMACHINEDEBUGGERINOFHLP pHlp)
950{
951 pHlp->Core.pfnPrintf = MachineDebuggerInfoPrintf;
952 pHlp->Core.pfnPrintfV = MachineDebuggerInfoPrintfV;
953 pHlp->pszBuf = NULL;
954 pHlp->cbBuf = 0;
955 pHlp->offBuf = 0;
956 pHlp->fOutOfMemory = false;
957}
958
959/**
960 * Deletes the debug info string buffer formatter.
961 * @param pHlp The helper structure to delete.
962 */
963static void MachineDebuggerInfoDelete(PMACHINEDEBUGGERINOFHLP pHlp)
964{
965 RTMemFree(pHlp->pszBuf);
966 pHlp->pszBuf = NULL;
967}
968
969HRESULT MachineDebugger::info(const com::Utf8Str &aName, const com::Utf8Str &aArgs, com::Utf8Str &aInfo)
970{
971 LogFlowThisFunc(("\n"));
972
973 /*
974 * Do the autocaller and lock bits.
975 */
976 AutoCaller autoCaller(this);
977 HRESULT hrc = autoCaller.rc();
978 if (SUCCEEDED(hrc))
979 {
980 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
981 Console::SafeVMPtr ptrVM(mParent);
982 hrc = ptrVM.rc();
983 if (SUCCEEDED(hrc))
984 {
985 /*
986 * Create a helper and call DBGFR3Info.
987 */
988 MACHINEDEBUGGERINOFHLP Hlp;
989 MachineDebuggerInfoInit(&Hlp);
990 int vrc = DBGFR3Info(ptrVM.rawUVM(), aName.c_str(), aArgs.c_str(), &Hlp.Core);
991 if (RT_SUCCESS(vrc))
992 {
993 if (!Hlp.fOutOfMemory)
994 {
995 /*
996 * Convert the info string, watching out for allocation errors.
997 */
998 try
999 {
1000 Bstr bstrInfo(Hlp.pszBuf);
1001 aInfo = bstrInfo;
1002 }
1003 catch (std::bad_alloc)
1004 {
1005 hrc = E_OUTOFMEMORY;
1006 }
1007 }
1008 else
1009 hrc = E_OUTOFMEMORY;
1010 }
1011 else
1012 hrc = setError(VBOX_E_VM_ERROR, tr("DBGFR3Info failed with %Rrc"), vrc);
1013 MachineDebuggerInfoDelete(&Hlp);
1014 }
1015 }
1016 return hrc;
1017}
1018
1019HRESULT MachineDebugger::injectNMI()
1020{
1021 LogFlowThisFunc(("\n"));
1022
1023 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1024 Console::SafeVMPtr ptrVM(mParent);
1025 HRESULT hrc = ptrVM.rc();
1026 if (SUCCEEDED(hrc))
1027 {
1028 int vrc = DBGFR3InjectNMI(ptrVM.rawUVM(), 0);
1029 if (RT_SUCCESS(vrc))
1030 hrc = S_OK;
1031 else
1032 hrc = setError(E_FAIL, tr("DBGFR3InjectNMI failed with %Rrc"), vrc);
1033 }
1034 return hrc;
1035}
1036
1037HRESULT MachineDebugger::modifyLogFlags(const com::Utf8Str &aSettings)
1038{
1039 LogFlowThisFunc(("aSettings=%s\n", aSettings.c_str()));
1040 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1041 Console::SafeVMPtr ptrVM(mParent);
1042 HRESULT hrc = ptrVM.rc();
1043 if (SUCCEEDED(hrc))
1044 {
1045 int vrc = DBGFR3LogModifyFlags(ptrVM.rawUVM(), aSettings.c_str());
1046 if (RT_SUCCESS(vrc))
1047 hrc = S_OK;
1048 else
1049 hrc = setError(E_FAIL, tr("DBGFR3LogModifyFlags failed with %Rrc"), vrc);
1050 }
1051 return hrc;
1052}
1053
1054HRESULT MachineDebugger::modifyLogGroups(const com::Utf8Str &aSettings)
1055{
1056 LogFlowThisFunc(("aSettings=%s\n", aSettings.c_str()));
1057 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1058 Console::SafeVMPtr ptrVM(mParent);
1059 HRESULT hrc = ptrVM.rc();
1060 if (SUCCEEDED(hrc))
1061 {
1062 int vrc = DBGFR3LogModifyGroups(ptrVM.rawUVM(), aSettings.c_str());
1063 if (RT_SUCCESS(vrc))
1064 hrc = S_OK;
1065 else
1066 hrc = setError(E_FAIL, tr("DBGFR3LogModifyGroups failed with %Rrc"), vrc);
1067 }
1068 return hrc;
1069}
1070
1071HRESULT MachineDebugger::modifyLogDestinations(const com::Utf8Str &aSettings)
1072{
1073 LogFlowThisFunc(("aSettings=%s\n", aSettings.c_str()));
1074 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1075 Console::SafeVMPtr ptrVM(mParent);
1076 HRESULT hrc = ptrVM.rc();
1077 if (SUCCEEDED(hrc))
1078 {
1079 int vrc = DBGFR3LogModifyDestinations(ptrVM.rawUVM(), aSettings.c_str());
1080 if (RT_SUCCESS(vrc))
1081 hrc = S_OK;
1082 else
1083 hrc = setError(E_FAIL, tr("DBGFR3LogModifyDestinations failed with %Rrc"), vrc);
1084 }
1085 return hrc;
1086}
1087
1088HRESULT MachineDebugger::readPhysicalMemory(LONG64 aAddress, ULONG aSize, std::vector<BYTE> &aBytes)
1089{
1090 RT_NOREF(aAddress, aSize, aBytes);
1091 ReturnComNotImplemented();
1092}
1093
1094HRESULT MachineDebugger::writePhysicalMemory(LONG64 aAddress, ULONG aSize, const std::vector<BYTE> &aBytes)
1095{
1096 RT_NOREF(aAddress, aSize, aBytes);
1097 ReturnComNotImplemented();
1098}
1099
1100HRESULT MachineDebugger::readVirtualMemory(ULONG aCpuId, LONG64 aAddress, ULONG aSize, std::vector<BYTE> &aBytes)
1101{
1102 RT_NOREF(aCpuId, aAddress, aSize, aBytes);
1103 ReturnComNotImplemented();
1104}
1105
1106HRESULT MachineDebugger::writeVirtualMemory(ULONG aCpuId, LONG64 aAddress, ULONG aSize, const std::vector<BYTE> &aBytes)
1107{
1108 RT_NOREF(aCpuId, aAddress, aSize, aBytes);
1109 ReturnComNotImplemented();
1110}
1111
1112HRESULT MachineDebugger::loadPlugIn(const com::Utf8Str &aName, com::Utf8Str &aPlugInName)
1113{
1114 /*
1115 * Lock the debugger and get the VM pointer
1116 */
1117 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1118 Console::SafeVMPtr ptrVM(mParent);
1119 HRESULT hrc = ptrVM.rc();
1120 if (SUCCEEDED(hrc))
1121 {
1122 /*
1123 * Do the job and try convert the name.
1124 */
1125 if (aName.equals("all"))
1126 {
1127 DBGFR3PlugInLoadAll(ptrVM.rawUVM());
1128 try
1129 {
1130 aPlugInName = "all";
1131 hrc = S_OK;
1132 }
1133 catch (std::bad_alloc)
1134 {
1135 hrc = E_OUTOFMEMORY;
1136 }
1137 }
1138 else
1139 {
1140 RTERRINFOSTATIC ErrInfo;
1141 char szName[80];
1142 int vrc = DBGFR3PlugInLoad(ptrVM.rawUVM(), aName.c_str(), szName, sizeof(szName), RTErrInfoInitStatic(&ErrInfo));
1143 if (RT_SUCCESS(vrc))
1144 {
1145 try
1146 {
1147 aPlugInName = szName;
1148 hrc = S_OK;
1149 }
1150 catch (std::bad_alloc)
1151 {
1152 hrc = E_OUTOFMEMORY;
1153 }
1154 }
1155 else
1156 hrc = setErrorVrc(vrc, "%s", ErrInfo.szMsg);
1157 }
1158 }
1159 return hrc;
1160
1161}
1162
1163HRESULT MachineDebugger::unloadPlugIn(const com::Utf8Str &aName)
1164{
1165 /*
1166 * Lock the debugger and get the VM pointer
1167 */
1168 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1169 Console::SafeVMPtr ptrVM(mParent);
1170 HRESULT hrc = ptrVM.rc();
1171 if (SUCCEEDED(hrc))
1172 {
1173 /*
1174 * Do the job and try convert the name.
1175 */
1176 if (aName.equals("all"))
1177 {
1178 DBGFR3PlugInUnloadAll(ptrVM.rawUVM());
1179 hrc = S_OK;
1180 }
1181 else
1182 {
1183 int vrc = DBGFR3PlugInUnload(ptrVM.rawUVM(), aName.c_str());
1184 if (RT_SUCCESS(vrc))
1185 hrc = S_OK;
1186 else if (vrc == VERR_NOT_FOUND)
1187 hrc = setErrorBoth(E_FAIL, vrc, "Plug-in '%s' was not found", aName.c_str());
1188 else
1189 hrc = setErrorVrc(vrc, "Error unloading '%s': %Rrc", aName.c_str(), vrc);
1190 }
1191 }
1192 return hrc;
1193
1194}
1195
1196HRESULT MachineDebugger::detectOS(com::Utf8Str &aOs)
1197{
1198 LogFlowThisFunc(("\n"));
1199
1200 /*
1201 * Lock the debugger and get the VM pointer
1202 */
1203 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1204 Console::SafeVMPtr ptrVM(mParent);
1205 HRESULT hrc = ptrVM.rc();
1206 if (SUCCEEDED(hrc))
1207 {
1208 /*
1209 * Do the job.
1210 */
1211 char szName[64];
1212 int vrc = DBGFR3OSDetect(ptrVM.rawUVM(), szName, sizeof(szName));
1213 if (RT_SUCCESS(vrc) && vrc != VINF_DBGF_OS_NOT_DETCTED)
1214 {
1215 try
1216 {
1217 aOs = szName;
1218 }
1219 catch (std::bad_alloc)
1220 {
1221 hrc = E_OUTOFMEMORY;
1222 }
1223 }
1224 else
1225 hrc = setError(VBOX_E_VM_ERROR, tr("DBGFR3OSDetect failed with %Rrc"), vrc);
1226 }
1227 return hrc;
1228}
1229
1230HRESULT MachineDebugger::queryOSKernelLog(ULONG aMaxMessages, com::Utf8Str &aDmesg)
1231{
1232 /*
1233 * Lock the debugger and get the VM pointer
1234 */
1235 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1236 Console::SafeVMPtr ptrVM(mParent);
1237 HRESULT hrc = ptrVM.rc();
1238 if (SUCCEEDED(hrc))
1239 {
1240 PDBGFOSIDMESG pDmesg = (PDBGFOSIDMESG)DBGFR3OSQueryInterface(ptrVM.rawUVM(), DBGFOSINTERFACE_DMESG);
1241 if (pDmesg)
1242 {
1243 size_t cbActual;
1244 size_t cbBuf = _512K;
1245 int vrc = aDmesg.reserveNoThrow(cbBuf);
1246 if (RT_SUCCESS(vrc))
1247 {
1248 uint32_t cMessages = aMaxMessages == 0 ? UINT32_MAX : aMaxMessages;
1249 vrc = pDmesg->pfnQueryKernelLog(pDmesg, ptrVM.rawUVM(), 0 /*fFlags*/, cMessages,
1250 aDmesg.mutableRaw(), cbBuf, &cbActual);
1251
1252 uint32_t cTries = 10;
1253 while (vrc == VERR_BUFFER_OVERFLOW && cbBuf < 16*_1M && cTries-- > 0)
1254 {
1255 cbBuf = RT_ALIGN_Z(cbActual + _4K, _4K);
1256 vrc = aDmesg.reserveNoThrow(cbBuf);
1257 if (RT_SUCCESS(vrc))
1258 vrc = pDmesg->pfnQueryKernelLog(pDmesg, ptrVM.rawUVM(), 0 /*fFlags*/, cMessages,
1259 aDmesg.mutableRaw(), cbBuf, &cbActual);
1260 }
1261 if (RT_SUCCESS(vrc))
1262 aDmesg.jolt();
1263 else if (vrc == VERR_BUFFER_OVERFLOW)
1264 hrc = setError(E_FAIL, "Too much log available, must use the maxMessages parameter to restrict.");
1265 else
1266 hrc = setErrorVrc(vrc);
1267 }
1268 else
1269 hrc = setErrorBoth(E_OUTOFMEMORY, vrc);
1270 }
1271 else
1272 hrc = setError(E_FAIL, "The dmesg interface isn't implemented by guest OS digger, or detectOS() has not been called.");
1273 }
1274 return hrc;
1275}
1276
1277/**
1278 * Formats a register value.
1279 *
1280 * This is used by both register getter methods.
1281 *
1282 * @returns
1283 * @param a_pbstr The output Bstr variable.
1284 * @param a_pValue The value to format.
1285 * @param a_enmType The type of the value.
1286 */
1287DECLINLINE(HRESULT) formatRegisterValue(Bstr *a_pbstr, PCDBGFREGVAL a_pValue, DBGFREGVALTYPE a_enmType)
1288{
1289 char szHex[160];
1290 ssize_t cch = DBGFR3RegFormatValue(szHex, sizeof(szHex), a_pValue, a_enmType, true /*fSpecial*/);
1291 if (RT_UNLIKELY(cch <= 0))
1292 return E_UNEXPECTED;
1293 *a_pbstr = szHex;
1294 return S_OK;
1295}
1296
1297HRESULT MachineDebugger::getRegister(ULONG aCpuId, const com::Utf8Str &aName, com::Utf8Str &aValue)
1298{
1299 /*
1300 * The prologue.
1301 */
1302 LogFlowThisFunc(("\n"));
1303 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1304 Console::SafeVMPtr ptrVM(mParent);
1305 HRESULT hrc = ptrVM.rc();
1306 if (SUCCEEDED(hrc))
1307 {
1308 /*
1309 * Real work.
1310 */
1311 DBGFREGVAL Value;
1312 DBGFREGVALTYPE enmType;
1313 int vrc = DBGFR3RegNmQuery(ptrVM.rawUVM(), aCpuId, aName.c_str(), &Value, &enmType);
1314 if (RT_SUCCESS(vrc))
1315 {
1316 try
1317 {
1318 Bstr bstrValue;
1319 hrc = formatRegisterValue(&bstrValue, &Value, enmType);
1320 if (SUCCEEDED(hrc))
1321 aValue = Utf8Str(bstrValue);
1322 }
1323 catch (std::bad_alloc)
1324 {
1325 hrc = E_OUTOFMEMORY;
1326 }
1327 }
1328 else if (vrc == VERR_DBGF_REGISTER_NOT_FOUND)
1329 hrc = setError(E_FAIL, tr("Register '%s' was not found"), aName.c_str());
1330 else if (vrc == VERR_INVALID_CPU_ID)
1331 hrc = setError(E_FAIL, tr("Invalid CPU ID: %u"), aCpuId);
1332 else
1333 hrc = setError(VBOX_E_VM_ERROR,
1334 tr("DBGFR3RegNmQuery failed with rc=%Rrc querying register '%s' with default cpu set to %u"),
1335 vrc, aName.c_str(), aCpuId);
1336 }
1337
1338 return hrc;
1339}
1340
1341HRESULT MachineDebugger::getRegisters(ULONG aCpuId, std::vector<com::Utf8Str> &aNames, std::vector<com::Utf8Str> &aValues)
1342{
1343 RT_NOREF(aCpuId); /** @todo fix missing aCpuId usage! */
1344
1345 /*
1346 * The prologue.
1347 */
1348 LogFlowThisFunc(("\n"));
1349 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1350 Console::SafeVMPtr ptrVM(mParent);
1351 HRESULT hrc = ptrVM.rc();
1352 if (SUCCEEDED(hrc))
1353 {
1354 /*
1355 * Real work.
1356 */
1357 size_t cRegs;
1358 int vrc = DBGFR3RegNmQueryAllCount(ptrVM.rawUVM(), &cRegs);
1359 if (RT_SUCCESS(vrc))
1360 {
1361 PDBGFREGENTRYNM paRegs = (PDBGFREGENTRYNM)RTMemAllocZ(sizeof(paRegs[0]) * cRegs);
1362 if (paRegs)
1363 {
1364 vrc = DBGFR3RegNmQueryAll(ptrVM.rawUVM(), paRegs, cRegs);
1365 if (RT_SUCCESS(vrc))
1366 {
1367 try
1368 {
1369 aValues.resize(cRegs);
1370 aNames.resize(cRegs);
1371 for (uint32_t iReg = 0; iReg < cRegs; iReg++)
1372 {
1373 char szHex[160];
1374 szHex[159] = szHex[0] = '\0';
1375 ssize_t cch = DBGFR3RegFormatValue(szHex, sizeof(szHex), &paRegs[iReg].Val,
1376 paRegs[iReg].enmType, true /*fSpecial*/);
1377 Assert(cch > 0); NOREF(cch);
1378 aNames[iReg] = Utf8Str(paRegs[iReg].pszName);
1379 aValues[iReg] = Utf8Str(szHex);
1380 }
1381 }
1382 catch (std::bad_alloc)
1383 {
1384 hrc = E_OUTOFMEMORY;
1385 }
1386 }
1387 else
1388 hrc = setError(E_FAIL, tr("DBGFR3RegNmQueryAll failed with %Rrc"), vrc);
1389
1390 RTMemFree(paRegs);
1391 }
1392 else
1393 hrc = E_OUTOFMEMORY;
1394 }
1395 else
1396 hrc = setError(E_FAIL, tr("DBGFR3RegNmQueryAllCount failed with %Rrc"), vrc);
1397 }
1398 return hrc;
1399}
1400
1401HRESULT MachineDebugger::setRegister(ULONG aCpuId, const com::Utf8Str &aName, const com::Utf8Str &aValue)
1402{
1403 RT_NOREF(aCpuId, aName, aValue);
1404 ReturnComNotImplemented();
1405}
1406
1407HRESULT MachineDebugger::setRegisters(ULONG aCpuId, const std::vector<com::Utf8Str> &aNames,
1408 const std::vector<com::Utf8Str> &aValues)
1409{
1410 RT_NOREF(aCpuId, aNames, aValues);
1411 ReturnComNotImplemented();
1412}
1413
1414HRESULT MachineDebugger::dumpGuestStack(ULONG aCpuId, com::Utf8Str &aStack)
1415{
1416 /*
1417 * The prologue.
1418 */
1419 LogFlowThisFunc(("\n"));
1420 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1421 Console::SafeVMPtr ptrVM(mParent);
1422 HRESULT hrc = ptrVM.rc();
1423 if (SUCCEEDED(hrc))
1424 {
1425 /*
1426 * There is currently a problem with the windows diggers and SMP, where
1427 * guest driver memory is being read from CPU zero in order to ensure that
1428 * we've got a consisten virtual memory view. If one of the other CPUs
1429 * initiates a rendezvous while we're unwinding the stack and trying to
1430 * read guest driver memory, we will deadlock.
1431 *
1432 * So, check the VM state and maybe suspend the VM before we continue.
1433 */
1434 int vrc = VINF_SUCCESS;
1435 bool fPaused = false;
1436 if (aCpuId != 0)
1437 {
1438 VMSTATE enmVmState = VMR3GetStateU(ptrVM.rawUVM());
1439 if ( enmVmState == VMSTATE_RUNNING
1440 || enmVmState == VMSTATE_RUNNING_LS
1441 || enmVmState == VMSTATE_RUNNING_FT)
1442 {
1443 alock.release();
1444 vrc = VMR3Suspend(ptrVM.rawUVM(), VMSUSPENDREASON_USER);
1445 alock.acquire();
1446 fPaused = RT_SUCCESS(vrc);
1447 }
1448 }
1449 if (RT_SUCCESS(vrc))
1450 {
1451 PCDBGFSTACKFRAME pFirstFrame;
1452 vrc = DBGFR3StackWalkBegin(ptrVM.rawUVM(), aCpuId, DBGFCODETYPE_GUEST, &pFirstFrame);
1453 if (RT_SUCCESS(vrc))
1454 {
1455 /*
1456 * Print header.
1457 */
1458 try
1459 {
1460 uint32_t fBitFlags = 0;
1461 for (PCDBGFSTACKFRAME pFrame = pFirstFrame;
1462 pFrame;
1463 pFrame = DBGFR3StackWalkNext(pFrame))
1464 {
1465 uint32_t const fCurBitFlags = pFrame->fFlags & (DBGFSTACKFRAME_FLAGS_16BIT | DBGFSTACKFRAME_FLAGS_32BIT | DBGFSTACKFRAME_FLAGS_64BIT);
1466 if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_16BIT)
1467 {
1468 if (fCurBitFlags != fBitFlags)
1469 aStack.append("SS:BP Ret SS:BP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n");
1470 aStack.append(Utf8StrFmt("%04RX16:%04RX16 %04RX16:%04RX16 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
1471 pFrame->AddrFrame.Sel,
1472 (uint16_t)pFrame->AddrFrame.off,
1473 pFrame->AddrReturnFrame.Sel,
1474 (uint16_t)pFrame->AddrReturnFrame.off,
1475 (uint32_t)pFrame->AddrReturnPC.Sel,
1476 (uint32_t)pFrame->AddrReturnPC.off,
1477 pFrame->Args.au32[0],
1478 pFrame->Args.au32[1],
1479 pFrame->Args.au32[2],
1480 pFrame->Args.au32[3]));
1481 }
1482 else if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_32BIT)
1483 {
1484 if (fCurBitFlags != fBitFlags)
1485 aStack.append("EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n");
1486 aStack.append(Utf8StrFmt("%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
1487 (uint32_t)pFrame->AddrFrame.off,
1488 (uint32_t)pFrame->AddrReturnFrame.off,
1489 (uint32_t)pFrame->AddrReturnPC.Sel,
1490 (uint32_t)pFrame->AddrReturnPC.off,
1491 pFrame->Args.au32[0],
1492 pFrame->Args.au32[1],
1493 pFrame->Args.au32[2],
1494 pFrame->Args.au32[3]));
1495 }
1496 else if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_64BIT)
1497 {
1498 if (fCurBitFlags != fBitFlags)
1499 aStack.append("RBP Ret SS:RBP Ret RIP CS:RIP / Symbol [line]\n");
1500 aStack.append(Utf8StrFmt("%016RX64 %04RX16:%016RX64 %016RX64",
1501 (uint64_t)pFrame->AddrFrame.off,
1502 pFrame->AddrReturnFrame.Sel,
1503 (uint64_t)pFrame->AddrReturnFrame.off,
1504 (uint64_t)pFrame->AddrReturnPC.off));
1505 }
1506
1507 if (!pFrame->pSymPC)
1508 aStack.append(Utf8StrFmt(fCurBitFlags & DBGFSTACKFRAME_FLAGS_64BIT
1509 ? " %RTsel:%016RGv"
1510 : fCurBitFlags & DBGFSTACKFRAME_FLAGS_32BIT
1511 ? " %RTsel:%08RGv"
1512 : " %RTsel:%04RGv"
1513 , pFrame->AddrPC.Sel, pFrame->AddrPC.off));
1514 else
1515 {
1516 RTGCINTPTR offDisp = pFrame->AddrPC.FlatPtr - pFrame->pSymPC->Value; /** @todo this isn't 100% correct for segmented stuff. */
1517 if (offDisp > 0)
1518 aStack.append(Utf8StrFmt(" %s+%llx", pFrame->pSymPC->szName, (int64_t)offDisp));
1519 else if (offDisp < 0)
1520 aStack.append(Utf8StrFmt(" %s-%llx", pFrame->pSymPC->szName, -(int64_t)offDisp));
1521 else
1522 aStack.append(Utf8StrFmt(" %s", pFrame->pSymPC->szName));
1523 }
1524 if (pFrame->pLinePC)
1525 aStack.append(Utf8StrFmt(" [%s @ 0i%d]", pFrame->pLinePC->szFilename, pFrame->pLinePC->uLineNo));
1526 aStack.append(Utf8StrFmt("\n"));
1527
1528 fBitFlags = fCurBitFlags;
1529 }
1530 }
1531 catch (std::bad_alloc)
1532 {
1533 hrc = E_OUTOFMEMORY;
1534 }
1535
1536 DBGFR3StackWalkEnd(pFirstFrame);
1537 }
1538 else
1539 hrc = setError(E_FAIL, tr("DBGFR3StackWalkBegin failed with %Rrc"), vrc);
1540
1541 /*
1542 * Resume the VM if we suspended it.
1543 */
1544 if (fPaused)
1545 {
1546 alock.release();
1547 VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_USER);
1548 }
1549 }
1550 else
1551 hrc = setError(E_FAIL, tr("Suspending the VM failed with %Rrc\n"), vrc);
1552 }
1553
1554 return hrc;
1555}
1556
1557/**
1558 * Resets VM statistics.
1559 *
1560 * @returns COM status code.
1561 * @param aPattern The selection pattern. A bit similar to filename globbing.
1562 */
1563HRESULT MachineDebugger::resetStats(const com::Utf8Str &aPattern)
1564{
1565 Console::SafeVMPtrQuiet ptrVM(mParent);
1566
1567 if (!ptrVM.isOk())
1568 return setError(VBOX_E_INVALID_VM_STATE, "Machine is not running");
1569
1570 STAMR3Reset(ptrVM.rawUVM(), aPattern.c_str());
1571
1572 return S_OK;
1573}
1574
1575/**
1576 * Dumps VM statistics to the log.
1577 *
1578 * @returns COM status code.
1579 * @param aPattern The selection pattern. A bit similar to filename globbing.
1580 */
1581HRESULT MachineDebugger::dumpStats(const com::Utf8Str &aPattern)
1582{
1583 Console::SafeVMPtrQuiet ptrVM(mParent);
1584
1585 if (!ptrVM.isOk())
1586 return setError(VBOX_E_INVALID_VM_STATE, "Machine is not running");
1587
1588 STAMR3Dump(ptrVM.rawUVM(), aPattern.c_str());
1589
1590 return S_OK;
1591}
1592
1593/**
1594 * Get the VM statistics in an XML format.
1595 *
1596 * @returns COM status code.
1597 * @param aPattern The selection pattern. A bit similar to filename globbing.
1598 * @param aWithDescriptions Whether to include the descriptions.
1599 * @param aStats The XML document containing the statistics.
1600 */
1601HRESULT MachineDebugger::getStats(const com::Utf8Str &aPattern, BOOL aWithDescriptions, com::Utf8Str &aStats)
1602{
1603 Console::SafeVMPtrQuiet ptrVM(mParent);
1604
1605 if (!ptrVM.isOk())
1606 return setError(VBOX_E_INVALID_VM_STATE, "Machine is not running");
1607
1608 char *pszSnapshot;
1609 int vrc = STAMR3Snapshot(ptrVM.rawUVM(), aPattern.c_str(), &pszSnapshot, NULL,
1610 !!aWithDescriptions);
1611 if (RT_FAILURE(vrc))
1612 return vrc == VERR_NO_MEMORY ? E_OUTOFMEMORY : E_FAIL;
1613
1614 /** @todo this is horribly inefficient! And it's kinda difficult to tell whether it failed...
1615 * Must use UTF-8 or ASCII here and completely avoid these two extra copy operations.
1616 * Until that's done, this method is kind of useless for debugger statistics GUI because
1617 * of the amount statistics in a debug build. */
1618 aStats = Utf8Str(pszSnapshot);
1619 STAMR3SnapshotFree(ptrVM.rawUVM(), pszSnapshot);
1620
1621 return S_OK;
1622}
1623
1624
1625// public methods only for internal purposes
1626/////////////////////////////////////////////////////////////////////////////
1627
1628void MachineDebugger::i_flushQueuedSettings()
1629{
1630 mFlushMode = true;
1631 if (mSingleStepQueued != -1)
1632 {
1633 COMSETTER(SingleStep)(mSingleStepQueued);
1634 mSingleStepQueued = -1;
1635 }
1636 for (unsigned i = 0; i < EMEXECPOLICY_END; i++)
1637 if (maiQueuedEmExecPolicyParams[i] != UINT8_MAX)
1638 {
1639 i_setEmExecPolicyProperty((EMEXECPOLICY)i, RT_BOOL(maiQueuedEmExecPolicyParams[i]));
1640 maiQueuedEmExecPolicyParams[i] = UINT8_MAX;
1641 }
1642 if (mPatmEnabledQueued != -1)
1643 {
1644 COMSETTER(PATMEnabled)(mPatmEnabledQueued);
1645 mPatmEnabledQueued = -1;
1646 }
1647 if (mCsamEnabledQueued != -1)
1648 {
1649 COMSETTER(CSAMEnabled)(mCsamEnabledQueued);
1650 mCsamEnabledQueued = -1;
1651 }
1652 if (mLogEnabledQueued != -1)
1653 {
1654 COMSETTER(LogEnabled)(mLogEnabledQueued);
1655 mLogEnabledQueued = -1;
1656 }
1657 if (mVirtualTimeRateQueued != UINT32_MAX)
1658 {
1659 COMSETTER(VirtualTimeRate)(mVirtualTimeRateQueued);
1660 mVirtualTimeRateQueued = UINT32_MAX;
1661 }
1662 mFlushMode = false;
1663}
1664
1665// private methods
1666/////////////////////////////////////////////////////////////////////////////
1667
1668bool MachineDebugger::i_queueSettings() const
1669{
1670 if (!mFlushMode)
1671 {
1672 // check if the machine is running
1673 MachineState_T machineState;
1674 mParent->COMGETTER(State)(&machineState);
1675 switch (machineState)
1676 {
1677 // queue the request
1678 default:
1679 return true;
1680
1681 case MachineState_Running:
1682 case MachineState_Paused:
1683 case MachineState_Stuck:
1684 case MachineState_LiveSnapshotting:
1685 case MachineState_Teleporting:
1686 break;
1687 }
1688 }
1689 return false;
1690}
1691/* 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