VirtualBox

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

Last change on this file since 37952 was 35638, checked in by vboxsync, 14 years ago

Main. QT/FE: fix long standing COM issue

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