VirtualBox

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

Last change on this file since 44362 was 44362, checked in by vboxsync, 12 years ago

PATM: Changed two Main APIs to use PUVM instead of PVM (one of them directly accessed it). Lot's of function scope cleanups.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette