VirtualBox

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

Last change on this file since 39850 was 39712, checked in by vboxsync, 13 years ago

Main: Some IMachineDebugger cleanups.

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