VirtualBox

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

Last change on this file since 70772 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use