VirtualBox

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

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

VBOX_WITH_RAW_MODE changes.

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