VirtualBox

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

Last change on this file since 47469 was 46423, checked in by vboxsync, 11 years ago

VMM,Main: Introduced a execute-all-in-IEM debug mode.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use