VirtualBox

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

Last change on this file since 56268 was 55996, checked in by vboxsync, 10 years ago

warning

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.0 KB
Line 
1/* $Id: MachineDebuggerImpl.cpp 55996 2015-05-21 09:50:28Z 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 astrSettings)
458{
459 BSTR *a_pbstrSettings = new BSTR;
460 astrSettings.cloneTo(a_pbstrSettings);
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 Bstr bstrEmpty;
473 bstrEmpty.cloneTo(a_pbstrSettings);
474 return S_OK;
475 }
476
477 /* Do the job. */
478 size_t cbBuf = _1K;
479 for (;;)
480 {
481 char *pszBuf = (char *)RTMemTmpAlloc(cbBuf);
482 AssertReturn(pszBuf, E_OUTOFMEMORY);
483
484 int rc = pfnLogGetStr(pLogger, pszBuf, cbBuf);
485 if (RT_SUCCESS(rc))
486 {
487 try
488 {
489 Bstr bstrRet(pszBuf);
490 bstrRet.detachTo(a_pbstrSettings);
491 hrc = S_OK;
492 }
493 catch (std::bad_alloc)
494 {
495 hrc = E_OUTOFMEMORY;
496 }
497 RTMemTmpFree(pszBuf);
498 return hrc;
499 }
500 RTMemTmpFree(pszBuf);
501 AssertReturn(rc == VERR_BUFFER_OVERFLOW, setError(VBOX_E_IPRT_ERROR, tr("%s returned %Rrc"), pszLogGetStr, rc));
502
503 /* try again with a bigger buffer. */
504 cbBuf *= 2;
505 AssertReturn(cbBuf <= _256K, setError(E_FAIL, tr("%s returns too much data"), pszLogGetStr));
506 }
507}
508
509HRESULT MachineDebugger::getLogDbgFlags(com::Utf8Str &aLogDbgFlags)
510{
511 HRESULT hrc = i_logStringProps(RTLogGetDefaultInstance(), RTLogGetFlags, "RTGetFlags", aLogDbgFlags);
512
513 return hrc;
514}
515
516HRESULT MachineDebugger::getLogDbgGroups(com::Utf8Str &aLogDbgGroups)
517{
518 HRESULT hrc = i_logStringProps(RTLogGetDefaultInstance(), RTLogGetGroupSettings, "RTLogGetGroupSettings", aLogDbgGroups);
519
520 return hrc;
521}
522
523HRESULT MachineDebugger::getLogDbgDestinations(com::Utf8Str &aLogDbgDestinations)
524{
525 HRESULT hrc = i_logStringProps(RTLogGetDefaultInstance(), RTLogGetDestinations, "RTLogGetDestinations", aLogDbgDestinations);
526 return hrc;
527}
528
529HRESULT MachineDebugger::getLogRelFlags(com::Utf8Str &aLogRelFlags)
530{
531 HRESULT hrc = i_logStringProps(RTLogRelGetDefaultInstance(), RTLogGetFlags, "RTGetFlags", aLogRelFlags);
532 return hrc;
533}
534
535HRESULT MachineDebugger::getLogRelGroups(com::Utf8Str &aLogRelGroups)
536{
537 HRESULT hrc = i_logStringProps(RTLogRelGetDefaultInstance(), RTLogGetGroupSettings, "RTLogGetGroupSettings", aLogRelGroups);
538 return hrc;
539}
540
541HRESULT MachineDebugger::getLogRelDestinations(com::Utf8Str &aLogRelDestinations)
542{
543 HRESULT hrc = i_logStringProps(RTLogRelGetDefaultInstance(), RTLogGetDestinations, "RTLogGetDestinations", aLogRelDestinations);
544 return hrc;
545}
546
547/**
548 * Returns the current hardware virtualization flag.
549 *
550 * @returns COM status code
551 * @param aEnabled address of result variable
552 */
553HRESULT MachineDebugger::getHWVirtExEnabled(BOOL *aHWVirtExEnabled)
554{
555 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
556
557 Console::SafeVMPtrQuiet ptrVM(mParent);
558
559 if (ptrVM.isOk())
560 *aHWVirtExEnabled = HMR3IsEnabled(ptrVM.rawUVM());
561 else
562 *aHWVirtExEnabled = false;
563
564 return S_OK;
565}
566
567/**
568 * Returns the current nested paging flag.
569 *
570 * @returns COM status code
571 * @param aEnabled address of result variable
572 */
573HRESULT MachineDebugger::getHWVirtExNestedPagingEnabled(BOOL *aHWVirtExNestedPagingEnabled)
574{
575 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
576
577 Console::SafeVMPtrQuiet ptrVM(mParent);
578
579 if (ptrVM.isOk())
580 *aHWVirtExNestedPagingEnabled = HMR3IsNestedPagingActive(ptrVM.rawUVM());
581 else
582 *aHWVirtExNestedPagingEnabled = false;
583
584 return S_OK;
585}
586
587/**
588 * Returns the current VPID flag.
589 *
590 * @returns COM status code
591 * @param aEnabled address of result variable
592 */
593HRESULT MachineDebugger::getHWVirtExVPIDEnabled(BOOL *aHWVirtExVPIDEnabled)
594{
595 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
596
597 Console::SafeVMPtrQuiet ptrVM(mParent);
598
599 if (ptrVM.isOk())
600 *aHWVirtExVPIDEnabled = HMR3IsVpidActive(ptrVM.rawUVM());
601 else
602 *aHWVirtExVPIDEnabled = false;
603
604 return S_OK;
605}
606
607/**
608 * Returns the current unrestricted execution setting.
609 *
610 * @returns COM status code
611 * @param aEnabled address of result variable
612 */
613HRESULT MachineDebugger::getHWVirtExUXEnabled(BOOL *aHWVirtExUXEnabled)
614{
615 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
616
617 Console::SafeVMPtrQuiet ptrVM(mParent);
618
619 if (ptrVM.isOk())
620 *aHWVirtExUXEnabled = HMR3IsUXActive(ptrVM.rawUVM());
621 else
622 *aHWVirtExUXEnabled = false;
623
624 return S_OK;
625}
626
627HRESULT MachineDebugger::getOSName(com::Utf8Str &aOSName)
628{
629 LogFlowThisFunc(("\n"));
630 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
631 Console::SafeVMPtr ptrVM(mParent);
632 HRESULT hrc = ptrVM.rc();
633 if (SUCCEEDED(hrc))
634 {
635 /*
636 * Do the job and try convert the name.
637 */
638 char szName[64];
639 int vrc = DBGFR3OSQueryNameAndVersion(ptrVM.rawUVM(), szName, sizeof(szName), NULL, 0);
640 if (RT_SUCCESS(vrc))
641 {
642 try
643 {
644 Bstr bstrName(szName);
645 aOSName = Utf8Str(bstrName);
646 }
647 catch (std::bad_alloc)
648 {
649 hrc = E_OUTOFMEMORY;
650 }
651 }
652 else
653 hrc = setError(VBOX_E_VM_ERROR, tr("DBGFR3OSQueryNameAndVersion failed with %Rrc"), vrc);
654 }
655 return hrc;
656}
657
658HRESULT MachineDebugger::getOSVersion(com::Utf8Str &aOSVersion)
659{
660 LogFlowThisFunc(("\n"));
661 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
662 Console::SafeVMPtr ptrVM(mParent);
663 HRESULT hrc = ptrVM.rc();
664 if (SUCCEEDED(hrc))
665 {
666 /*
667 * Do the job and try convert the name.
668 */
669 char szVersion[256];
670 int vrc = DBGFR3OSQueryNameAndVersion(ptrVM.rawUVM(), NULL, 0, szVersion, sizeof(szVersion));
671 if (RT_SUCCESS(vrc))
672 {
673 try
674 {
675 Bstr bstrVersion(szVersion);
676 aOSVersion = Utf8Str(bstrVersion);
677 }
678 catch (std::bad_alloc)
679 {
680 hrc = E_OUTOFMEMORY;
681 }
682 }
683 else
684 hrc = setError(VBOX_E_VM_ERROR, tr("DBGFR3OSQueryNameAndVersion failed with %Rrc"), vrc);
685 }
686 return hrc;
687}
688
689/**
690 * Returns the current PAE flag.
691 *
692 * @returns COM status code
693 * @param aEnabled address of result variable
694 */
695HRESULT MachineDebugger::getPAEEnabled(BOOL *aPAEEnabled)
696{
697 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
698
699 Console::SafeVMPtrQuiet ptrVM(mParent);
700
701 if (ptrVM.isOk())
702 {
703 uint32_t cr4;
704 int rc = DBGFR3RegCpuQueryU32(ptrVM.rawUVM(), 0 /*idCpu*/, DBGFREG_CR4, &cr4); AssertRC(rc);
705 *aPAEEnabled = RT_BOOL(cr4 & X86_CR4_PAE);
706 }
707 else
708 *aPAEEnabled = false;
709
710 return S_OK;
711}
712
713/**
714 * Returns the current virtual time rate.
715 *
716 * @returns COM status code.
717 * @param a_puPct Where to store the rate.
718 */
719HRESULT MachineDebugger::getVirtualTimeRate(ULONG *aVirtualTimeRate)
720{
721 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
722
723 Console::SafeVMPtr ptrVM(mParent);
724 HRESULT hrc = ptrVM.rc();
725 if (SUCCEEDED(hrc))
726 *aVirtualTimeRate = TMR3GetWarpDrive(ptrVM.rawUVM());
727
728 return hrc;
729}
730
731/**
732 * Returns the current virtual time rate.
733 *
734 * @returns COM status code.
735 * @param aPct Where to store the rate.
736 */
737HRESULT MachineDebugger::setVirtualTimeRate(ULONG aVirtualTimeRate)
738{
739 HRESULT hrc = S_OK;
740
741 if (aVirtualTimeRate < 2 || aVirtualTimeRate > 20000)
742 return setError(E_INVALIDARG, tr("%u is out of range [2..20000]"), aVirtualTimeRate);
743
744 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
745 if (i_queueSettings())
746 mVirtualTimeRateQueued = aVirtualTimeRate;
747 else
748 {
749 Console::SafeVMPtr ptrVM(mParent);
750 hrc = ptrVM.rc();
751 if (SUCCEEDED(hrc))
752 {
753 int vrc = TMR3SetWarpDrive(ptrVM.rawUVM(), aVirtualTimeRate);
754 if (RT_FAILURE(vrc))
755 hrc = setError(VBOX_E_VM_ERROR, tr("TMR3SetWarpDrive(, %u) failed with rc=%Rrc"), aVirtualTimeRate, vrc);
756 }
757 }
758
759 return hrc;
760}
761
762/**
763 * Hack for getting the user mode VM handle (UVM).
764 *
765 * This is only temporary (promise) while prototyping the debugger.
766 *
767 * @returns COM status code
768 * @param a_u64Vm Where to store the vm handle. Since there is no
769 * uintptr_t in COM, we're using the max integer.
770 * (No, ULONG is not pointer sized!)
771 * @remarks The returned handle must be passed to VMR3ReleaseUVM()!
772 * @remarks Prior to 4.3 this returned PVM.
773 */
774HRESULT MachineDebugger::getVM(LONG64 *aVM)
775{
776 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
777
778 Console::SafeVMPtr ptrVM(mParent);
779 HRESULT hrc = ptrVM.rc();
780 if (SUCCEEDED(hrc))
781 {
782 VMR3RetainUVM(ptrVM.rawUVM());
783 *aVM = (intptr_t)ptrVM.rawUVM();
784 }
785
786 /*
787 * Note! ptrVM protection provided by SafeVMPtr is no long effective
788 * after we return from this method.
789 */
790 return hrc;
791}
792
793// IMachineDebugger methods
794/////////////////////////////////////////////////////////////////////////////
795
796HRESULT MachineDebugger::dumpGuestCore(const com::Utf8Str &aFilename, const com::Utf8Str &aCompression)
797{
798 if (aCompression.length())
799 return setError(E_INVALIDARG, tr("The compression parameter must be empty"));
800
801 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
802 Console::SafeVMPtr ptrVM(mParent);
803 HRESULT hrc = ptrVM.rc();
804 if (SUCCEEDED(hrc))
805 {
806 int vrc = DBGFR3CoreWrite(ptrVM.rawUVM(), aFilename.c_str(), false /*fReplaceFile*/);
807 if (RT_SUCCESS(vrc))
808 hrc = S_OK;
809 else
810 hrc = setError(E_FAIL, tr("DBGFR3CoreWrite failed with %Rrc"), vrc);
811 }
812
813 return hrc;
814}
815
816HRESULT MachineDebugger::dumpHostProcessCore(const com::Utf8Str &aFilename, const com::Utf8Str &aCompression)
817{
818 ReturnComNotImplemented();
819}
820
821/**
822 * Debug info string buffer formatter.
823 */
824typedef struct MACHINEDEBUGGERINOFHLP
825{
826 /** The core info helper structure. */
827 DBGFINFOHLP Core;
828 /** Pointer to the buffer. */
829 char *pszBuf;
830 /** The size of the buffer. */
831 size_t cbBuf;
832 /** The offset into the buffer */
833 size_t offBuf;
834 /** Indicates an out-of-memory condition. */
835 bool fOutOfMemory;
836} MACHINEDEBUGGERINOFHLP;
837/** Pointer to a Debug info string buffer formatter. */
838typedef MACHINEDEBUGGERINOFHLP *PMACHINEDEBUGGERINOFHLP;
839
840
841/**
842 * @callback_method_impl{FNRTSTROUTPUT}
843 */
844static DECLCALLBACK(size_t) MachineDebuggerInfoOutput(void *pvArg, const char *pachChars, size_t cbChars)
845{
846 PMACHINEDEBUGGERINOFHLP pHlp = (PMACHINEDEBUGGERINOFHLP)pvArg;
847
848 /*
849 * Grow the buffer if required.
850 */
851 size_t const cbRequired = cbChars + pHlp->offBuf + 1;
852 if (cbRequired > pHlp->cbBuf)
853 {
854 if (RT_UNLIKELY(pHlp->fOutOfMemory))
855 return 0;
856
857 size_t cbBufNew = pHlp->cbBuf * 2;
858 if (cbRequired > cbBufNew)
859 cbBufNew = RT_ALIGN_Z(cbRequired, 256);
860 void *pvBufNew = RTMemRealloc(pHlp->pszBuf, cbBufNew);
861 if (RT_UNLIKELY(!pvBufNew))
862 {
863 pHlp->fOutOfMemory = true;
864 RTMemFree(pHlp->pszBuf);
865 pHlp->pszBuf = NULL;
866 pHlp->cbBuf = 0;
867 pHlp->offBuf = 0;
868 return 0;
869 }
870
871 pHlp->pszBuf = (char *)pvBufNew;
872 pHlp->cbBuf = cbBufNew;
873 }
874
875 /*
876 * Copy the bytes into the buffer and terminate it.
877 */
878 memcpy(&pHlp->pszBuf[pHlp->offBuf], pachChars, cbChars);
879 pHlp->offBuf += cbChars;
880 pHlp->pszBuf[pHlp->offBuf] = '\0';
881 Assert(pHlp->offBuf < pHlp->cbBuf);
882 return cbChars;
883}
884
885/**
886 * @interface_method_impl{DBGFINFOHLP, pfnPrintfV}
887 */
888static DECLCALLBACK(void) MachineDebuggerInfoPrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list va)
889{
890 RTStrFormatV(MachineDebuggerInfoOutput, (void *)pHlp, NULL, NULL, pszFormat, va);
891}
892
893/**
894 * @interface_method_impl{DBGFINFOHLP, pfnPrintf}
895 */
896static DECLCALLBACK(void) MachineDebuggerInfoPrintf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
897{
898 va_list va;
899 va_start(va, pszFormat);
900 MachineDebuggerInfoPrintfV(pHlp, pszFormat, va);
901 va_end(va);
902}
903
904/**
905 * Initializes the debug info string buffer formatter
906 *
907 * @param pHlp The help structure to init.
908 */
909static void MachineDebuggerInfoInit(PMACHINEDEBUGGERINOFHLP pHlp)
910{
911 pHlp->Core.pfnPrintf = MachineDebuggerInfoPrintf;
912 pHlp->Core.pfnPrintfV = MachineDebuggerInfoPrintfV;
913 pHlp->pszBuf = NULL;
914 pHlp->cbBuf = 0;
915 pHlp->offBuf = 0;
916 pHlp->fOutOfMemory = false;
917}
918
919/**
920 * Deletes the debug info string buffer formatter.
921 * @param pHlp The helper structure to delete.
922 */
923static void MachineDebuggerInfoDelete(PMACHINEDEBUGGERINOFHLP pHlp)
924{
925 RTMemFree(pHlp->pszBuf);
926 pHlp->pszBuf = NULL;
927}
928
929HRESULT MachineDebugger::info(const com::Utf8Str &aName, const com::Utf8Str &aArgs, com::Utf8Str &aInfo)
930{
931 LogFlowThisFunc(("\n"));
932
933 /*
934 * Do the autocaller and lock bits.
935 */
936 AutoCaller autoCaller(this);
937 HRESULT hrc = autoCaller.rc();
938 if (SUCCEEDED(hrc))
939 {
940 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
941 Console::SafeVMPtr ptrVM(mParent);
942 hrc = ptrVM.rc();
943 if (SUCCEEDED(hrc))
944 {
945 /*
946 * Create a helper and call DBGFR3Info.
947 */
948 MACHINEDEBUGGERINOFHLP Hlp;
949 MachineDebuggerInfoInit(&Hlp);
950 int vrc = DBGFR3Info(ptrVM.rawUVM(), aName.c_str(), aArgs.c_str(), &Hlp.Core);
951 if (RT_SUCCESS(vrc))
952 {
953 if (!Hlp.fOutOfMemory)
954 {
955 /*
956 * Convert the info string, watching out for allocation errors.
957 */
958 try
959 {
960 Bstr bstrInfo(Hlp.pszBuf);
961 aInfo = bstrInfo;
962 }
963 catch (std::bad_alloc)
964 {
965 hrc = E_OUTOFMEMORY;
966 }
967 }
968 else
969 hrc = E_OUTOFMEMORY;
970 }
971 else
972 hrc = setError(VBOX_E_VM_ERROR, tr("DBGFR3Info failed with %Rrc"), vrc);
973 MachineDebuggerInfoDelete(&Hlp);
974 }
975 }
976 return hrc;
977}
978
979HRESULT MachineDebugger::injectNMI()
980{
981 LogFlowThisFunc(("\n"));
982
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 = DBGFR3InjectNMI(ptrVM.rawUVM(), 0);
989 if (RT_SUCCESS(vrc))
990 hrc = S_OK;
991 else
992 hrc = setError(E_FAIL, tr("DBGFR3InjectNMI failed with %Rrc"), vrc);
993 }
994 return hrc;
995}
996
997HRESULT MachineDebugger::modifyLogFlags(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 = DBGFR3LogModifyFlags(ptrVM.rawUVM(), aSettings.c_str());
1006 if (RT_SUCCESS(vrc))
1007 hrc = S_OK;
1008 else
1009 hrc = setError(E_FAIL, tr("DBGFR3LogModifyFlags failed with %Rrc"), vrc);
1010 }
1011 return hrc;
1012}
1013
1014HRESULT MachineDebugger::modifyLogGroups(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 = DBGFR3LogModifyGroups(ptrVM.rawUVM(), aSettings.c_str());
1023 if (RT_SUCCESS(vrc))
1024 hrc = S_OK;
1025 else
1026 hrc = setError(E_FAIL, tr("DBGFR3LogModifyGroups failed with %Rrc"), vrc);
1027 }
1028 return hrc;
1029}
1030
1031HRESULT MachineDebugger::modifyLogDestinations(const com::Utf8Str &aSettings)
1032{
1033 LogFlowThisFunc(("aSettings=%s\n", aSettings.c_str()));
1034 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1035 Console::SafeVMPtr ptrVM(mParent);
1036 HRESULT hrc = ptrVM.rc();
1037 if (SUCCEEDED(hrc))
1038 {
1039 int vrc = DBGFR3LogModifyDestinations(ptrVM.rawUVM(), aSettings.c_str());
1040 if (RT_SUCCESS(vrc))
1041 hrc = S_OK;
1042 else
1043 hrc = setError(E_FAIL, tr("DBGFR3LogModifyDestinations failed with %Rrc"), vrc);
1044 }
1045 return hrc;
1046}
1047
1048HRESULT MachineDebugger::readPhysicalMemory(LONG64 aAddress, ULONG aSize, std::vector<BYTE> &aBytes)
1049{
1050 ReturnComNotImplemented();
1051}
1052
1053HRESULT MachineDebugger::writePhysicalMemory(LONG64 aAddress, ULONG aSize, const std::vector<BYTE> &aBytes)
1054{
1055 ReturnComNotImplemented();
1056}
1057
1058HRESULT MachineDebugger::readVirtualMemory(ULONG aCpuId, LONG64 aAddress, ULONG aSize, std::vector<BYTE> &aBytes)
1059{
1060 ReturnComNotImplemented();
1061}
1062
1063HRESULT MachineDebugger::writeVirtualMemory(ULONG aCpuId, LONG64 aAddress, ULONG aSize, const std::vector<BYTE> &aBytes)
1064{
1065 ReturnComNotImplemented();
1066}
1067
1068HRESULT MachineDebugger::loadPlugIn(const com::Utf8Str &aName, com::Utf8Str &aPlugInName)
1069{
1070 /*
1071 * Lock the debugger and get the VM pointer
1072 */
1073 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1074 Console::SafeVMPtr ptrVM(mParent);
1075 HRESULT hrc = ptrVM.rc();
1076 if (SUCCEEDED(hrc))
1077 {
1078 /*
1079 * Do the job and try convert the name.
1080 */
1081 if (aName.equals("all"))
1082 {
1083 DBGFR3PlugInLoadAll(ptrVM.rawUVM());
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 {
1096 RTERRINFOSTATIC ErrInfo;
1097 char szName[80];
1098 int vrc = DBGFR3PlugInLoad(ptrVM.rawUVM(), aName.c_str(), szName, sizeof(szName), RTErrInfoInitStatic(&ErrInfo));
1099 if (RT_SUCCESS(vrc))
1100 {
1101 try
1102 {
1103 aPlugInName = "all";
1104 hrc = S_OK;
1105 }
1106 catch (std::bad_alloc)
1107 {
1108 hrc = E_OUTOFMEMORY;
1109 }
1110 }
1111 else
1112 hrc = setErrorVrc(vrc, "%s", ErrInfo.szMsg);
1113 }
1114 }
1115 return hrc;
1116
1117}
1118
1119HRESULT MachineDebugger::unloadPlugIn(const com::Utf8Str &aName)
1120{
1121 /*
1122 * Lock the debugger and get the VM pointer
1123 */
1124 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1125 Console::SafeVMPtr ptrVM(mParent);
1126 HRESULT hrc = ptrVM.rc();
1127 if (SUCCEEDED(hrc))
1128 {
1129 /*
1130 * Do the job and try convert the name.
1131 */
1132 if (aName.equals("all"))
1133 {
1134 DBGFR3PlugInUnloadAll(ptrVM.rawUVM());
1135 hrc = S_OK;
1136 }
1137 else
1138 {
1139 int vrc = DBGFR3PlugInUnload(ptrVM.rawUVM(), aName.c_str());
1140 if (RT_SUCCESS(vrc))
1141 hrc = S_OK;
1142 else if (vrc == VERR_NOT_FOUND)
1143 hrc = setErrorBoth(E_FAIL, vrc, "Plug-in '%s' was not found", aName.c_str());
1144 else
1145 hrc = setErrorVrc(vrc, "Error unloading '%s': %Rrc", aName.c_str(), vrc);
1146 }
1147 }
1148 return hrc;
1149
1150}
1151
1152HRESULT MachineDebugger::detectOS(com::Utf8Str &aOs)
1153{
1154 LogFlowThisFunc(("\n"));
1155
1156 /*
1157 * Lock the debugger and get the VM pointer
1158 */
1159 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1160 Console::SafeVMPtr ptrVM(mParent);
1161 HRESULT hrc = ptrVM.rc();
1162 if (SUCCEEDED(hrc))
1163 {
1164 /*
1165 * Do the job.
1166 */
1167 char szName[64];
1168 int vrc = DBGFR3OSDetect(ptrVM.rawUVM(), szName, sizeof(szName));
1169 if (RT_SUCCESS(vrc) && vrc != VINF_DBGF_OS_NOT_DETCTED)
1170 {
1171 try
1172 {
1173 aOs = szName;
1174 }
1175 catch (std::bad_alloc)
1176 {
1177 hrc = E_OUTOFMEMORY;
1178 }
1179 }
1180 else
1181 hrc = setError(VBOX_E_VM_ERROR, tr("DBGFR3OSDetect failed with %Rrc"), vrc);
1182 }
1183 return hrc;
1184}
1185
1186HRESULT MachineDebugger::queryOSKernelLog(ULONG aMaxMessages, com::Utf8Str &aDmesg)
1187{
1188 /*
1189 * Lock the debugger and get the VM pointer
1190 */
1191 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1192 Console::SafeVMPtr ptrVM(mParent);
1193 HRESULT hrc = ptrVM.rc();
1194 if (SUCCEEDED(hrc))
1195 {
1196 PDBGFOSIDMESG pDmesg = (PDBGFOSIDMESG)DBGFR3OSQueryInterface(ptrVM.rawUVM(), DBGFOSINTERFACE_DMESG);
1197 if (pDmesg)
1198 {
1199 size_t cbActual;
1200 size_t cbBuf = _512K;
1201 int vrc = aDmesg.reserveNoThrow(cbBuf);
1202 if (RT_SUCCESS(vrc))
1203 {
1204 uint32_t cMessages = aMaxMessages == 0 ? UINT32_MAX : aMaxMessages;
1205 vrc = pDmesg->pfnQueryKernelLog(pDmesg, ptrVM.rawUVM(), 0 /*fFlags*/, cMessages,
1206 aDmesg.mutableRaw(), cbBuf, &cbActual);
1207
1208 uint32_t cTries = 10;
1209 while (vrc == VERR_BUFFER_OVERFLOW && cbBuf < 16*_1M && cTries-- > 0)
1210 {
1211 cbBuf = RT_ALIGN_Z(cbActual + _4K, _4K);
1212 vrc = aDmesg.reserveNoThrow(cbBuf);
1213 if (RT_SUCCESS(vrc))
1214 vrc = pDmesg->pfnQueryKernelLog(pDmesg, ptrVM.rawUVM(), 0 /*fFlags*/, cMessages,
1215 aDmesg.mutableRaw(), cbBuf, &cbActual);
1216 }
1217 if (RT_SUCCESS(vrc))
1218 aDmesg.jolt();
1219 else if (vrc == VERR_BUFFER_OVERFLOW)
1220 hrc = setError(E_FAIL, "Too much log available, must use the maxMessages parameter to restrict.");
1221 else
1222 hrc = setErrorVrc(vrc);
1223 }
1224 else
1225 hrc = setErrorBoth(E_OUTOFMEMORY, vrc);
1226 }
1227 else
1228 hrc = setError(E_FAIL, "The dmesg interface isn't implemented by guest OS digger, or detectOS() has not been called.");
1229 }
1230 return hrc;
1231}
1232
1233/**
1234 * Formats a register value.
1235 *
1236 * This is used by both register getter methods.
1237 *
1238 * @returns
1239 * @param a_pbstr The output Bstr variable.
1240 * @param a_pValue The value to format.
1241 * @param a_enmType The type of the value.
1242 */
1243DECLINLINE(HRESULT) formatRegisterValue(Bstr *a_pbstr, PCDBGFREGVAL a_pValue, DBGFREGVALTYPE a_enmType)
1244{
1245 char szHex[160];
1246 ssize_t cch = DBGFR3RegFormatValue(szHex, sizeof(szHex), a_pValue, a_enmType, true /*fSpecial*/);
1247 if (RT_UNLIKELY(cch <= 0))
1248 return E_UNEXPECTED;
1249 *a_pbstr = szHex;
1250 return S_OK;
1251}
1252
1253HRESULT MachineDebugger::getRegister(ULONG aCpuId, const com::Utf8Str &aName, com::Utf8Str &aValue)
1254{
1255 /*
1256 * The prologue.
1257 */
1258 LogFlowThisFunc(("\n"));
1259 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1260 Console::SafeVMPtr ptrVM(mParent);
1261 HRESULT hrc = ptrVM.rc();
1262 if (SUCCEEDED(hrc))
1263 {
1264 /*
1265 * Real work.
1266 */
1267 DBGFREGVAL Value;
1268 DBGFREGVALTYPE enmType;
1269 int vrc = DBGFR3RegNmQuery(ptrVM.rawUVM(), aCpuId, aName.c_str(), &Value, &enmType);
1270 if (RT_SUCCESS(vrc))
1271 {
1272 try
1273 {
1274 Bstr bstrValue;
1275 hrc = formatRegisterValue(&bstrValue, &Value, enmType);
1276 if (SUCCEEDED(hrc))
1277 aValue = Utf8Str(bstrValue);
1278 }
1279 catch (std::bad_alloc)
1280 {
1281 hrc = E_OUTOFMEMORY;
1282 }
1283 }
1284 else if (vrc == VERR_DBGF_REGISTER_NOT_FOUND)
1285 hrc = setError(E_FAIL, tr("Register '%s' was not found"), aName.c_str());
1286 else if (vrc == VERR_INVALID_CPU_ID)
1287 hrc = setError(E_FAIL, tr("Invalid CPU ID: %u"), aCpuId);
1288 else
1289 hrc = setError(VBOX_E_VM_ERROR,
1290 tr("DBGFR3RegNmQuery failed with rc=%Rrc querying register '%s' with default cpu set to %u"),
1291 vrc, aName.c_str(), aCpuId);
1292 }
1293
1294 return hrc;
1295}
1296
1297HRESULT MachineDebugger::getRegisters(ULONG aCpuId, std::vector<com::Utf8Str> &aNames, std::vector<com::Utf8Str> &aValues)
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 size_t cRegs;
1312 int vrc = DBGFR3RegNmQueryAllCount(ptrVM.rawUVM(), &cRegs);
1313 if (RT_SUCCESS(vrc))
1314 {
1315 PDBGFREGENTRYNM paRegs = (PDBGFREGENTRYNM)RTMemAllocZ(sizeof(paRegs[0]) * cRegs);
1316 if (paRegs)
1317 {
1318 vrc = DBGFR3RegNmQueryAll(ptrVM.rawUVM(), paRegs, cRegs);
1319 if (RT_SUCCESS(vrc))
1320 {
1321 try
1322 {
1323 aValues.resize(cRegs);
1324 aNames.resize(cRegs);
1325 for (uint32_t iReg = 0; iReg < cRegs; iReg++)
1326 {
1327 char szHex[160];
1328 szHex[159] = szHex[0] = '\0';
1329 ssize_t cch = DBGFR3RegFormatValue(szHex, sizeof(szHex), &paRegs[iReg].Val,
1330 paRegs[iReg].enmType, true /*fSpecial*/);
1331 Assert(cch > 0);
1332 aNames[iReg] = Utf8Str(paRegs[iReg].pszName);
1333 aValues[iReg] = Utf8Str(szHex);
1334 }
1335 }
1336 catch (std::bad_alloc)
1337 {
1338 hrc = E_OUTOFMEMORY;
1339 }
1340 }
1341 else
1342 hrc = setError(E_FAIL, tr("DBGFR3RegNmQueryAll failed with %Rrc"), vrc);
1343
1344 RTMemFree(paRegs);
1345 }
1346 else
1347 hrc = E_OUTOFMEMORY;
1348 }
1349 else
1350 hrc = setError(E_FAIL, tr("DBGFR3RegNmQueryAllCount failed with %Rrc"), vrc);
1351 }
1352 return hrc;
1353}
1354
1355HRESULT MachineDebugger::setRegister(ULONG aCpuId, const com::Utf8Str &aName, const com::Utf8Str &aValue)
1356{
1357 ReturnComNotImplemented();
1358}
1359
1360HRESULT MachineDebugger::setRegisters(ULONG aCpuId, const std::vector<com::Utf8Str> &aNames,
1361 const std::vector<com::Utf8Str> &aValues)
1362{
1363 ReturnComNotImplemented();
1364}
1365
1366HRESULT MachineDebugger::dumpGuestStack(ULONG aCpuId, com::Utf8Str &aStack)
1367{
1368 ReturnComNotImplemented();
1369}
1370
1371/**
1372 * Resets VM statistics.
1373 *
1374 * @returns COM status code.
1375 * @param aPattern The selection pattern. A bit similar to filename globbing.
1376 */
1377HRESULT MachineDebugger::resetStats(const com::Utf8Str &aPattern)
1378{
1379 Console::SafeVMPtrQuiet ptrVM(mParent);
1380
1381 if (!ptrVM.isOk())
1382 return setError(VBOX_E_INVALID_VM_STATE, "Machine is not running");
1383
1384 STAMR3Reset(ptrVM.rawUVM(), aPattern.c_str());
1385
1386 return S_OK;
1387}
1388
1389/**
1390 * Dumps VM statistics to the log.
1391 *
1392 * @returns COM status code.
1393 * @param aPattern The selection pattern. A bit similar to filename globbing.
1394 */
1395HRESULT MachineDebugger::dumpStats(const com::Utf8Str &aPattern)
1396{
1397 Console::SafeVMPtrQuiet ptrVM(mParent);
1398
1399 if (!ptrVM.isOk())
1400 return setError(VBOX_E_INVALID_VM_STATE, "Machine is not running");
1401
1402 STAMR3Dump(ptrVM.rawUVM(), aPattern.c_str());
1403
1404 return S_OK;
1405}
1406
1407/**
1408 * Get the VM statistics in an XML format.
1409 *
1410 * @returns COM status code.
1411 * @param aPattern The selection pattern. A bit similar to filename globbing.
1412 * @param aWithDescriptions Whether to include the descriptions.
1413 * @param aStats The XML document containing the statistics.
1414 */
1415HRESULT MachineDebugger::getStats(const com::Utf8Str &aPattern, BOOL aWithDescriptions, com::Utf8Str &aStats)
1416{
1417 Console::SafeVMPtrQuiet ptrVM (mParent);
1418
1419 if (!ptrVM.isOk())
1420 return setError(VBOX_E_INVALID_VM_STATE, "Machine is not running");
1421
1422 char *pszSnapshot;
1423 int vrc = STAMR3Snapshot(ptrVM.rawUVM(), aPattern.c_str(), &pszSnapshot, NULL,
1424 !!aWithDescriptions);
1425 if (RT_FAILURE(vrc))
1426 return vrc == VERR_NO_MEMORY ? E_OUTOFMEMORY : E_FAIL;
1427
1428 /** @todo this is horribly inefficient! And it's kinda difficult to tell whether it failed...
1429 * Must use UTF-8 or ASCII here and completely avoid these two extra copy operations.
1430 * Until that's done, this method is kind of useless for debugger statistics GUI because
1431 * of the amount statistics in a debug build. */
1432 aStats = Utf8Str(pszSnapshot);
1433 STAMR3SnapshotFree(ptrVM.rawUVM(), pszSnapshot);
1434
1435 return S_OK;
1436}
1437
1438
1439// public methods only for internal purposes
1440/////////////////////////////////////////////////////////////////////////////
1441
1442void MachineDebugger::i_flushQueuedSettings()
1443{
1444 mFlushMode = true;
1445 if (mSingleStepQueued != ~0)
1446 {
1447 COMSETTER(SingleStep)(mSingleStepQueued);
1448 mSingleStepQueued = ~0;
1449 }
1450 for (unsigned i = 0; i < EMEXECPOLICY_END; i++)
1451 if (maiQueuedEmExecPolicyParams[i] != UINT8_MAX)
1452 {
1453 i_setEmExecPolicyProperty((EMEXECPOLICY)i, RT_BOOL(maiQueuedEmExecPolicyParams[i]));
1454 maiQueuedEmExecPolicyParams[i] = UINT8_MAX;
1455 }
1456 if (mPatmEnabledQueued != ~0)
1457 {
1458 COMSETTER(PATMEnabled)(mPatmEnabledQueued);
1459 mPatmEnabledQueued = ~0;
1460 }
1461 if (mCsamEnabledQueued != ~0)
1462 {
1463 COMSETTER(CSAMEnabled)(mCsamEnabledQueued);
1464 mCsamEnabledQueued = ~0;
1465 }
1466 if (mLogEnabledQueued != ~0)
1467 {
1468 COMSETTER(LogEnabled)(mLogEnabledQueued);
1469 mLogEnabledQueued = ~0;
1470 }
1471 if (mVirtualTimeRateQueued != ~(uint32_t)0)
1472 {
1473 COMSETTER(VirtualTimeRate)(mVirtualTimeRateQueued);
1474 mVirtualTimeRateQueued = ~0;
1475 }
1476 mFlushMode = false;
1477}
1478
1479// private methods
1480/////////////////////////////////////////////////////////////////////////////
1481
1482bool MachineDebugger::i_queueSettings() const
1483{
1484 if (!mFlushMode)
1485 {
1486 // check if the machine is running
1487 MachineState_T machineState;
1488 mParent->COMGETTER(State)(&machineState);
1489 switch (machineState)
1490 {
1491 // queue the request
1492 default:
1493 return true;
1494
1495 case MachineState_Running:
1496 case MachineState_Paused:
1497 case MachineState_Stuck:
1498 case MachineState_LiveSnapshotting:
1499 case MachineState_Teleporting:
1500 break;
1501 }
1502 }
1503 return false;
1504}
1505/* 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