VirtualBox

source: vbox/trunk/src/VBox/Main/MachineDebuggerImpl.cpp@ 14579

Last change on this file since 14579 was 14579, checked in by vboxsync, 16 years ago

Main: VirtualBoxBase::addCaller() now returns E_ACCESSDENIED. Also replaced E_UNEXPECTED with E_FAIL in all Assert* statements (for consistency).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.9 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#include "MachineDebuggerImpl.h"
23#include "ConsoleImpl.h"
24#include "Logging.h"
25
26#include <VBox/em.h>
27#include <VBox/patm.h>
28#include <VBox/csam.h>
29#include <VBox/vm.h>
30#include <VBox/tm.h>
31#include <VBox/err.h>
32#include <VBox/hwaccm.h>
33
34//
35// defines
36//
37
38
39//
40// globals
41//
42
43
44//
45// constructor / destructor
46//
47
48HRESULT MachineDebugger::FinalConstruct()
49{
50 mParent = NULL;
51 return S_OK;
52}
53
54void MachineDebugger::FinalRelease()
55{
56 if (isReady())
57 uninit();
58}
59
60//
61// public methods
62//
63
64/**
65 * Initializes the machine debugger object.
66 *
67 * @returns COM result indicator
68 * @param parent handle of our parent object
69 */
70HRESULT MachineDebugger::init(Console *parent)
71{
72 LogFlow(("MachineDebugger::init(): isReady=%d\n", isReady()));
73
74 ComAssertRet (parent, E_INVALIDARG);
75
76 AutoWriteLock alock (this);
77 ComAssertRet (!isReady(), E_FAIL);
78
79 mParent = parent;
80 singlestepQueued = ~0;
81 recompileUserQueued = ~0;
82 recompileSupervisorQueued = ~0;
83 patmEnabledQueued = ~0;
84 csamEnabledQueued = ~0;
85 mLogEnabledQueued = ~0;
86 mVirtualTimeRateQueued = ~0;
87 fFlushMode = false;
88 setReady(true);
89 return S_OK;
90}
91
92/**
93 * Uninitializes the instance and sets the ready flag to FALSE.
94 * Called either from FinalRelease() or by the parent when it gets destroyed.
95 */
96void MachineDebugger::uninit()
97{
98 LogFlow(("MachineDebugger::uninit(): isReady=%d\n", isReady()));
99
100 AutoWriteLock alock (this);
101 AssertReturn (isReady(), (void) 0);
102
103 setReady (false);
104}
105
106/**
107 * Returns the current singlestepping flag.
108 *
109 * @returns COM status code
110 * @param enabled address of result variable
111 */
112STDMETHODIMP MachineDebugger::COMGETTER(Singlestep)(BOOL *enabled)
113{
114 if (!enabled)
115 return E_POINTER;
116 AutoWriteLock alock (this);
117 CHECK_READY();
118 /** @todo */
119 return E_NOTIMPL;
120}
121
122/**
123 * Sets the singlestepping flag.
124 *
125 * @returns COM status code
126 * @param enable new singlestepping flag
127 */
128STDMETHODIMP MachineDebugger::COMSETTER(Singlestep)(BOOL enable)
129{
130 AutoWriteLock alock (this);
131 CHECK_READY();
132 /** @todo */
133 return E_NOTIMPL;
134}
135
136/**
137 * Resets VM statistics.
138 *
139 * @returns COM status code.
140 * @param aPattern The selection pattern. A bit similar to filename globbing.
141 */
142STDMETHODIMP MachineDebugger::ResetStats(INPTR BSTR aPattern)
143{
144 Console::SafeVMPtrQuiet pVM (mParent);
145 if (pVM.isOk())
146 STAMR3Reset(pVM, Utf8Str(aPattern).raw());
147 return S_OK;
148}
149
150/**
151 * Dumps VM statistics to the log.
152 *
153 * @returns COM status code.
154 * @param aPattern The selection pattern. A bit similar to filename globbing.
155 */
156STDMETHODIMP MachineDebugger::DumpStats(INPTR BSTR aPattern)
157{
158 Console::SafeVMPtrQuiet pVM (mParent);
159 if (pVM.isOk())
160 STAMR3Dump(pVM, Utf8Str(aPattern).raw());
161 return S_OK;
162}
163
164/**
165 * Get the VM statistics in an XML format.
166 *
167 * @returns COM status code.
168 * @param aPattern The selection pattern. A bit similar to filename globbing.
169 * @param aWithDescriptions Whether to include the descriptions.
170 * @param aStats The XML document containing the statistics.
171 */
172STDMETHODIMP MachineDebugger::GetStats(INPTR BSTR aPattern, BOOL aWithDescriptions, BSTR *aStats)
173{
174 Console::SafeVMPtrQuiet pVM (mParent);
175 if (!pVM.isOk())
176 return E_FAIL;
177
178 char *pszSnapshot;
179 int vrc = STAMR3Snapshot(pVM, Utf8Str(aPattern).raw(), &pszSnapshot, NULL,
180 !!aWithDescriptions);
181 if (RT_FAILURE(vrc))
182 return vrc == VERR_NO_MEMORY ? E_OUTOFMEMORY : E_FAIL;
183
184 /** @todo this is horribly inefficient! And it's kinda difficult to tell whether it failed...
185 * Must use UTF-8 or ASCII here and completely avoid these two extra copy operations.
186 * Until that's done, this method is kind of useless for debugger statistics GUI because
187 * of the amount statistics in a debug build. */
188 Bstr(pszSnapshot).cloneTo(aStats);
189
190 return S_OK;
191}
192
193/**
194 * Returns the current recompile user mode code flag.
195 *
196 * @returns COM status code
197 * @param enabled address of result variable
198 */
199STDMETHODIMP MachineDebugger::COMGETTER(RecompileUser)(BOOL *enabled)
200{
201 if (!enabled)
202 return E_POINTER;
203 AutoWriteLock alock (this);
204 CHECK_READY();
205 Console::SafeVMPtrQuiet pVM (mParent);
206 if (pVM.isOk())
207 *enabled = !EMIsRawRing3Enabled(pVM.raw());
208 else
209 *enabled = false;
210 return S_OK;
211}
212
213/**
214 * Sets the recompile user mode code flag.
215 *
216 * @returns COM status
217 * @param enable new user mode code recompile flag.
218 */
219STDMETHODIMP MachineDebugger::COMSETTER(RecompileUser)(BOOL enable)
220{
221 LogFlowThisFunc (("enable=%d\n", enable));
222
223 AutoWriteLock alock (this);
224 CHECK_READY();
225
226 if (!fFlushMode)
227 {
228 // check if the machine is running
229 MachineState_T machineState;
230 mParent->COMGETTER(State)(&machineState);
231 if ( machineState != MachineState_Running
232 && machineState != MachineState_Paused
233 && machineState != MachineState_Stuck)
234 {
235 // queue the request
236 recompileUserQueued = enable;
237 return S_OK;
238 }
239 }
240
241 Console::SafeVMPtr pVM (mParent);
242 CheckComRCReturnRC (pVM.rc());
243
244 PVMREQ pReq;
245 EMRAWMODE rawModeFlag = enable ? EMRAW_RING3_DISABLE : EMRAW_RING3_ENABLE;
246 int rcVBox = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT,
247 (PFNRT)EMR3RawSetMode, 2, pVM.raw(), rawModeFlag);
248 if (RT_SUCCESS(rcVBox))
249 {
250 rcVBox = pReq->iStatus;
251 VMR3ReqFree(pReq);
252 }
253
254 if (RT_SUCCESS(rcVBox))
255 return S_OK;
256
257 AssertMsgFailed(("Could not set raw mode flags to %d, rcVBox = %Rrc\n",
258 rawModeFlag, rcVBox));
259 return E_FAIL;
260}
261
262/**
263 * Returns the current recompile supervisor code flag.
264 *
265 * @returns COM status code
266 * @param enabled address of result variable
267 */
268STDMETHODIMP MachineDebugger::COMGETTER(RecompileSupervisor)(BOOL *enabled)
269{
270 if (!enabled)
271 return E_POINTER;
272 AutoWriteLock alock (this);
273 CHECK_READY();
274 Console::SafeVMPtrQuiet pVM (mParent);
275 if (pVM.isOk())
276 *enabled = !EMIsRawRing0Enabled(pVM.raw());
277 else
278 *enabled = false;
279 return S_OK;
280}
281
282/**
283 * Sets the new recompile supervisor code flag.
284 *
285 * @returns COM status code
286 * @param enable new recompile supervisor code flag
287 */
288STDMETHODIMP MachineDebugger::COMSETTER(RecompileSupervisor)(BOOL enable)
289{
290 LogFlowThisFunc (("enable=%d\n", enable));
291
292 AutoWriteLock alock (this);
293 CHECK_READY();
294
295 if (!fFlushMode)
296 {
297 // check if the machine is running
298 MachineState_T machineState;
299 mParent->COMGETTER(State)(&machineState);
300 if ( machineState != MachineState_Running
301 && machineState != MachineState_Paused
302 && machineState != MachineState_Stuck)
303 {
304 // queue the request
305 recompileSupervisorQueued = enable;
306 return S_OK;
307 }
308 }
309
310 Console::SafeVMPtr pVM (mParent);
311 CheckComRCReturnRC (pVM.rc());
312
313 PVMREQ pReq;
314 EMRAWMODE rawModeFlag = enable ? EMRAW_RING0_DISABLE : EMRAW_RING0_ENABLE;
315 int rcVBox = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT,
316 (PFNRT)EMR3RawSetMode, 2, pVM.raw(), rawModeFlag);
317 if (RT_SUCCESS(rcVBox))
318 {
319 rcVBox = pReq->iStatus;
320 VMR3ReqFree(pReq);
321 }
322
323 if (RT_SUCCESS(rcVBox))
324 return S_OK;
325
326 AssertMsgFailed(("Could not set raw mode flags to %d, rcVBox = %Rrc\n",
327 rawModeFlag, rcVBox));
328 return E_FAIL;
329}
330
331/**
332 * Returns the current patch manager enabled flag.
333 *
334 * @returns COM status code
335 * @param enabled address of result variable
336 */
337STDMETHODIMP MachineDebugger::COMGETTER(PATMEnabled)(BOOL *enabled)
338{
339 if (!enabled)
340 return E_POINTER;
341 AutoWriteLock alock (this);
342 CHECK_READY();
343 Console::SafeVMPtrQuiet pVM (mParent);
344 if (pVM.isOk())
345 *enabled = PATMIsEnabled(pVM.raw());
346 else
347 *enabled = false;
348 return S_OK;
349}
350
351/**
352 * Set the new patch manager enabled flag.
353 *
354 * @returns COM status code
355 * @param new patch manager enabled flag
356 */
357STDMETHODIMP MachineDebugger::COMSETTER(PATMEnabled)(BOOL enable)
358{
359 AutoWriteLock alock (this);
360 CHECK_READY();
361 LogFlowThisFunc (("enable=%d\n", enable));
362
363 if (!fFlushMode)
364 {
365 // check if the machine is running
366 MachineState_T machineState;
367 mParent->COMGETTER(State)(&machineState);
368 if ( machineState != MachineState_Running
369 && machineState != MachineState_Paused
370 && machineState != MachineState_Stuck)
371 {
372 // queue the request
373 patmEnabledQueued = enable;
374 return S_OK;
375 }
376 }
377
378 Console::SafeVMPtr pVM (mParent);
379 CheckComRCReturnRC (pVM.rc());
380
381 PATMR3AllowPatching(pVM, enable);
382 return S_OK;
383}
384
385/**
386 * Set the new patch manager enabled flag.
387 *
388 * @returns COM status code
389 * @param new patch manager enabled flag
390 */
391STDMETHODIMP MachineDebugger::InjectNMI()
392{
393 AutoWriteLock alock (this);
394 CHECK_READY();
395 LogFlowThisFunc ((""));
396
397 Console::SafeVMPtr pVM (mParent);
398 CheckComRCReturnRC (pVM.rc());
399
400 HWACCMR3InjectNMI(pVM);
401 return S_OK;
402}
403
404/**
405 * Returns the current code scanner enabled flag.
406 *
407 * @returns COM status code
408 * @param enabled address of result variable
409 */
410STDMETHODIMP MachineDebugger::COMGETTER(CSAMEnabled)(BOOL *enabled)
411{
412 if (!enabled)
413 return E_POINTER;
414 AutoWriteLock alock (this);
415 CHECK_READY();
416 Console::SafeVMPtrQuiet pVM (mParent);
417 if (pVM.isOk())
418 *enabled = CSAMIsEnabled(pVM.raw());
419 else
420 *enabled = false;
421 return S_OK;
422}
423
424/**
425 * Sets the new code scanner enabled flag.
426 *
427 * @returns COM status code
428 * @param enable new code scanner enabled flag
429 */
430STDMETHODIMP MachineDebugger::COMSETTER(CSAMEnabled)(BOOL enable)
431{
432 AutoWriteLock alock (this);
433 CHECK_READY();
434 LogFlowThisFunc (("enable=%d\n", enable));
435
436 if (!fFlushMode)
437 {
438 // check if the machine is running
439 MachineState_T machineState;
440 mParent->COMGETTER(State)(&machineState);
441 if ( machineState != MachineState_Running
442 && machineState != MachineState_Paused
443 && machineState != MachineState_Stuck)
444 {
445 // queue the request
446 csamEnabledQueued = enable;
447 return S_OK;
448 }
449 }
450
451 Console::SafeVMPtr pVM (mParent);
452 CheckComRCReturnRC (pVM.rc());
453
454 int vrc;
455 if (enable)
456 vrc = CSAMEnableScanning(pVM);
457 else
458 vrc = CSAMDisableScanning(pVM);
459 if (RT_FAILURE(vrc))
460 {
461 /** @todo handle error case */
462 }
463 return S_OK;
464}
465
466/**
467 * Returns the log enabled / disabled status.
468 *
469 * @returns COM status code
470 * @param aEnabled address of result variable
471 */
472STDMETHODIMP MachineDebugger::COMGETTER(LogEnabled)(BOOL *aEnabled)
473{
474 if (!aEnabled)
475 return E_POINTER;
476 AutoWriteLock alock(this);
477 CHECK_READY();
478#ifdef LOG_ENABLED
479 PRTLOGGER pLogInstance = RTLogDefaultInstance();
480 *aEnabled = pLogInstance && !(pLogInstance->fFlags & RTLOGFLAGS_DISABLED);
481#else
482 *aEnabled = false;
483#endif
484 return S_OK;
485}
486
487/**
488 * Enables or disables logging.
489 *
490 * @returns COM status code
491 * @param aEnabled The new code log state.
492 */
493STDMETHODIMP MachineDebugger::COMSETTER(LogEnabled)(BOOL aEnabled)
494{
495 AutoWriteLock alock(this);
496
497 CHECK_READY();
498 LogFlowThisFunc (("aEnabled=%d\n", aEnabled));
499
500 if (!fFlushMode)
501 {
502 // check if the machine is running
503 MachineState_T machineState;
504 mParent->COMGETTER(State)(&machineState);
505 if ( machineState != MachineState_Running
506 && machineState != MachineState_Paused
507 && machineState != MachineState_Stuck)
508 {
509 // queue the request
510 mLogEnabledQueued = aEnabled;
511 return S_OK;
512 }
513 }
514
515 Console::SafeVMPtr pVM (mParent);
516 CheckComRCReturnRC (pVM.rc());
517
518#ifdef LOG_ENABLED
519 int vrc = DBGFR3LogModifyFlags(pVM, aEnabled ? "enabled" : "disabled");
520 if (RT_FAILURE(vrc))
521 {
522 /** @todo handle error code. */
523 }
524#endif
525 return S_OK;
526}
527
528/**
529 * Returns the current hardware virtualization flag.
530 *
531 * @returns COM status code
532 * @param enabled address of result variable
533 */
534STDMETHODIMP MachineDebugger::COMGETTER(HWVirtExEnabled)(BOOL *enabled)
535{
536 if (!enabled)
537 return E_POINTER;
538
539 AutoWriteLock alock (this);
540 CHECK_READY();
541
542 Console::SafeVMPtrQuiet pVM (mParent);
543 if (pVM.isOk())
544 *enabled = HWACCMIsEnabled(pVM.raw());
545 else
546 *enabled = false;
547 return S_OK;
548}
549
550/**
551 * Returns the current nested paging flag.
552 *
553 * @returns COM status code
554 * @param enabled address of result variable
555 */
556STDMETHODIMP MachineDebugger::COMGETTER(HWVirtExNestedPagingEnabled)(BOOL *enabled)
557{
558 if (!enabled)
559 return E_POINTER;
560
561 AutoWriteLock alock (this);
562 CHECK_READY();
563
564 Console::SafeVMPtrQuiet pVM (mParent);
565 if (pVM.isOk())
566 *enabled = HWACCMR3IsNestedPagingActive(pVM.raw());
567 else
568 *enabled = false;
569 return S_OK;
570}
571
572/**
573 * Returns the current VPID flag.
574 *
575 * @returns COM status code
576 * @param enabled address of result variable
577 */
578STDMETHODIMP MachineDebugger::COMGETTER(HWVirtExVPIDEnabled)(BOOL *enabled)
579{
580 if (!enabled)
581 return E_POINTER;
582
583 AutoWriteLock alock (this);
584 CHECK_READY();
585
586 Console::SafeVMPtrQuiet pVM (mParent);
587 if (pVM.isOk())
588 *enabled = HWACCMR3IsVPIDActive(pVM.raw());
589 else
590 *enabled = false;
591 return S_OK;
592}
593
594/**
595 * Returns the current PAE flag.
596 *
597 * @returns COM status code
598 * @param enabled address of result variable
599 */
600STDMETHODIMP MachineDebugger::COMGETTER(PAEEnabled)(BOOL *enabled)
601{
602 if (!enabled)
603 return E_POINTER;
604
605 AutoWriteLock alock (this);
606 CHECK_READY();
607
608 Console::SafeVMPtrQuiet pVM (mParent);
609 if (pVM.isOk())
610 {
611 uint64_t cr4 = CPUMGetGuestCR4(pVM.raw());
612 *enabled = !!(cr4 & X86_CR4_PAE);
613 }
614 else
615 *enabled = false;
616 return S_OK;
617}
618
619/**
620 * Returns the current virtual time rate.
621 *
622 * @returns COM status code.
623 * @param pct Where to store the rate.
624 */
625STDMETHODIMP MachineDebugger::COMGETTER(VirtualTimeRate)(ULONG *pct)
626{
627 if (!pct)
628 return E_POINTER;
629
630 AutoWriteLock alock (this);
631 CHECK_READY();
632
633 Console::SafeVMPtrQuiet pVM (mParent);
634 if (pVM.isOk())
635 *pct = TMVirtualGetWarpDrive(pVM);
636 else
637 *pct = 100;
638 return S_OK;
639}
640
641/**
642 * Returns the current virtual time rate.
643 *
644 * @returns COM status code.
645 * @param pct Where to store the rate.
646 */
647STDMETHODIMP MachineDebugger::COMSETTER(VirtualTimeRate)(ULONG pct)
648{
649 if (pct < 2 || pct > 20000)
650 return E_INVALIDARG;
651
652 AutoWriteLock alock (this);
653 CHECK_READY();
654
655 if (!fFlushMode)
656 {
657 // check if the machine is running
658 MachineState_T machineState;
659 mParent->COMGETTER(State)(&machineState);
660 if ( machineState != MachineState_Running
661 && machineState != MachineState_Paused
662 && machineState != MachineState_Stuck)
663 {
664 // queue the request
665 mVirtualTimeRateQueued = pct;
666 return S_OK;
667 }
668 }
669
670 Console::SafeVMPtr pVM (mParent);
671 CheckComRCReturnRC (pVM.rc());
672
673 int vrc = TMVirtualSetWarpDrive(pVM, pct);
674 if (RT_FAILURE(vrc))
675 {
676 /** @todo handle error code. */
677 }
678 return S_OK;
679}
680
681/**
682 * Hack for getting the VM handle.
683 * This is only temporary (promise) while prototyping the debugger.
684 *
685 * @returns COM status code
686 * @param vm Where to store the vm handle.
687 * Since there is no uintptr_t in COM, we're using the max integer.
688 * (No, ULONG is not pointer sized!)
689 */
690STDMETHODIMP MachineDebugger::COMGETTER(VM)(ULONG64 *vm)
691{
692 if (!vm)
693 return E_POINTER;
694
695 AutoWriteLock alock (this);
696 CHECK_READY();
697
698 Console::SafeVMPtr pVM (mParent);
699 CheckComRCReturnRC (pVM.rc());
700
701 *vm = (uintptr_t)pVM.raw();
702
703 /*
704 * Note: pVM protection provided by SafeVMPtr is no more effective
705 * after we return from this method.
706 */
707
708 return S_OK;
709}
710
711//
712// "public-private" methods
713//
714void MachineDebugger::flushQueuedSettings()
715{
716 fFlushMode = true;
717 if (singlestepQueued != ~0)
718 {
719 COMSETTER(Singlestep)(singlestepQueued);
720 singlestepQueued = ~0;
721 }
722 if (recompileUserQueued != ~0)
723 {
724 COMSETTER(RecompileUser)(recompileUserQueued);
725 recompileUserQueued = ~0;
726 }
727 if (recompileSupervisorQueued != ~0)
728 {
729 COMSETTER(RecompileSupervisor)(recompileSupervisorQueued);
730 recompileSupervisorQueued = ~0;
731 }
732 if (patmEnabledQueued != ~0)
733 {
734 COMSETTER(PATMEnabled)(patmEnabledQueued);
735 patmEnabledQueued = ~0;
736 }
737 if (csamEnabledQueued != ~0)
738 {
739 COMSETTER(CSAMEnabled)(csamEnabledQueued);
740 csamEnabledQueued = ~0;
741 }
742 if (mLogEnabledQueued != ~0)
743 {
744 COMSETTER(LogEnabled)(mLogEnabledQueued);
745 mLogEnabledQueued = ~0;
746 }
747 if (mVirtualTimeRateQueued != ~(uint32_t)0)
748 {
749 COMSETTER(VirtualTimeRate)(mVirtualTimeRateQueued);
750 mVirtualTimeRateQueued = ~0;
751 }
752 fFlushMode = false;
753}
754
755//
756// private methods
757//
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use