VirtualBox

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

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

Main, VMM: Added an API seting to disable VT-x unrestricted execution.

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