VirtualBox

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

Last change on this file since 35381 was 35368, checked in by vboxsync, 14 years ago

Main: source re-org.

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