VirtualBox

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

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

VMM,Main,Debugger,REM: VM API cleanup, prefering PUVM over PVM so we can use real reference counting and not have the memory backing the VM structure disappear on us.

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