VirtualBox

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

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

PGM,SSM,STAM: Changed APIs used by Main to take PUVM instead of PVM as the VM handle.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.4 KB
Line 
1/* $Id: MachineDebuggerImpl.cpp 44347 2013-01-24 00:27:56Z 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 ptrVM(mParent);
757
758 if (ptrVM.isOk())
759 {
760 uint32_t cr4;
761 int rc = DBGFR3RegCpuQueryU32(ptrVM.raw(), 0 /*idCpu*/, DBGFREG_CR4, &cr4); AssertRC(rc);
762 *aEnabled = RT_BOOL(cr4 & X86_CR4_PAE);
763 }
764 else
765 *aEnabled = false;
766
767 return S_OK;
768}
769
770/**
771 * Returns the current virtual time rate.
772 *
773 * @returns COM status code.
774 * @param a_puPct Where to store the rate.
775 */
776STDMETHODIMP MachineDebugger::COMGETTER(VirtualTimeRate)(ULONG *a_puPct)
777{
778 CheckComArgOutPointerValid(a_puPct);
779
780 AutoCaller autoCaller(this);
781 HRESULT hrc = autoCaller.rc();
782 if (SUCCEEDED(hrc))
783 {
784 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
785
786 Console::SafeVMPtr ptrVM(mParent);
787 hrc = ptrVM.rc();
788 if (SUCCEEDED(hrc))
789 *a_puPct = TMR3GetWarpDrive(ptrVM.rawUVM());
790 }
791
792 return hrc;
793}
794
795/**
796 * Returns the current virtual time rate.
797 *
798 * @returns COM status code.
799 * @param aPct Where to store the rate.
800 */
801STDMETHODIMP MachineDebugger::COMSETTER(VirtualTimeRate)(ULONG a_uPct)
802{
803 if (a_uPct < 2 || a_uPct > 20000)
804 return setError(E_INVALIDARG, tr("%u is out of range [2..20000]"), a_uPct);
805
806 AutoCaller autoCaller(this);
807 HRESULT hrc = autoCaller.rc();
808 if (SUCCEEDED(hrc))
809 {
810 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
811 if (queueSettings())
812 mVirtualTimeRateQueued = a_uPct;
813 else
814 {
815 Console::SafeVMPtr ptrVM(mParent);
816 hrc = ptrVM.rc();
817 if (SUCCEEDED(hrc))
818 {
819 int vrc = TMR3SetWarpDrive(ptrVM.rawUVM(), a_uPct);
820 if (RT_FAILURE(vrc))
821 hrc = setError(VBOX_E_VM_ERROR, tr("TMR3SetWarpDrive(, %u) failed with rc=%Rrc"), a_uPct, vrc);
822 }
823 }
824 }
825
826 return hrc;
827}
828
829/**
830 * Hack for getting the user mode VM handle (UVM).
831 *
832 * This is only temporary (promise) while prototyping the debugger.
833 *
834 * @returns COM status code
835 * @param a_u64Vm Where to store the vm handle. Since there is no
836 * uintptr_t in COM, we're using the max integer.
837 * (No, ULONG is not pointer sized!)
838 * @remarks The returned handle must be passed to VMR3ReleaseUVM()!
839 * @remarks Prior to 4.3 this returned PVM.
840 */
841STDMETHODIMP MachineDebugger::COMGETTER(VM)(LONG64 *a_i64Vm)
842{
843 CheckComArgOutPointerValid(a_i64Vm);
844
845 AutoCaller autoCaller(this);
846 HRESULT hrc = autoCaller.rc();
847 if (SUCCEEDED(hrc))
848 {
849 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
850
851 Console::SafeVMPtr ptrVM(mParent);
852 hrc = ptrVM.rc();
853 if (SUCCEEDED(hrc))
854 {
855 VMR3RetainUVM(ptrVM.rawUVM());
856 *a_i64Vm = (intptr_t)ptrVM.rawUVM();
857 }
858
859 /*
860 * Note! pVM protection provided by SafeVMPtr is no long effective
861 * after we return from this method.
862 */
863 }
864
865 return hrc;
866}
867
868// IMachineDebugger methods
869/////////////////////////////////////////////////////////////////////////////
870
871STDMETHODIMP MachineDebugger::DumpGuestCore(IN_BSTR a_bstrFilename, IN_BSTR a_bstrCompression)
872{
873 CheckComArgStrNotEmptyOrNull(a_bstrFilename);
874 Utf8Str strFilename(a_bstrFilename);
875 if (a_bstrCompression && *a_bstrCompression)
876 return setError(E_INVALIDARG, tr("The compression parameter must be empty"));
877
878 AutoCaller autoCaller(this);
879 HRESULT hrc = autoCaller.rc();
880 if (SUCCEEDED(hrc))
881 {
882 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
883 Console::SafeVMPtr ptrVM(mParent);
884 hrc = ptrVM.rc();
885 if (SUCCEEDED(hrc))
886 {
887 int vrc = DBGFR3CoreWrite(ptrVM, strFilename.c_str(), false /*fReplaceFile*/);
888 if (RT_SUCCESS(vrc))
889 hrc = S_OK;
890 else
891 hrc = setError(E_FAIL, tr("DBGFR3CoreWrite failed with %Rrc"), vrc);
892 }
893 }
894
895 return hrc;
896}
897
898STDMETHODIMP MachineDebugger::DumpHostProcessCore(IN_BSTR a_bstrFilename, IN_BSTR a_bstrCompression)
899{
900 ReturnComNotImplemented();
901}
902
903/**
904 * Debug info string buffer formatter.
905 */
906typedef struct MACHINEDEBUGGERINOFHLP
907{
908 /** The core info helper structure. */
909 DBGFINFOHLP Core;
910 /** Pointer to the buffer. */
911 char *pszBuf;
912 /** The size of the buffer. */
913 size_t cbBuf;
914 /** The offset into the buffer */
915 size_t offBuf;
916 /** Indicates an out-of-memory condition. */
917 bool fOutOfMemory;
918} MACHINEDEBUGGERINOFHLP;
919/** Pointer to a Debug info string buffer formatter. */
920typedef MACHINEDEBUGGERINOFHLP *PMACHINEDEBUGGERINOFHLP;
921
922
923/**
924 * @callback_method_impl{FNRTSTROUTPUT}
925 */
926static DECLCALLBACK(size_t) MachineDebuggerInfoOutput(void *pvArg, const char *pachChars, size_t cbChars)
927{
928 PMACHINEDEBUGGERINOFHLP pHlp = (PMACHINEDEBUGGERINOFHLP)pvArg;
929
930 /*
931 * Grow the buffer if required.
932 */
933 size_t const cbRequired = cbChars + pHlp->offBuf + 1;
934 if (cbRequired > pHlp->cbBuf)
935 {
936 if (RT_UNLIKELY(pHlp->fOutOfMemory))
937 return 0;
938
939 size_t cbBufNew = pHlp->cbBuf * 2;
940 if (cbRequired > cbBufNew)
941 cbBufNew = RT_ALIGN_Z(cbRequired, 256);
942 void *pvBufNew = RTMemRealloc(pHlp->pszBuf, cbBufNew);
943 if (RT_UNLIKELY(!pvBufNew))
944 {
945 pHlp->fOutOfMemory = true;
946 RTMemFree(pHlp->pszBuf);
947 pHlp->pszBuf = NULL;
948 pHlp->cbBuf = 0;
949 pHlp->offBuf = 0;
950 return 0;
951 }
952
953 pHlp->pszBuf = (char *)pvBufNew;
954 pHlp->cbBuf = cbBufNew;
955 }
956
957 /*
958 * Copy the bytes into the buffer and terminate it.
959 */
960 memcpy(&pHlp->pszBuf[pHlp->offBuf], pachChars, cbChars);
961 pHlp->offBuf += cbChars;
962 pHlp->pszBuf[pHlp->offBuf] = '\0';
963 Assert(pHlp->offBuf < pHlp->cbBuf);
964 return cbChars;
965}
966
967/**
968 * @interface_method_impl{DBGFINFOHLP, pfnPrintfV}
969 */
970static DECLCALLBACK(void) MachineDebuggerInfoPrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list va)
971{
972 RTStrFormatV(MachineDebuggerInfoOutput, (void *)pHlp, NULL, NULL, pszFormat, va);
973}
974
975/**
976 * @interface_method_impl{DBGFINFOHLP, pfnPrintf}
977 */
978static DECLCALLBACK(void) MachineDebuggerInfoPrintf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
979{
980 va_list va;
981 va_start(va, pszFormat);
982 MachineDebuggerInfoPrintfV(pHlp, pszFormat, va);
983 va_end(va);
984}
985
986/**
987 * Initializes the debug info string buffer formatter
988 *
989 * @param pHlp The help structure to init.
990 */
991static void MachineDebuggerInfoInit(PMACHINEDEBUGGERINOFHLP pHlp)
992{
993 pHlp->Core.pfnPrintf = MachineDebuggerInfoPrintf;
994 pHlp->Core.pfnPrintfV = MachineDebuggerInfoPrintfV;
995 pHlp->pszBuf = NULL;
996 pHlp->cbBuf = 0;
997 pHlp->offBuf = 0;
998 pHlp->fOutOfMemory = false;
999}
1000
1001/**
1002 * Deletes the debug info string buffer formatter.
1003 * @param pHlp The helper structure to delete.
1004 */
1005static void MachineDebuggerInfoDelete(PMACHINEDEBUGGERINOFHLP pHlp)
1006{
1007 RTMemFree(pHlp->pszBuf);
1008 pHlp->pszBuf = NULL;
1009}
1010
1011STDMETHODIMP MachineDebugger::Info(IN_BSTR a_bstrName, IN_BSTR a_bstrArgs, BSTR *a_pbstrInfo)
1012{
1013 LogFlowThisFunc(("\n"));
1014
1015 /*
1016 * Validate and convert input.
1017 */
1018 CheckComArgStrNotEmptyOrNull(a_bstrName);
1019 Utf8Str strName, strArgs;
1020 try
1021 {
1022 strName = a_bstrName;
1023 strArgs = a_bstrArgs;
1024 }
1025 catch (std::bad_alloc)
1026 {
1027 return E_OUTOFMEMORY;
1028 }
1029
1030 /*
1031 * Do the autocaller and lock bits.
1032 */
1033 AutoCaller autoCaller(this);
1034 HRESULT hrc = autoCaller.rc();
1035 if (SUCCEEDED(hrc))
1036 {
1037 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1038 Console::SafeVMPtr ptrVM(mParent);
1039 hrc = ptrVM.rc();
1040 if (SUCCEEDED(hrc))
1041 {
1042 /*
1043 * Create a helper and call DBGFR3Info.
1044 */
1045 MACHINEDEBUGGERINOFHLP Hlp;
1046 MachineDebuggerInfoInit(&Hlp);
1047 int vrc = DBGFR3Info(ptrVM.raw(), strName.c_str(), strArgs.c_str(), &Hlp.Core);
1048 if (RT_SUCCESS(vrc))
1049 {
1050 if (!Hlp.fOutOfMemory)
1051 {
1052 /*
1053 * Convert the info string, watching out for allocation errors.
1054 */
1055 try
1056 {
1057 Bstr bstrInfo(Hlp.pszBuf);
1058 bstrInfo.detachTo(a_pbstrInfo);
1059 }
1060 catch (std::bad_alloc)
1061 {
1062 hrc = E_OUTOFMEMORY;
1063 }
1064 }
1065 else
1066 hrc = E_OUTOFMEMORY;
1067 }
1068 else
1069 hrc = setError(VBOX_E_VM_ERROR, tr("DBGFR3Info failed with %Rrc"), vrc);
1070 MachineDebuggerInfoDelete(&Hlp);
1071 }
1072 }
1073 return hrc;
1074}
1075
1076STDMETHODIMP MachineDebugger::InjectNMI()
1077{
1078 LogFlowThisFunc(("\n"));
1079
1080 AutoCaller autoCaller(this);
1081 HRESULT hrc = autoCaller.rc();
1082 if (SUCCEEDED(hrc))
1083 {
1084 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1085 Console::SafeVMPtr ptrVM(mParent);
1086 hrc = ptrVM.rc();
1087 if (SUCCEEDED(hrc))
1088 {
1089 int vrc = HMR3InjectNMI(ptrVM);
1090 if (RT_SUCCESS(vrc))
1091 hrc = S_OK;
1092 else
1093 hrc = setError(E_FAIL, tr("HMR3InjectNMI failed with %Rrc"), vrc);
1094 }
1095 }
1096 return hrc;
1097}
1098
1099STDMETHODIMP MachineDebugger::ModifyLogFlags(IN_BSTR a_bstrSettings)
1100{
1101 CheckComArgStrNotEmptyOrNull(a_bstrSettings);
1102 Utf8Str strSettings(a_bstrSettings);
1103
1104 LogFlowThisFunc(("a_bstrSettings=%s\n", strSettings.c_str()));
1105 AutoCaller autoCaller(this);
1106 HRESULT hrc = autoCaller.rc();
1107 if (SUCCEEDED(hrc))
1108 {
1109 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1110 Console::SafeVMPtr ptrVM(mParent);
1111 hrc = ptrVM.rc();
1112 if (SUCCEEDED(hrc))
1113 {
1114 int vrc = DBGFR3LogModifyFlags(ptrVM, strSettings.c_str());
1115 if (RT_SUCCESS(vrc))
1116 hrc = S_OK;
1117 else
1118 hrc = setError(E_FAIL, tr("DBGFR3LogModifyFlags failed with %Rrc"), vrc);
1119 }
1120 }
1121 return hrc;
1122}
1123
1124STDMETHODIMP MachineDebugger::ModifyLogGroups(IN_BSTR a_bstrSettings)
1125{
1126 CheckComArgStrNotEmptyOrNull(a_bstrSettings);
1127 Utf8Str strSettings(a_bstrSettings);
1128
1129 LogFlowThisFunc(("a_bstrSettings=%s\n", strSettings.c_str()));
1130 AutoCaller autoCaller(this);
1131 HRESULT hrc = autoCaller.rc();
1132 if (SUCCEEDED(hrc))
1133 {
1134 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1135 Console::SafeVMPtr ptrVM(mParent);
1136 hrc = ptrVM.rc();
1137 if (SUCCEEDED(hrc))
1138 {
1139 int vrc = DBGFR3LogModifyGroups(ptrVM, strSettings.c_str());
1140 if (RT_SUCCESS(vrc))
1141 hrc = S_OK;
1142 else
1143 hrc = setError(E_FAIL, tr("DBGFR3LogModifyGroups failed with %Rrc"), vrc);
1144 }
1145 }
1146 return hrc;
1147}
1148
1149STDMETHODIMP MachineDebugger::ModifyLogDestinations(IN_BSTR a_bstrSettings)
1150{
1151 CheckComArgStrNotEmptyOrNull(a_bstrSettings);
1152 Utf8Str strSettings(a_bstrSettings);
1153
1154 LogFlowThisFunc(("a_bstrSettings=%s\n", strSettings.c_str()));
1155 AutoCaller autoCaller(this);
1156 HRESULT hrc = autoCaller.rc();
1157 if (SUCCEEDED(hrc))
1158 {
1159 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1160 Console::SafeVMPtr ptrVM(mParent);
1161 hrc = ptrVM.rc();
1162 if (SUCCEEDED(hrc))
1163 {
1164 int vrc = DBGFR3LogModifyDestinations(ptrVM, strSettings.c_str());
1165 if (RT_SUCCESS(vrc))
1166 hrc = S_OK;
1167 else
1168 hrc = setError(E_FAIL, tr("DBGFR3LogModifyDestinations failed with %Rrc"), vrc);
1169 }
1170 }
1171 return hrc;
1172}
1173
1174STDMETHODIMP MachineDebugger::ReadPhysicalMemory(LONG64 a_Address, ULONG a_cbRead, ComSafeArrayOut(BYTE, a_abData))
1175{
1176 ReturnComNotImplemented();
1177}
1178
1179STDMETHODIMP MachineDebugger::WritePhysicalMemory(LONG64 a_Address, ULONG a_cbRead, ComSafeArrayIn(BYTE, a_abData))
1180{
1181 ReturnComNotImplemented();
1182}
1183
1184STDMETHODIMP MachineDebugger::ReadVirtualMemory(ULONG a_idCpu, LONG64 a_Address, ULONG a_cbRead, ComSafeArrayOut(BYTE, a_abData))
1185{
1186 ReturnComNotImplemented();
1187}
1188
1189STDMETHODIMP MachineDebugger::WriteVirtualMemory(ULONG a_idCpu, LONG64 a_Address, ULONG a_cbRead, ComSafeArrayIn(BYTE, a_abData))
1190{
1191 ReturnComNotImplemented();
1192}
1193
1194STDMETHODIMP MachineDebugger::DetectOS(BSTR *a_pbstrName)
1195{
1196 LogFlowThisFunc(("\n"));
1197 CheckComArgNotNull(a_pbstrName);
1198
1199 /*
1200 * Do the autocaller and lock bits.
1201 */
1202 AutoCaller autoCaller(this);
1203 HRESULT hrc = autoCaller.rc();
1204 if (SUCCEEDED(hrc))
1205 {
1206 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1207 Console::SafeVMPtr ptrVM(mParent);
1208 hrc = ptrVM.rc();
1209 if (SUCCEEDED(hrc))
1210 {
1211 /*
1212 * Do the job and try convert the name.
1213 */
1214/** @todo automatically load the DBGC plugins or this is a waste of time. */
1215 char szName[64];
1216 int vrc = DBGFR3OSDetect(ptrVM.raw(), szName, sizeof(szName));
1217 if (RT_SUCCESS(vrc) && vrc != VINF_DBGF_OS_NOT_DETCTED)
1218 {
1219 try
1220 {
1221 Bstr bstrName(szName);
1222 bstrName.detachTo(a_pbstrName);
1223 }
1224 catch (std::bad_alloc)
1225 {
1226 hrc = E_OUTOFMEMORY;
1227 }
1228 }
1229 else
1230 hrc = setError(VBOX_E_VM_ERROR, tr("DBGFR3OSDetect failed with %Rrc"), vrc);
1231 }
1232 }
1233 return hrc;
1234}
1235
1236/**
1237 * Formats a register value.
1238 *
1239 * This is used by both register getter methods.
1240 *
1241 * @returns
1242 * @param a_pbstr The output Bstr variable.
1243 * @param a_pValue The value to format.
1244 * @param a_enmType The type of the value.
1245 */
1246DECLINLINE(HRESULT) formatRegisterValue(Bstr *a_pbstr, PCDBGFREGVAL a_pValue, DBGFREGVALTYPE a_enmType)
1247{
1248 char szHex[160];
1249 ssize_t cch = DBGFR3RegFormatValue(szHex, sizeof(szHex), a_pValue, a_enmType, true /*fSpecial*/);
1250 if (RT_UNLIKELY(cch <= 0))
1251 return E_UNEXPECTED;
1252 *a_pbstr = szHex;
1253 return S_OK;
1254}
1255
1256STDMETHODIMP MachineDebugger::GetRegister(ULONG a_idCpu, IN_BSTR a_bstrName, BSTR *a_pbstrValue)
1257{
1258 /*
1259 * Validate and convert input.
1260 */
1261 CheckComArgStrNotEmptyOrNull(a_bstrName);
1262 CheckComArgNotNull(a_pbstrValue);
1263 Utf8Str strName;
1264 try
1265 {
1266 strName = a_bstrName;
1267 }
1268 catch (std::bad_alloc)
1269 {
1270 return E_OUTOFMEMORY;
1271 }
1272
1273 /*
1274 * The prologue.
1275 */
1276 LogFlowThisFunc(("\n"));
1277 AutoCaller autoCaller(this);
1278 HRESULT hrc = autoCaller.rc();
1279 if (SUCCEEDED(hrc))
1280 {
1281 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1282 Console::SafeVMPtr ptrVM(mParent);
1283 hrc = ptrVM.rc();
1284 if (SUCCEEDED(hrc))
1285 {
1286 /*
1287 * Real work.
1288 */
1289 DBGFREGVAL Value;
1290 DBGFREGVALTYPE enmType;
1291 int vrc = DBGFR3RegNmQuery(ptrVM.raw(), a_idCpu, strName.c_str(), &Value, &enmType);
1292 if (RT_SUCCESS(vrc))
1293 {
1294 try
1295 {
1296 Bstr bstrValue;
1297 hrc = formatRegisterValue(&bstrValue, &Value, enmType);
1298 if (SUCCEEDED(hrc))
1299 bstrValue.detachTo(a_pbstrValue);
1300 }
1301 catch (std::bad_alloc)
1302 {
1303 hrc = E_OUTOFMEMORY;
1304 }
1305 }
1306 else if (vrc == VERR_DBGF_REGISTER_NOT_FOUND)
1307 hrc = setError(E_FAIL, tr("Register '%s' was not found"), strName.c_str());
1308 else if (vrc == VERR_INVALID_CPU_ID)
1309 hrc = setError(E_FAIL, tr("Invalid CPU ID: %u"), a_idCpu);
1310 else
1311 hrc = setError(VBOX_E_VM_ERROR,
1312 tr("DBGFR3RegNmQuery failed with rc=%Rrc querying register '%s' with default cpu set to %u"),
1313 vrc, strName.c_str(), a_idCpu);
1314 }
1315 }
1316
1317 return hrc;
1318}
1319
1320STDMETHODIMP MachineDebugger::GetRegisters(ULONG a_idCpu, ComSafeArrayOut(BSTR, a_bstrNames), ComSafeArrayOut(BSTR, a_bstrValues))
1321{
1322 /*
1323 * The prologue.
1324 */
1325 LogFlowThisFunc(("\n"));
1326 AutoCaller autoCaller(this);
1327 HRESULT hrc = autoCaller.rc();
1328 if (SUCCEEDED(hrc))
1329 {
1330 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1331 Console::SafeVMPtr ptrVM(mParent);
1332 hrc = ptrVM.rc();
1333 if (SUCCEEDED(hrc))
1334 {
1335 /*
1336 * Real work.
1337 */
1338 size_t cRegs;
1339 int vrc = DBGFR3RegNmQueryAllCount(ptrVM.raw(), &cRegs);
1340 if (RT_SUCCESS(vrc))
1341 {
1342 PDBGFREGENTRYNM paRegs = (PDBGFREGENTRYNM)RTMemAllocZ(sizeof(paRegs[0]) * cRegs);
1343 if (paRegs)
1344 {
1345 vrc = DBGFR3RegNmQueryAll(ptrVM.raw(), paRegs, cRegs);
1346 if (RT_SUCCESS(vrc))
1347 {
1348 try
1349 {
1350 com::SafeArray<BSTR> abstrNames(cRegs);
1351 com::SafeArray<BSTR> abstrValues(cRegs);
1352
1353 for (uint32_t iReg = 0; iReg < cRegs; iReg++)
1354 {
1355 char szHex[128];
1356 Bstr bstrValue;
1357
1358 hrc = formatRegisterValue(&bstrValue, &paRegs[iReg].Val, paRegs[iReg].enmType);
1359 AssertComRC(hrc);
1360 bstrValue.detachTo(&abstrValues[iReg]);
1361
1362 Bstr bstrName(paRegs[iReg].pszName);
1363 bstrName.detachTo(&abstrNames[iReg]);
1364 }
1365
1366 abstrNames.detachTo(ComSafeArrayOutArg(a_bstrNames));
1367 abstrValues.detachTo(ComSafeArrayOutArg(a_bstrValues));
1368 }
1369 catch (std::bad_alloc)
1370 {
1371 hrc = E_OUTOFMEMORY;
1372 }
1373 }
1374 else
1375 hrc = setError(E_FAIL, tr("DBGFR3RegNmQueryAll failed with %Rrc"), vrc);
1376
1377 RTMemFree(paRegs);
1378 }
1379 else
1380 hrc = E_OUTOFMEMORY;
1381 }
1382 else
1383 hrc = setError(E_FAIL, tr("DBGFR3RegNmQueryAllCount failed with %Rrc"), vrc);
1384 }
1385 }
1386 return hrc;
1387}
1388
1389STDMETHODIMP MachineDebugger::SetRegister(ULONG a_idCpu, IN_BSTR a_bstrName, IN_BSTR a_bstrValue)
1390{
1391 ReturnComNotImplemented();
1392}
1393
1394STDMETHODIMP MachineDebugger::SetRegisters(ULONG a_idCpu, ComSafeArrayIn(IN_BSTR, a_bstrNames), ComSafeArrayIn(IN_BSTR, a_bstrValues))
1395{
1396 ReturnComNotImplemented();
1397}
1398
1399STDMETHODIMP MachineDebugger::DumpGuestStack(ULONG a_idCpu, BSTR *a_pbstrStack)
1400{
1401 ReturnComNotImplemented();
1402}
1403
1404/**
1405 * Resets VM statistics.
1406 *
1407 * @returns COM status code.
1408 * @param aPattern The selection pattern. A bit similar to filename globbing.
1409 */
1410STDMETHODIMP MachineDebugger::ResetStats(IN_BSTR aPattern)
1411{
1412 Console::SafeVMPtrQuiet ptrVM(mParent);
1413
1414 if (!ptrVM.isOk())
1415 return setError(VBOX_E_INVALID_VM_STATE, "Machine is not running");
1416
1417 STAMR3Reset(ptrVM.rawUVM(), Utf8Str(aPattern).c_str());
1418
1419 return S_OK;
1420}
1421
1422/**
1423 * Dumps VM statistics to the log.
1424 *
1425 * @returns COM status code.
1426 * @param aPattern The selection pattern. A bit similar to filename globbing.
1427 */
1428STDMETHODIMP MachineDebugger::DumpStats(IN_BSTR aPattern)
1429{
1430 Console::SafeVMPtrQuiet ptrVM(mParent);
1431
1432 if (!ptrVM.isOk())
1433 return setError(VBOX_E_INVALID_VM_STATE, "Machine is not running");
1434
1435 STAMR3Dump(ptrVM.rawUVM(), Utf8Str(aPattern).c_str());
1436
1437 return S_OK;
1438}
1439
1440/**
1441 * Get the VM statistics in an XML format.
1442 *
1443 * @returns COM status code.
1444 * @param aPattern The selection pattern. A bit similar to filename globbing.
1445 * @param aWithDescriptions Whether to include the descriptions.
1446 * @param aStats The XML document containing the statistics.
1447 */
1448STDMETHODIMP MachineDebugger::GetStats (IN_BSTR aPattern, BOOL aWithDescriptions, BSTR *aStats)
1449{
1450 Console::SafeVMPtrQuiet ptrVM (mParent);
1451
1452 if (!ptrVM.isOk())
1453 return setError(VBOX_E_INVALID_VM_STATE, "Machine is not running");
1454
1455 char *pszSnapshot;
1456 int vrc = STAMR3Snapshot(ptrVM.rawUVM(), Utf8Str(aPattern).c_str(), &pszSnapshot, NULL,
1457 !!aWithDescriptions);
1458 if (RT_FAILURE(vrc))
1459 return vrc == VERR_NO_MEMORY ? E_OUTOFMEMORY : E_FAIL;
1460
1461 /** @todo this is horribly inefficient! And it's kinda difficult to tell whether it failed...
1462 * Must use UTF-8 or ASCII here and completely avoid these two extra copy operations.
1463 * Until that's done, this method is kind of useless for debugger statistics GUI because
1464 * of the amount statistics in a debug build. */
1465 Bstr(pszSnapshot).detachTo(aStats);
1466 STAMR3SnapshotFree(ptrVM.rawUVM(), pszSnapshot);
1467
1468 return S_OK;
1469}
1470
1471
1472// public methods only for internal purposes
1473/////////////////////////////////////////////////////////////////////////////
1474
1475void MachineDebugger::flushQueuedSettings()
1476{
1477 mFlushMode = true;
1478 if (mSingleStepQueued != ~0)
1479 {
1480 COMSETTER(SingleStep)(mSingleStepQueued);
1481 mSingleStepQueued = ~0;
1482 }
1483 if (mRecompileUserQueued != ~0)
1484 {
1485 COMSETTER(RecompileUser)(mRecompileUserQueued);
1486 mRecompileUserQueued = ~0;
1487 }
1488 if (mRecompileSupervisorQueued != ~0)
1489 {
1490 COMSETTER(RecompileSupervisor)(mRecompileSupervisorQueued);
1491 mRecompileSupervisorQueued = ~0;
1492 }
1493 if (mPatmEnabledQueued != ~0)
1494 {
1495 COMSETTER(PATMEnabled)(mPatmEnabledQueued);
1496 mPatmEnabledQueued = ~0;
1497 }
1498 if (mCsamEnabledQueued != ~0)
1499 {
1500 COMSETTER(CSAMEnabled)(mCsamEnabledQueued);
1501 mCsamEnabledQueued = ~0;
1502 }
1503 if (mLogEnabledQueued != ~0)
1504 {
1505 COMSETTER(LogEnabled)(mLogEnabledQueued);
1506 mLogEnabledQueued = ~0;
1507 }
1508 if (mVirtualTimeRateQueued != ~(uint32_t)0)
1509 {
1510 COMSETTER(VirtualTimeRate)(mVirtualTimeRateQueued);
1511 mVirtualTimeRateQueued = ~0;
1512 }
1513 mFlushMode = false;
1514}
1515
1516// private methods
1517/////////////////////////////////////////////////////////////////////////////
1518
1519bool MachineDebugger::queueSettings() const
1520{
1521 if (!mFlushMode)
1522 {
1523 // check if the machine is running
1524 MachineState_T machineState;
1525 mParent->COMGETTER(State)(&machineState);
1526 switch (machineState)
1527 {
1528 // queue the request
1529 default:
1530 return true;
1531
1532 case MachineState_Running:
1533 case MachineState_Paused:
1534 case MachineState_Stuck:
1535 case MachineState_LiveSnapshotting:
1536 case MachineState_Teleporting:
1537 break;
1538 }
1539 }
1540 return false;
1541}
1542/* 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