VirtualBox

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

Last change on this file since 56858 was 56567, checked in by vboxsync, 9 years ago

IMachineDebugger: Fixed getters for LogDbgFlags, LogRelFlags, LogDbgGroups, LogRelGroups, LogDbgDestinations and LogRelDestinations. They returned nothing as the i_logStringProps worker method didn't actually have an output parameter and was using a local BSTR variable instead, which it would leak.

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