VirtualBox

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

Last change on this file since 80008 was 80008, checked in by vboxsync, 5 years ago

VMM: Kicking out raw-mode (work in progress). bugref:9517

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 49.8 KB
Line 
1/* $Id: MachineDebuggerImpl.cpp 80008 2019-07-26 14:05:14Z vboxsync $ */
2/** @file
3 * VBox IMachineDebugger COM class implementation (VBoxC).
4 */
5
6/*
7 * Copyright (C) 2006-2019 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/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_MAIN_MACHINEDEBUGGER
23#include "LoggingNew.h"
24
25#include "MachineDebuggerImpl.h"
26
27#include "Global.h"
28#include "ConsoleImpl.h"
29
30#include "AutoCaller.h"
31
32#include <VBox/vmm/em.h>
33#include <VBox/vmm/uvm.h>
34#include <VBox/vmm/tm.h>
35#include <VBox/vmm/hm.h>
36#include <VBox/err.h>
37#include <iprt/cpp/utils.h>
38
39
40// constructor / destructor
41/////////////////////////////////////////////////////////////////////////////
42
43MachineDebugger::MachineDebugger()
44 : mParent(NULL)
45{
46}
47
48MachineDebugger::~MachineDebugger()
49{
50}
51
52HRESULT MachineDebugger::FinalConstruct()
53{
54 unconst(mParent) = NULL;
55 return BaseFinalConstruct();
56}
57
58void MachineDebugger::FinalRelease()
59{
60 uninit();
61 BaseFinalRelease();
62}
63
64// public initializer/uninitializer for internal purposes only
65/////////////////////////////////////////////////////////////////////////////
66
67/**
68 * Initializes the machine debugger object.
69 *
70 * @returns COM result indicator
71 * @param aParent handle of our parent object
72 */
73HRESULT MachineDebugger::init(Console *aParent)
74{
75 LogFlowThisFunc(("aParent=%p\n", aParent));
76
77 ComAssertRet(aParent, E_INVALIDARG);
78
79 /* Enclose the state transition NotReady->InInit->Ready */
80 AutoInitSpan autoInitSpan(this);
81 AssertReturn(autoInitSpan.isOk(), E_FAIL);
82
83 unconst(mParent) = aParent;
84
85 for (unsigned i = 0; i < RT_ELEMENTS(maiQueuedEmExecPolicyParams); i++)
86 maiQueuedEmExecPolicyParams[i] = UINT8_MAX;
87 mSingleStepQueued = -1;
88 mRecompileUserQueued = -1;
89 mRecompileSupervisorQueued = -1;
90 mPatmEnabledQueued = -1;
91 mCsamEnabledQueued = -1;
92 mLogEnabledQueued = -1;
93 mVirtualTimeRateQueued = UINT32_MAX;
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 aSingleStep Where to store the result.
127 */
128HRESULT MachineDebugger::getSingleStep(BOOL *aSingleStep)
129{
130 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
131 Console::SafeVMPtr ptrVM(mParent);
132 HRESULT hrc = ptrVM.rc();
133 if (SUCCEEDED(hrc))
134 {
135 RT_NOREF(aSingleStep); /** @todo */
136 ReturnComNotImplemented();
137 }
138 return hrc;
139}
140
141/**
142 * Sets the singlestepping flag.
143 *
144 * @returns COM status code
145 * @param aSingleStep The new state.
146 */
147HRESULT MachineDebugger::setSingleStep(BOOL aSingleStep)
148{
149 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
150 Console::SafeVMPtr ptrVM(mParent);
151 HRESULT hrc = ptrVM.rc();
152 if (SUCCEEDED(hrc))
153 {
154 NOREF(aSingleStep); /** @todo */
155 ReturnComNotImplemented();
156 }
157 return hrc;
158}
159
160/**
161 * Internal worker for getting an EM executable policy setting.
162 *
163 * @returns COM status code.
164 * @param enmPolicy Which EM policy.
165 * @param pfEnforced Where to return the policy setting.
166 */
167HRESULT MachineDebugger::i_getEmExecPolicyProperty(EMEXECPOLICY enmPolicy, BOOL *pfEnforced)
168{
169 CheckComArgOutPointerValid(pfEnforced);
170
171 AutoCaller autoCaller(this);
172 HRESULT hrc = autoCaller.rc();
173 if (SUCCEEDED(hrc))
174 {
175 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
176 if (i_queueSettings())
177 *pfEnforced = maiQueuedEmExecPolicyParams[enmPolicy] == 1;
178 else
179 {
180 bool fEnforced = false;
181 Console::SafeVMPtrQuiet ptrVM(mParent);
182 hrc = ptrVM.rc();
183 if (SUCCEEDED(hrc))
184 EMR3QueryExecutionPolicy(ptrVM.rawUVM(), enmPolicy, &fEnforced);
185 *pfEnforced = fEnforced;
186 }
187 }
188 return hrc;
189}
190
191/**
192 * Internal worker for setting an EM executable policy.
193 *
194 * @returns COM status code.
195 * @param enmPolicy Which policy to change.
196 * @param fEnforce Whether to enforce the policy or not.
197 */
198HRESULT MachineDebugger::i_setEmExecPolicyProperty(EMEXECPOLICY enmPolicy, BOOL fEnforce)
199{
200 AutoCaller autoCaller(this);
201 HRESULT hrc = autoCaller.rc();
202 if (SUCCEEDED(hrc))
203 {
204 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
205 if (i_queueSettings())
206 maiQueuedEmExecPolicyParams[enmPolicy] = fEnforce ? 1 : 0;
207 else
208 {
209 Console::SafeVMPtrQuiet ptrVM(mParent);
210 hrc = ptrVM.rc();
211 if (SUCCEEDED(hrc))
212 {
213 int vrc = EMR3SetExecutionPolicy(ptrVM.rawUVM(), enmPolicy, fEnforce != FALSE);
214 if (RT_FAILURE(vrc))
215 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("EMR3SetExecutionPolicy failed with %Rrc"), vrc);
216 }
217 }
218 }
219 return hrc;
220}
221
222/**
223 * Returns the current recompile user mode code flag.
224 *
225 * @returns COM status code
226 * @param aRecompileUser address of result variable
227 */
228HRESULT MachineDebugger::getRecompileUser(BOOL *aRecompileUser)
229{
230 return i_getEmExecPolicyProperty(EMEXECPOLICY_RECOMPILE_RING3, aRecompileUser);
231}
232
233/**
234 * Sets the recompile user mode code flag.
235 *
236 * @returns COM status
237 * @param aRecompileUser new user mode code recompile flag.
238 */
239HRESULT MachineDebugger::setRecompileUser(BOOL aRecompileUser)
240{
241 LogFlowThisFunc(("enable=%d\n", aRecompileUser));
242 return i_setEmExecPolicyProperty(EMEXECPOLICY_RECOMPILE_RING3, aRecompileUser);
243}
244
245/**
246 * Returns the current recompile supervisor code flag.
247 *
248 * @returns COM status code
249 * @param aRecompileSupervisor address of result variable
250 */
251HRESULT MachineDebugger::getRecompileSupervisor(BOOL *aRecompileSupervisor)
252{
253 return i_getEmExecPolicyProperty(EMEXECPOLICY_RECOMPILE_RING0, aRecompileSupervisor);
254}
255
256/**
257 * Sets the new recompile supervisor code flag.
258 *
259 * @returns COM status code
260 * @param aRecompileSupervisor new recompile supervisor code flag
261 */
262HRESULT MachineDebugger::setRecompileSupervisor(BOOL aRecompileSupervisor)
263{
264 LogFlowThisFunc(("enable=%d\n", aRecompileSupervisor));
265 return i_setEmExecPolicyProperty(EMEXECPOLICY_RECOMPILE_RING0, aRecompileSupervisor);
266}
267
268/**
269 * Returns the current execute-all-in-IEM setting.
270 *
271 * @returns COM status code
272 * @param aExecuteAllInIEM Address of result variable.
273 */
274HRESULT MachineDebugger::getExecuteAllInIEM(BOOL *aExecuteAllInIEM)
275{
276 return i_getEmExecPolicyProperty(EMEXECPOLICY_IEM_ALL, aExecuteAllInIEM);
277}
278
279/**
280 * Changes the execute-all-in-IEM setting.
281 *
282 * @returns COM status code
283 * @param aExecuteAllInIEM New setting.
284 */
285HRESULT MachineDebugger::setExecuteAllInIEM(BOOL aExecuteAllInIEM)
286{
287 LogFlowThisFunc(("enable=%d\n", aExecuteAllInIEM));
288 return i_setEmExecPolicyProperty(EMEXECPOLICY_IEM_ALL, aExecuteAllInIEM);
289}
290
291/**
292 * Returns the current patch manager enabled flag.
293 *
294 * @returns COM status code
295 * @param aPATMEnabled address of result variable
296 */
297HRESULT MachineDebugger::getPATMEnabled(BOOL *aPATMEnabled)
298{
299 *aPATMEnabled = false;
300 return S_OK;
301}
302
303/**
304 * Set the new patch manager enabled flag.
305 *
306 * @returns COM status code
307 * @param aPATMEnabled new patch manager enabled flag
308 */
309HRESULT MachineDebugger::setPATMEnabled(BOOL aPATMEnabled)
310{
311 LogFlowThisFunc(("enable=%d\n", aPATMEnabled));
312
313 if (aPATMEnabled)
314 return setErrorBoth(VBOX_E_VM_ERROR, VERR_RAW_MODE_NOT_SUPPORTED, tr("PATM not present"), VERR_NOT_SUPPORTED);
315 return S_OK;
316}
317
318/**
319 * Returns the current code scanner enabled flag.
320 *
321 * @returns COM status code
322 * @param aCSAMEnabled address of result variable
323 */
324HRESULT MachineDebugger::getCSAMEnabled(BOOL *aCSAMEnabled)
325{
326 *aCSAMEnabled = false;
327 return S_OK;
328}
329
330/**
331 * Sets the new code scanner enabled flag.
332 *
333 * @returns COM status code
334 * @param aCSAMEnabled new code scanner enabled flag
335 */
336HRESULT MachineDebugger::setCSAMEnabled(BOOL aCSAMEnabled)
337{
338 LogFlowThisFunc(("enable=%d\n", aCSAMEnabled));
339
340 if (aCSAMEnabled)
341 return setErrorBoth(VBOX_E_VM_ERROR, VERR_RAW_MODE_NOT_SUPPORTED, tr("CASM not present"));
342 return S_OK;
343}
344
345/**
346 * Returns the log enabled / disabled status.
347 *
348 * @returns COM status code
349 * @param aLogEnabled address of result variable
350 */
351HRESULT MachineDebugger::getLogEnabled(BOOL *aLogEnabled)
352{
353#ifdef LOG_ENABLED
354 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
355
356 const PRTLOGGER pLogInstance = RTLogDefaultInstance();
357 *aLogEnabled = pLogInstance && !(pLogInstance->fFlags & RTLOGFLAGS_DISABLED);
358#else
359 *aLogEnabled = false;
360#endif
361
362 return S_OK;
363}
364
365/**
366 * Enables or disables logging.
367 *
368 * @returns COM status code
369 * @param aLogEnabled The new code log state.
370 */
371HRESULT MachineDebugger::setLogEnabled(BOOL aLogEnabled)
372{
373 LogFlowThisFunc(("aLogEnabled=%d\n", aLogEnabled));
374
375 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
376
377 if (i_queueSettings())
378 {
379 // queue the request
380 mLogEnabledQueued = aLogEnabled;
381 return S_OK;
382 }
383
384 Console::SafeVMPtr ptrVM(mParent);
385 if (FAILED(ptrVM.rc())) return ptrVM.rc();
386
387#ifdef LOG_ENABLED
388 int vrc = DBGFR3LogModifyFlags(ptrVM.rawUVM(), aLogEnabled ? "enabled" : "disabled");
389 if (RT_FAILURE(vrc))
390 {
391 /** @todo handle error code. */
392 }
393#endif
394
395 return S_OK;
396}
397
398HRESULT MachineDebugger::i_logStringProps(PRTLOGGER pLogger, PFNLOGGETSTR pfnLogGetStr,
399 const char *pszLogGetStr, Utf8Str *pstrSettings)
400{
401 /* Make sure the VM is powered up. */
402 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
403 Console::SafeVMPtr ptrVM(mParent);
404 HRESULT hrc = ptrVM.rc();
405 if (FAILED(hrc))
406 return hrc;
407
408 /* Make sure we've got a logger. */
409 if (!pLogger)
410 {
411 *pstrSettings = "";
412 return S_OK;
413 }
414
415 /* Do the job. */
416 size_t cbBuf = _1K;
417 for (;;)
418 {
419 char *pszBuf = (char *)RTMemTmpAlloc(cbBuf);
420 AssertReturn(pszBuf, E_OUTOFMEMORY);
421 int vrc = pstrSettings->reserveNoThrow(cbBuf);
422 if (RT_SUCCESS(vrc))
423 {
424 vrc = pfnLogGetStr(pLogger, pstrSettings->mutableRaw(), cbBuf);
425 if (RT_SUCCESS(vrc))
426 {
427 pstrSettings->jolt();
428 return S_OK;
429 }
430 *pstrSettings = "";
431 AssertReturn(vrc == VERR_BUFFER_OVERFLOW,
432 setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("%s returned %Rrc"), pszLogGetStr, vrc));
433 }
434 else
435 return E_OUTOFMEMORY;
436
437 /* try again with a bigger buffer. */
438 cbBuf *= 2;
439 AssertReturn(cbBuf <= _256K, setError(E_FAIL, tr("%s returns too much data"), pszLogGetStr));
440 }
441}
442
443HRESULT MachineDebugger::getLogDbgFlags(com::Utf8Str &aLogDbgFlags)
444{
445 return i_logStringProps(RTLogGetDefaultInstance(), RTLogGetFlags, "RTGetFlags", &aLogDbgFlags);
446}
447
448HRESULT MachineDebugger::getLogDbgGroups(com::Utf8Str &aLogDbgGroups)
449{
450 return i_logStringProps(RTLogGetDefaultInstance(), RTLogGetGroupSettings, "RTLogGetGroupSettings", &aLogDbgGroups);
451}
452
453HRESULT MachineDebugger::getLogDbgDestinations(com::Utf8Str &aLogDbgDestinations)
454{
455 return i_logStringProps(RTLogGetDefaultInstance(), RTLogGetDestinations, "RTLogGetDestinations", &aLogDbgDestinations);
456}
457
458HRESULT MachineDebugger::getLogRelFlags(com::Utf8Str &aLogRelFlags)
459{
460 return i_logStringProps(RTLogRelGetDefaultInstance(), RTLogGetFlags, "RTGetFlags", &aLogRelFlags);
461}
462
463HRESULT MachineDebugger::getLogRelGroups(com::Utf8Str &aLogRelGroups)
464{
465 return i_logStringProps(RTLogRelGetDefaultInstance(), RTLogGetGroupSettings, "RTLogGetGroupSettings", &aLogRelGroups);
466}
467
468HRESULT MachineDebugger::getLogRelDestinations(com::Utf8Str &aLogRelDestinations)
469{
470 return i_logStringProps(RTLogRelGetDefaultInstance(), RTLogGetDestinations, "RTLogGetDestinations", &aLogRelDestinations);
471}
472
473/**
474 * Return the main execution engine of the VM.
475 *
476 * @returns COM status code
477 * @param apenmEngine Address of the result variable.
478 */
479HRESULT MachineDebugger::getExecutionEngine(VMExecutionEngine_T *apenmEngine)
480{
481 *apenmEngine = VMExecutionEngine_NotSet;
482
483 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
484 Console::SafeVMPtrQuiet ptrVM(mParent);
485 if (ptrVM.isOk())
486 {
487 uint8_t bEngine = UINT8_MAX;
488 int rc = EMR3QueryMainExecutionEngine(ptrVM.rawUVM(), &bEngine);
489 if (RT_SUCCESS(rc))
490 switch (bEngine)
491 {
492 case VM_EXEC_ENGINE_NOT_SET: *apenmEngine = VMExecutionEngine_NotSet; break;
493 case VM_EXEC_ENGINE_RAW_MODE: *apenmEngine = VMExecutionEngine_RawMode; break;
494 case VM_EXEC_ENGINE_HW_VIRT: *apenmEngine = VMExecutionEngine_HwVirt; break;
495 case VM_EXEC_ENGINE_NATIVE_API: *apenmEngine = VMExecutionEngine_NativeApi; break;
496 default: AssertMsgFailed(("bEngine=%d\n", bEngine));
497 }
498 }
499
500 return S_OK;
501}
502
503/**
504 * Returns the current hardware virtualization flag.
505 *
506 * @returns COM status code
507 * @param aHWVirtExEnabled address of result variable
508 */
509HRESULT MachineDebugger::getHWVirtExEnabled(BOOL *aHWVirtExEnabled)
510{
511 *aHWVirtExEnabled = false;
512
513 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
514 Console::SafeVMPtrQuiet ptrVM(mParent);
515 if (ptrVM.isOk())
516 {
517 uint8_t bEngine = UINT8_MAX;
518 int rc = EMR3QueryMainExecutionEngine(ptrVM.rawUVM(), &bEngine);
519 *aHWVirtExEnabled = RT_SUCCESS(rc) && bEngine == VM_EXEC_ENGINE_HW_VIRT;
520 }
521
522 return S_OK;
523}
524
525/**
526 * Returns the current nested paging flag.
527 *
528 * @returns COM status code
529 * @param aHWVirtExNestedPagingEnabled address of result variable
530 */
531HRESULT MachineDebugger::getHWVirtExNestedPagingEnabled(BOOL *aHWVirtExNestedPagingEnabled)
532{
533 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
534
535 Console::SafeVMPtrQuiet ptrVM(mParent);
536
537 if (ptrVM.isOk())
538 *aHWVirtExNestedPagingEnabled = HMR3IsNestedPagingActive(ptrVM.rawUVM());
539 else
540 *aHWVirtExNestedPagingEnabled = false;
541
542 return S_OK;
543}
544
545/**
546 * Returns the current VPID flag.
547 *
548 * @returns COM status code
549 * @param aHWVirtExVPIDEnabled address of result variable
550 */
551HRESULT MachineDebugger::getHWVirtExVPIDEnabled(BOOL *aHWVirtExVPIDEnabled)
552{
553 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
554
555 Console::SafeVMPtrQuiet ptrVM(mParent);
556
557 if (ptrVM.isOk())
558 *aHWVirtExVPIDEnabled = HMR3IsVpidActive(ptrVM.rawUVM());
559 else
560 *aHWVirtExVPIDEnabled = false;
561
562 return S_OK;
563}
564
565/**
566 * Returns the current unrestricted execution setting.
567 *
568 * @returns COM status code
569 * @param aHWVirtExUXEnabled address of result variable
570 */
571HRESULT MachineDebugger::getHWVirtExUXEnabled(BOOL *aHWVirtExUXEnabled)
572{
573 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
574
575 Console::SafeVMPtrQuiet ptrVM(mParent);
576
577 if (ptrVM.isOk())
578 *aHWVirtExUXEnabled = HMR3IsUXActive(ptrVM.rawUVM());
579 else
580 *aHWVirtExUXEnabled = false;
581
582 return S_OK;
583}
584
585HRESULT MachineDebugger::getOSName(com::Utf8Str &aOSName)
586{
587 LogFlowThisFunc(("\n"));
588 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
589 Console::SafeVMPtr ptrVM(mParent);
590 HRESULT hrc = ptrVM.rc();
591 if (SUCCEEDED(hrc))
592 {
593 /*
594 * Do the job and try convert the name.
595 */
596 char szName[64];
597 int vrc = DBGFR3OSQueryNameAndVersion(ptrVM.rawUVM(), szName, sizeof(szName), NULL, 0);
598 if (RT_SUCCESS(vrc))
599 {
600 try
601 {
602 Bstr bstrName(szName);
603 aOSName = Utf8Str(bstrName);
604 }
605 catch (std::bad_alloc &)
606 {
607 hrc = E_OUTOFMEMORY;
608 }
609 }
610 else
611 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("DBGFR3OSQueryNameAndVersion failed with %Rrc"), vrc);
612 }
613 return hrc;
614}
615
616HRESULT MachineDebugger::getOSVersion(com::Utf8Str &aOSVersion)
617{
618 LogFlowThisFunc(("\n"));
619 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
620 Console::SafeVMPtr ptrVM(mParent);
621 HRESULT hrc = ptrVM.rc();
622 if (SUCCEEDED(hrc))
623 {
624 /*
625 * Do the job and try convert the name.
626 */
627 char szVersion[256];
628 int vrc = DBGFR3OSQueryNameAndVersion(ptrVM.rawUVM(), NULL, 0, szVersion, sizeof(szVersion));
629 if (RT_SUCCESS(vrc))
630 {
631 try
632 {
633 Bstr bstrVersion(szVersion);
634 aOSVersion = Utf8Str(bstrVersion);
635 }
636 catch (std::bad_alloc &)
637 {
638 hrc = E_OUTOFMEMORY;
639 }
640 }
641 else
642 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("DBGFR3OSQueryNameAndVersion failed with %Rrc"), vrc);
643 }
644 return hrc;
645}
646
647/**
648 * Returns the current PAE flag.
649 *
650 * @returns COM status code
651 * @param aPAEEnabled address of result variable.
652 */
653HRESULT MachineDebugger::getPAEEnabled(BOOL *aPAEEnabled)
654{
655 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
656
657 Console::SafeVMPtrQuiet ptrVM(mParent);
658
659 if (ptrVM.isOk())
660 {
661 uint32_t cr4;
662 int rc = DBGFR3RegCpuQueryU32(ptrVM.rawUVM(), 0 /*idCpu*/, DBGFREG_CR4, &cr4); AssertRC(rc);
663 *aPAEEnabled = RT_BOOL(cr4 & X86_CR4_PAE);
664 }
665 else
666 *aPAEEnabled = false;
667
668 return S_OK;
669}
670
671/**
672 * Returns the current virtual time rate.
673 *
674 * @returns COM status code.
675 * @param aVirtualTimeRate Where to store the rate.
676 */
677HRESULT MachineDebugger::getVirtualTimeRate(ULONG *aVirtualTimeRate)
678{
679 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
680
681 Console::SafeVMPtr ptrVM(mParent);
682 HRESULT hrc = ptrVM.rc();
683 if (SUCCEEDED(hrc))
684 *aVirtualTimeRate = TMR3GetWarpDrive(ptrVM.rawUVM());
685
686 return hrc;
687}
688
689/**
690 * Set the virtual time rate.
691 *
692 * @returns COM status code.
693 * @param aVirtualTimeRate The new rate.
694 */
695HRESULT MachineDebugger::setVirtualTimeRate(ULONG aVirtualTimeRate)
696{
697 HRESULT hrc = S_OK;
698
699 if (aVirtualTimeRate < 2 || aVirtualTimeRate > 20000)
700 return setError(E_INVALIDARG, tr("%u is out of range [2..20000]"), aVirtualTimeRate);
701
702 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
703 if (i_queueSettings())
704 mVirtualTimeRateQueued = aVirtualTimeRate;
705 else
706 {
707 Console::SafeVMPtr ptrVM(mParent);
708 hrc = ptrVM.rc();
709 if (SUCCEEDED(hrc))
710 {
711 int vrc = TMR3SetWarpDrive(ptrVM.rawUVM(), aVirtualTimeRate);
712 if (RT_FAILURE(vrc))
713 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("TMR3SetWarpDrive(, %u) failed with rc=%Rrc"), aVirtualTimeRate, vrc);
714 }
715 }
716
717 return hrc;
718}
719
720/**
721 * Hack for getting the user mode VM handle (UVM).
722 *
723 * This is only temporary (promise) while prototyping the debugger.
724 *
725 * @returns COM status code
726 * @param aVM Where to store the vm handle. Since there is no
727 * uintptr_t in COM, we're using the max integer.
728 * (No, ULONG is not pointer sized!)
729 * @remarks The returned handle must be passed to VMR3ReleaseUVM()!
730 * @remarks Prior to 4.3 this returned PVM.
731 */
732HRESULT MachineDebugger::getVM(LONG64 *aVM)
733{
734 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
735
736 Console::SafeVMPtr ptrVM(mParent);
737 HRESULT hrc = ptrVM.rc();
738 if (SUCCEEDED(hrc))
739 {
740 VMR3RetainUVM(ptrVM.rawUVM());
741 *aVM = (intptr_t)ptrVM.rawUVM();
742 }
743
744 /*
745 * Note! ptrVM protection provided by SafeVMPtr is no long effective
746 * after we return from this method.
747 */
748 return hrc;
749}
750
751/**
752 * Get the VM uptime in milliseconds.
753 *
754 * @returns COM status code
755 * @param aUptime Where to store the uptime.
756 */
757HRESULT MachineDebugger::getUptime(LONG64 *aUptime)
758{
759 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
760
761 Console::SafeVMPtr ptrVM(mParent);
762 HRESULT hrc = ptrVM.rc();
763 if (SUCCEEDED(hrc))
764 *aUptime = (int64_t)TMR3TimeVirtGetMilli(ptrVM.rawUVM());
765
766 return hrc;
767}
768
769// IMachineDebugger methods
770/////////////////////////////////////////////////////////////////////////////
771
772HRESULT MachineDebugger::dumpGuestCore(const com::Utf8Str &aFilename, const com::Utf8Str &aCompression)
773{
774 if (aCompression.length())
775 return setError(E_INVALIDARG, tr("The compression parameter must be empty"));
776
777 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
778 Console::SafeVMPtr ptrVM(mParent);
779 HRESULT hrc = ptrVM.rc();
780 if (SUCCEEDED(hrc))
781 {
782 int vrc = DBGFR3CoreWrite(ptrVM.rawUVM(), aFilename.c_str(), false /*fReplaceFile*/);
783 if (RT_SUCCESS(vrc))
784 hrc = S_OK;
785 else
786 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3CoreWrite failed with %Rrc"), vrc);
787 }
788
789 return hrc;
790}
791
792HRESULT MachineDebugger::dumpHostProcessCore(const com::Utf8Str &aFilename, const com::Utf8Str &aCompression)
793{
794 RT_NOREF(aFilename, aCompression);
795 ReturnComNotImplemented();
796}
797
798/**
799 * Debug info string buffer formatter.
800 */
801typedef struct MACHINEDEBUGGERINOFHLP
802{
803 /** The core info helper structure. */
804 DBGFINFOHLP Core;
805 /** Pointer to the buffer. */
806 char *pszBuf;
807 /** The size of the buffer. */
808 size_t cbBuf;
809 /** The offset into the buffer */
810 size_t offBuf;
811 /** Indicates an out-of-memory condition. */
812 bool fOutOfMemory;
813} MACHINEDEBUGGERINOFHLP;
814/** Pointer to a Debug info string buffer formatter. */
815typedef MACHINEDEBUGGERINOFHLP *PMACHINEDEBUGGERINOFHLP;
816
817
818/**
819 * @callback_method_impl{FNRTSTROUTPUT}
820 */
821static DECLCALLBACK(size_t) MachineDebuggerInfoOutput(void *pvArg, const char *pachChars, size_t cbChars)
822{
823 PMACHINEDEBUGGERINOFHLP pHlp = (PMACHINEDEBUGGERINOFHLP)pvArg;
824
825 /*
826 * Grow the buffer if required.
827 */
828 size_t const cbRequired = cbChars + pHlp->offBuf + 1;
829 if (cbRequired > pHlp->cbBuf)
830 {
831 if (RT_UNLIKELY(pHlp->fOutOfMemory))
832 return 0;
833
834 size_t cbBufNew = pHlp->cbBuf * 2;
835 if (cbRequired > cbBufNew)
836 cbBufNew = RT_ALIGN_Z(cbRequired, 256);
837 void *pvBufNew = RTMemRealloc(pHlp->pszBuf, cbBufNew);
838 if (RT_UNLIKELY(!pvBufNew))
839 {
840 pHlp->fOutOfMemory = true;
841 RTMemFree(pHlp->pszBuf);
842 pHlp->pszBuf = NULL;
843 pHlp->cbBuf = 0;
844 pHlp->offBuf = 0;
845 return 0;
846 }
847
848 pHlp->pszBuf = (char *)pvBufNew;
849 pHlp->cbBuf = cbBufNew;
850 }
851
852 /*
853 * Copy the bytes into the buffer and terminate it.
854 */
855 if (cbChars)
856 {
857 memcpy(&pHlp->pszBuf[pHlp->offBuf], pachChars, cbChars);
858 pHlp->offBuf += cbChars;
859 }
860 pHlp->pszBuf[pHlp->offBuf] = '\0';
861 Assert(pHlp->offBuf < pHlp->cbBuf);
862 return cbChars;
863}
864
865/**
866 * @interface_method_impl{DBGFINFOHLP,pfnPrintfV}
867 */
868static DECLCALLBACK(void) MachineDebuggerInfoPrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
869{
870 RTStrFormatV(MachineDebuggerInfoOutput, (void *)pHlp, NULL, NULL, pszFormat, args);
871}
872
873/**
874 * @interface_method_impl{DBGFINFOHLP,pfnPrintf}
875 */
876static DECLCALLBACK(void) MachineDebuggerInfoPrintf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
877{
878 va_list va;
879 va_start(va, pszFormat);
880 MachineDebuggerInfoPrintfV(pHlp, pszFormat, va);
881 va_end(va);
882}
883
884/**
885 * Initializes the debug info string buffer formatter
886 *
887 * @param pHlp The help structure to init.
888 */
889static void MachineDebuggerInfoInit(PMACHINEDEBUGGERINOFHLP pHlp)
890{
891 pHlp->Core.pfnPrintf = MachineDebuggerInfoPrintf;
892 pHlp->Core.pfnPrintfV = MachineDebuggerInfoPrintfV;
893 pHlp->pszBuf = NULL;
894 pHlp->cbBuf = 0;
895 pHlp->offBuf = 0;
896 pHlp->fOutOfMemory = false;
897}
898
899/**
900 * Deletes the debug info string buffer formatter.
901 * @param pHlp The helper structure to delete.
902 */
903static void MachineDebuggerInfoDelete(PMACHINEDEBUGGERINOFHLP pHlp)
904{
905 RTMemFree(pHlp->pszBuf);
906 pHlp->pszBuf = NULL;
907}
908
909HRESULT MachineDebugger::info(const com::Utf8Str &aName, const com::Utf8Str &aArgs, com::Utf8Str &aInfo)
910{
911 LogFlowThisFunc(("\n"));
912
913 /*
914 * Do the autocaller and lock bits.
915 */
916 AutoCaller autoCaller(this);
917 HRESULT hrc = autoCaller.rc();
918 if (SUCCEEDED(hrc))
919 {
920 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
921 Console::SafeVMPtr ptrVM(mParent);
922 hrc = ptrVM.rc();
923 if (SUCCEEDED(hrc))
924 {
925 /*
926 * Create a helper and call DBGFR3Info.
927 */
928 MACHINEDEBUGGERINOFHLP Hlp;
929 MachineDebuggerInfoInit(&Hlp);
930 int vrc = DBGFR3Info(ptrVM.rawUVM(), aName.c_str(), aArgs.c_str(), &Hlp.Core);
931 if (RT_SUCCESS(vrc))
932 {
933 if (!Hlp.fOutOfMemory)
934 {
935 /*
936 * Convert the info string, watching out for allocation errors.
937 */
938 try
939 {
940 Bstr bstrInfo(Hlp.pszBuf);
941 aInfo = bstrInfo;
942 }
943 catch (std::bad_alloc &)
944 {
945 hrc = E_OUTOFMEMORY;
946 }
947 }
948 else
949 hrc = E_OUTOFMEMORY;
950 }
951 else
952 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("DBGFR3Info failed with %Rrc"), vrc);
953 MachineDebuggerInfoDelete(&Hlp);
954 }
955 }
956 return hrc;
957}
958
959HRESULT MachineDebugger::injectNMI()
960{
961 LogFlowThisFunc(("\n"));
962
963 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
964 Console::SafeVMPtr ptrVM(mParent);
965 HRESULT hrc = ptrVM.rc();
966 if (SUCCEEDED(hrc))
967 {
968 int vrc = DBGFR3InjectNMI(ptrVM.rawUVM(), 0);
969 if (RT_SUCCESS(vrc))
970 hrc = S_OK;
971 else
972 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3InjectNMI failed with %Rrc"), vrc);
973 }
974 return hrc;
975}
976
977HRESULT MachineDebugger::modifyLogFlags(const com::Utf8Str &aSettings)
978{
979 LogFlowThisFunc(("aSettings=%s\n", aSettings.c_str()));
980 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
981 Console::SafeVMPtr ptrVM(mParent);
982 HRESULT hrc = ptrVM.rc();
983 if (SUCCEEDED(hrc))
984 {
985 int vrc = DBGFR3LogModifyFlags(ptrVM.rawUVM(), aSettings.c_str());
986 if (RT_SUCCESS(vrc))
987 hrc = S_OK;
988 else
989 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3LogModifyFlags failed with %Rrc"), vrc);
990 }
991 return hrc;
992}
993
994HRESULT MachineDebugger::modifyLogGroups(const com::Utf8Str &aSettings)
995{
996 LogFlowThisFunc(("aSettings=%s\n", aSettings.c_str()));
997 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
998 Console::SafeVMPtr ptrVM(mParent);
999 HRESULT hrc = ptrVM.rc();
1000 if (SUCCEEDED(hrc))
1001 {
1002 int vrc = DBGFR3LogModifyGroups(ptrVM.rawUVM(), aSettings.c_str());
1003 if (RT_SUCCESS(vrc))
1004 hrc = S_OK;
1005 else
1006 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3LogModifyGroups failed with %Rrc"), vrc);
1007 }
1008 return hrc;
1009}
1010
1011HRESULT MachineDebugger::modifyLogDestinations(const com::Utf8Str &aSettings)
1012{
1013 LogFlowThisFunc(("aSettings=%s\n", aSettings.c_str()));
1014 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1015 Console::SafeVMPtr ptrVM(mParent);
1016 HRESULT hrc = ptrVM.rc();
1017 if (SUCCEEDED(hrc))
1018 {
1019 int vrc = DBGFR3LogModifyDestinations(ptrVM.rawUVM(), aSettings.c_str());
1020 if (RT_SUCCESS(vrc))
1021 hrc = S_OK;
1022 else
1023 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3LogModifyDestinations failed with %Rrc"), vrc);
1024 }
1025 return hrc;
1026}
1027
1028HRESULT MachineDebugger::readPhysicalMemory(LONG64 aAddress, ULONG aSize, std::vector<BYTE> &aBytes)
1029{
1030 RT_NOREF(aAddress, aSize, aBytes);
1031 ReturnComNotImplemented();
1032}
1033
1034HRESULT MachineDebugger::writePhysicalMemory(LONG64 aAddress, ULONG aSize, const std::vector<BYTE> &aBytes)
1035{
1036 RT_NOREF(aAddress, aSize, aBytes);
1037 ReturnComNotImplemented();
1038}
1039
1040HRESULT MachineDebugger::readVirtualMemory(ULONG aCpuId, LONG64 aAddress, ULONG aSize, std::vector<BYTE> &aBytes)
1041{
1042 RT_NOREF(aCpuId, aAddress, aSize, aBytes);
1043 ReturnComNotImplemented();
1044}
1045
1046HRESULT MachineDebugger::writeVirtualMemory(ULONG aCpuId, LONG64 aAddress, ULONG aSize, const std::vector<BYTE> &aBytes)
1047{
1048 RT_NOREF(aCpuId, aAddress, aSize, aBytes);
1049 ReturnComNotImplemented();
1050}
1051
1052HRESULT MachineDebugger::loadPlugIn(const com::Utf8Str &aName, com::Utf8Str &aPlugInName)
1053{
1054 /*
1055 * Lock the debugger and get the VM pointer
1056 */
1057 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1058 Console::SafeVMPtr ptrVM(mParent);
1059 HRESULT hrc = ptrVM.rc();
1060 if (SUCCEEDED(hrc))
1061 {
1062 /*
1063 * Do the job and try convert the name.
1064 */
1065 if (aName.equals("all"))
1066 {
1067 DBGFR3PlugInLoadAll(ptrVM.rawUVM());
1068 try
1069 {
1070 aPlugInName = "all";
1071 hrc = S_OK;
1072 }
1073 catch (std::bad_alloc &)
1074 {
1075 hrc = E_OUTOFMEMORY;
1076 }
1077 }
1078 else
1079 {
1080 RTERRINFOSTATIC ErrInfo;
1081 char szName[80];
1082 int vrc = DBGFR3PlugInLoad(ptrVM.rawUVM(), aName.c_str(), szName, sizeof(szName), RTErrInfoInitStatic(&ErrInfo));
1083 if (RT_SUCCESS(vrc))
1084 {
1085 try
1086 {
1087 aPlugInName = szName;
1088 hrc = S_OK;
1089 }
1090 catch (std::bad_alloc &)
1091 {
1092 hrc = E_OUTOFMEMORY;
1093 }
1094 }
1095 else
1096 hrc = setErrorVrc(vrc, "%s", ErrInfo.szMsg);
1097 }
1098 }
1099 return hrc;
1100
1101}
1102
1103HRESULT MachineDebugger::unloadPlugIn(const com::Utf8Str &aName)
1104{
1105 /*
1106 * Lock the debugger and get the VM pointer
1107 */
1108 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1109 Console::SafeVMPtr ptrVM(mParent);
1110 HRESULT hrc = ptrVM.rc();
1111 if (SUCCEEDED(hrc))
1112 {
1113 /*
1114 * Do the job and try convert the name.
1115 */
1116 if (aName.equals("all"))
1117 {
1118 DBGFR3PlugInUnloadAll(ptrVM.rawUVM());
1119 hrc = S_OK;
1120 }
1121 else
1122 {
1123 int vrc = DBGFR3PlugInUnload(ptrVM.rawUVM(), aName.c_str());
1124 if (RT_SUCCESS(vrc))
1125 hrc = S_OK;
1126 else if (vrc == VERR_NOT_FOUND)
1127 hrc = setErrorBoth(E_FAIL, vrc, "Plug-in '%s' was not found", aName.c_str());
1128 else
1129 hrc = setErrorVrc(vrc, "Error unloading '%s': %Rrc", aName.c_str(), vrc);
1130 }
1131 }
1132 return hrc;
1133
1134}
1135
1136HRESULT MachineDebugger::detectOS(com::Utf8Str &aOs)
1137{
1138 LogFlowThisFunc(("\n"));
1139
1140 /*
1141 * Lock the debugger and get the VM pointer
1142 */
1143 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1144 Console::SafeVMPtr ptrVM(mParent);
1145 HRESULT hrc = ptrVM.rc();
1146 if (SUCCEEDED(hrc))
1147 {
1148 /*
1149 * Do the job.
1150 */
1151 char szName[64];
1152 int vrc = DBGFR3OSDetect(ptrVM.rawUVM(), szName, sizeof(szName));
1153 if (RT_SUCCESS(vrc) && vrc != VINF_DBGF_OS_NOT_DETCTED)
1154 {
1155 try
1156 {
1157 aOs = szName;
1158 }
1159 catch (std::bad_alloc &)
1160 {
1161 hrc = E_OUTOFMEMORY;
1162 }
1163 }
1164 else
1165 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("DBGFR3OSDetect failed with %Rrc"), vrc);
1166 }
1167 return hrc;
1168}
1169
1170HRESULT MachineDebugger::queryOSKernelLog(ULONG aMaxMessages, com::Utf8Str &aDmesg)
1171{
1172 /*
1173 * Lock the debugger and get the VM pointer
1174 */
1175 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1176 Console::SafeVMPtr ptrVM(mParent);
1177 HRESULT hrc = ptrVM.rc();
1178 if (SUCCEEDED(hrc))
1179 {
1180 PDBGFOSIDMESG pDmesg = (PDBGFOSIDMESG)DBGFR3OSQueryInterface(ptrVM.rawUVM(), DBGFOSINTERFACE_DMESG);
1181 if (pDmesg)
1182 {
1183 size_t cbActual;
1184 size_t cbBuf = _512K;
1185 int vrc = aDmesg.reserveNoThrow(cbBuf);
1186 if (RT_SUCCESS(vrc))
1187 {
1188 uint32_t cMessages = aMaxMessages == 0 ? UINT32_MAX : aMaxMessages;
1189 vrc = pDmesg->pfnQueryKernelLog(pDmesg, ptrVM.rawUVM(), 0 /*fFlags*/, cMessages,
1190 aDmesg.mutableRaw(), cbBuf, &cbActual);
1191
1192 uint32_t cTries = 10;
1193 while (vrc == VERR_BUFFER_OVERFLOW && cbBuf < 16*_1M && cTries-- > 0)
1194 {
1195 cbBuf = RT_ALIGN_Z(cbActual + _4K, _4K);
1196 vrc = aDmesg.reserveNoThrow(cbBuf);
1197 if (RT_SUCCESS(vrc))
1198 vrc = pDmesg->pfnQueryKernelLog(pDmesg, ptrVM.rawUVM(), 0 /*fFlags*/, cMessages,
1199 aDmesg.mutableRaw(), cbBuf, &cbActual);
1200 }
1201 if (RT_SUCCESS(vrc))
1202 aDmesg.jolt();
1203 else if (vrc == VERR_BUFFER_OVERFLOW)
1204 hrc = setError(E_FAIL, "Too much log available, must use the maxMessages parameter to restrict.");
1205 else
1206 hrc = setErrorVrc(vrc);
1207 }
1208 else
1209 hrc = setErrorBoth(E_OUTOFMEMORY, vrc);
1210 }
1211 else
1212 hrc = setError(E_FAIL, "The dmesg interface isn't implemented by guest OS digger, or detectOS() has not been called.");
1213 }
1214 return hrc;
1215}
1216
1217/**
1218 * Formats a register value.
1219 *
1220 * This is used by both register getter methods.
1221 *
1222 * @returns
1223 * @param a_pbstr The output Bstr variable.
1224 * @param a_pValue The value to format.
1225 * @param a_enmType The type of the value.
1226 */
1227DECLINLINE(HRESULT) formatRegisterValue(Bstr *a_pbstr, PCDBGFREGVAL a_pValue, DBGFREGVALTYPE a_enmType)
1228{
1229 char szHex[160];
1230 ssize_t cch = DBGFR3RegFormatValue(szHex, sizeof(szHex), a_pValue, a_enmType, true /*fSpecial*/);
1231 if (RT_UNLIKELY(cch <= 0))
1232 return E_UNEXPECTED;
1233 *a_pbstr = szHex;
1234 return S_OK;
1235}
1236
1237HRESULT MachineDebugger::getRegister(ULONG aCpuId, const com::Utf8Str &aName, com::Utf8Str &aValue)
1238{
1239 /*
1240 * The prologue.
1241 */
1242 LogFlowThisFunc(("\n"));
1243 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1244 Console::SafeVMPtr ptrVM(mParent);
1245 HRESULT hrc = ptrVM.rc();
1246 if (SUCCEEDED(hrc))
1247 {
1248 /*
1249 * Real work.
1250 */
1251 DBGFREGVAL Value;
1252 DBGFREGVALTYPE enmType;
1253 int vrc = DBGFR3RegNmQuery(ptrVM.rawUVM(), aCpuId, aName.c_str(), &Value, &enmType);
1254 if (RT_SUCCESS(vrc))
1255 {
1256 try
1257 {
1258 Bstr bstrValue;
1259 hrc = formatRegisterValue(&bstrValue, &Value, enmType);
1260 if (SUCCEEDED(hrc))
1261 aValue = Utf8Str(bstrValue);
1262 }
1263 catch (std::bad_alloc &)
1264 {
1265 hrc = E_OUTOFMEMORY;
1266 }
1267 }
1268 else if (vrc == VERR_DBGF_REGISTER_NOT_FOUND)
1269 hrc = setErrorBoth(E_FAIL, vrc, tr("Register '%s' was not found"), aName.c_str());
1270 else if (vrc == VERR_INVALID_CPU_ID)
1271 hrc = setErrorBoth(E_FAIL, vrc, tr("Invalid CPU ID: %u"), aCpuId);
1272 else
1273 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc,
1274 tr("DBGFR3RegNmQuery failed with rc=%Rrc querying register '%s' with default cpu set to %u"),
1275 vrc, aName.c_str(), aCpuId);
1276 }
1277
1278 return hrc;
1279}
1280
1281HRESULT MachineDebugger::getRegisters(ULONG aCpuId, std::vector<com::Utf8Str> &aNames, std::vector<com::Utf8Str> &aValues)
1282{
1283 RT_NOREF(aCpuId); /** @todo fix missing aCpuId usage! */
1284
1285 /*
1286 * The prologue.
1287 */
1288 LogFlowThisFunc(("\n"));
1289 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1290 Console::SafeVMPtr ptrVM(mParent);
1291 HRESULT hrc = ptrVM.rc();
1292 if (SUCCEEDED(hrc))
1293 {
1294 /*
1295 * Real work.
1296 */
1297 size_t cRegs;
1298 int vrc = DBGFR3RegNmQueryAllCount(ptrVM.rawUVM(), &cRegs);
1299 if (RT_SUCCESS(vrc))
1300 {
1301 PDBGFREGENTRYNM paRegs = (PDBGFREGENTRYNM)RTMemAllocZ(sizeof(paRegs[0]) * cRegs);
1302 if (paRegs)
1303 {
1304 vrc = DBGFR3RegNmQueryAll(ptrVM.rawUVM(), paRegs, cRegs);
1305 if (RT_SUCCESS(vrc))
1306 {
1307 try
1308 {
1309 aValues.resize(cRegs);
1310 aNames.resize(cRegs);
1311 for (uint32_t iReg = 0; iReg < cRegs; iReg++)
1312 {
1313 char szHex[160];
1314 szHex[159] = szHex[0] = '\0';
1315 ssize_t cch = DBGFR3RegFormatValue(szHex, sizeof(szHex), &paRegs[iReg].Val,
1316 paRegs[iReg].enmType, true /*fSpecial*/);
1317 Assert(cch > 0); NOREF(cch);
1318 aNames[iReg] = Utf8Str(paRegs[iReg].pszName);
1319 aValues[iReg] = Utf8Str(szHex);
1320 }
1321 }
1322 catch (std::bad_alloc &)
1323 {
1324 hrc = E_OUTOFMEMORY;
1325 }
1326 }
1327 else
1328 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3RegNmQueryAll failed with %Rrc"), vrc);
1329
1330 RTMemFree(paRegs);
1331 }
1332 else
1333 hrc = E_OUTOFMEMORY;
1334 }
1335 else
1336 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3RegNmQueryAllCount failed with %Rrc"), vrc);
1337 }
1338 return hrc;
1339}
1340
1341HRESULT MachineDebugger::setRegister(ULONG aCpuId, const com::Utf8Str &aName, const com::Utf8Str &aValue)
1342{
1343 RT_NOREF(aCpuId, aName, aValue);
1344 ReturnComNotImplemented();
1345}
1346
1347HRESULT MachineDebugger::setRegisters(ULONG aCpuId, const std::vector<com::Utf8Str> &aNames,
1348 const std::vector<com::Utf8Str> &aValues)
1349{
1350 RT_NOREF(aCpuId, aNames, aValues);
1351 ReturnComNotImplemented();
1352}
1353
1354HRESULT MachineDebugger::dumpGuestStack(ULONG aCpuId, com::Utf8Str &aStack)
1355{
1356 /*
1357 * The prologue.
1358 */
1359 LogFlowThisFunc(("\n"));
1360 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1361 Console::SafeVMPtr ptrVM(mParent);
1362 HRESULT hrc = ptrVM.rc();
1363 if (SUCCEEDED(hrc))
1364 {
1365 /*
1366 * There is currently a problem with the windows diggers and SMP, where
1367 * guest driver memory is being read from CPU zero in order to ensure that
1368 * we've got a consisten virtual memory view. If one of the other CPUs
1369 * initiates a rendezvous while we're unwinding the stack and trying to
1370 * read guest driver memory, we will deadlock.
1371 *
1372 * So, check the VM state and maybe suspend the VM before we continue.
1373 */
1374 int vrc = VINF_SUCCESS;
1375 bool fPaused = false;
1376 if (aCpuId != 0)
1377 {
1378 VMSTATE enmVmState = VMR3GetStateU(ptrVM.rawUVM());
1379 if ( enmVmState == VMSTATE_RUNNING
1380 || enmVmState == VMSTATE_RUNNING_LS
1381 || enmVmState == VMSTATE_RUNNING_FT)
1382 {
1383 alock.release();
1384 vrc = VMR3Suspend(ptrVM.rawUVM(), VMSUSPENDREASON_USER);
1385 alock.acquire();
1386 fPaused = RT_SUCCESS(vrc);
1387 }
1388 }
1389 if (RT_SUCCESS(vrc))
1390 {
1391 PCDBGFSTACKFRAME pFirstFrame;
1392 vrc = DBGFR3StackWalkBegin(ptrVM.rawUVM(), aCpuId, DBGFCODETYPE_GUEST, &pFirstFrame);
1393 if (RT_SUCCESS(vrc))
1394 {
1395 /*
1396 * Print header.
1397 */
1398 try
1399 {
1400 uint32_t fBitFlags = 0;
1401 for (PCDBGFSTACKFRAME pFrame = pFirstFrame;
1402 pFrame;
1403 pFrame = DBGFR3StackWalkNext(pFrame))
1404 {
1405 uint32_t const fCurBitFlags = pFrame->fFlags & (DBGFSTACKFRAME_FLAGS_16BIT | DBGFSTACKFRAME_FLAGS_32BIT | DBGFSTACKFRAME_FLAGS_64BIT);
1406 if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_16BIT)
1407 {
1408 if (fCurBitFlags != fBitFlags)
1409 aStack.append("SS:BP Ret SS:BP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n");
1410 aStack.append(Utf8StrFmt("%04RX16:%04RX16 %04RX16:%04RX16 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
1411 pFrame->AddrFrame.Sel,
1412 (uint16_t)pFrame->AddrFrame.off,
1413 pFrame->AddrReturnFrame.Sel,
1414 (uint16_t)pFrame->AddrReturnFrame.off,
1415 (uint32_t)pFrame->AddrReturnPC.Sel,
1416 (uint32_t)pFrame->AddrReturnPC.off,
1417 pFrame->Args.au32[0],
1418 pFrame->Args.au32[1],
1419 pFrame->Args.au32[2],
1420 pFrame->Args.au32[3]));
1421 }
1422 else if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_32BIT)
1423 {
1424 if (fCurBitFlags != fBitFlags)
1425 aStack.append("EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n");
1426 aStack.append(Utf8StrFmt("%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
1427 (uint32_t)pFrame->AddrFrame.off,
1428 (uint32_t)pFrame->AddrReturnFrame.off,
1429 (uint32_t)pFrame->AddrReturnPC.Sel,
1430 (uint32_t)pFrame->AddrReturnPC.off,
1431 pFrame->Args.au32[0],
1432 pFrame->Args.au32[1],
1433 pFrame->Args.au32[2],
1434 pFrame->Args.au32[3]));
1435 }
1436 else if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_64BIT)
1437 {
1438 if (fCurBitFlags != fBitFlags)
1439 aStack.append("RBP Ret SS:RBP Ret RIP CS:RIP / Symbol [line]\n");
1440 aStack.append(Utf8StrFmt("%016RX64 %04RX16:%016RX64 %016RX64",
1441 (uint64_t)pFrame->AddrFrame.off,
1442 pFrame->AddrReturnFrame.Sel,
1443 (uint64_t)pFrame->AddrReturnFrame.off,
1444 (uint64_t)pFrame->AddrReturnPC.off));
1445 }
1446
1447 if (!pFrame->pSymPC)
1448 aStack.append(Utf8StrFmt(fCurBitFlags & DBGFSTACKFRAME_FLAGS_64BIT
1449 ? " %RTsel:%016RGv"
1450 : fCurBitFlags & DBGFSTACKFRAME_FLAGS_32BIT
1451 ? " %RTsel:%08RGv"
1452 : " %RTsel:%04RGv"
1453 , pFrame->AddrPC.Sel, pFrame->AddrPC.off));
1454 else
1455 {
1456 RTGCINTPTR offDisp = pFrame->AddrPC.FlatPtr - pFrame->pSymPC->Value; /** @todo this isn't 100% correct for segmented stuff. */
1457 if (offDisp > 0)
1458 aStack.append(Utf8StrFmt(" %s+%llx", pFrame->pSymPC->szName, (int64_t)offDisp));
1459 else if (offDisp < 0)
1460 aStack.append(Utf8StrFmt(" %s-%llx", pFrame->pSymPC->szName, -(int64_t)offDisp));
1461 else
1462 aStack.append(Utf8StrFmt(" %s", pFrame->pSymPC->szName));
1463 }
1464 if (pFrame->pLinePC)
1465 aStack.append(Utf8StrFmt(" [%s @ 0i%d]", pFrame->pLinePC->szFilename, pFrame->pLinePC->uLineNo));
1466 aStack.append(Utf8StrFmt("\n"));
1467
1468 fBitFlags = fCurBitFlags;
1469 }
1470 }
1471 catch (std::bad_alloc &)
1472 {
1473 hrc = E_OUTOFMEMORY;
1474 }
1475
1476 DBGFR3StackWalkEnd(pFirstFrame);
1477 }
1478 else
1479 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3StackWalkBegin failed with %Rrc"), vrc);
1480
1481 /*
1482 * Resume the VM if we suspended it.
1483 */
1484 if (fPaused)
1485 {
1486 alock.release();
1487 VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_USER);
1488 }
1489 }
1490 else
1491 hrc = setErrorBoth(E_FAIL, vrc, tr("Suspending the VM failed with %Rrc\n"), vrc);
1492 }
1493
1494 return hrc;
1495}
1496
1497/**
1498 * Resets VM statistics.
1499 *
1500 * @returns COM status code.
1501 * @param aPattern The selection pattern. A bit similar to filename globbing.
1502 */
1503HRESULT MachineDebugger::resetStats(const com::Utf8Str &aPattern)
1504{
1505 Console::SafeVMPtrQuiet ptrVM(mParent);
1506
1507 if (!ptrVM.isOk())
1508 return setError(VBOX_E_INVALID_VM_STATE, "Machine is not running");
1509
1510 STAMR3Reset(ptrVM.rawUVM(), aPattern.c_str());
1511
1512 return S_OK;
1513}
1514
1515/**
1516 * Dumps VM statistics to the log.
1517 *
1518 * @returns COM status code.
1519 * @param aPattern The selection pattern. A bit similar to filename globbing.
1520 */
1521HRESULT MachineDebugger::dumpStats(const com::Utf8Str &aPattern)
1522{
1523 Console::SafeVMPtrQuiet ptrVM(mParent);
1524
1525 if (!ptrVM.isOk())
1526 return setError(VBOX_E_INVALID_VM_STATE, "Machine is not running");
1527
1528 STAMR3Dump(ptrVM.rawUVM(), aPattern.c_str());
1529
1530 return S_OK;
1531}
1532
1533/**
1534 * Get the VM statistics in an XML format.
1535 *
1536 * @returns COM status code.
1537 * @param aPattern The selection pattern. A bit similar to filename globbing.
1538 * @param aWithDescriptions Whether to include the descriptions.
1539 * @param aStats The XML document containing the statistics.
1540 */
1541HRESULT MachineDebugger::getStats(const com::Utf8Str &aPattern, BOOL aWithDescriptions, com::Utf8Str &aStats)
1542{
1543 Console::SafeVMPtrQuiet ptrVM(mParent);
1544
1545 if (!ptrVM.isOk())
1546 return setError(VBOX_E_INVALID_VM_STATE, "Machine is not running");
1547
1548 char *pszSnapshot;
1549 int vrc = STAMR3Snapshot(ptrVM.rawUVM(), aPattern.c_str(), &pszSnapshot, NULL,
1550 !!aWithDescriptions);
1551 if (RT_FAILURE(vrc))
1552 return vrc == VERR_NO_MEMORY ? E_OUTOFMEMORY : E_FAIL;
1553
1554 /** @todo this is horribly inefficient! And it's kinda difficult to tell whether it failed...
1555 * Must use UTF-8 or ASCII here and completely avoid these two extra copy operations.
1556 * Until that's done, this method is kind of useless for debugger statistics GUI because
1557 * of the amount statistics in a debug build. */
1558 aStats = Utf8Str(pszSnapshot);
1559 STAMR3SnapshotFree(ptrVM.rawUVM(), pszSnapshot);
1560
1561 return S_OK;
1562}
1563
1564
1565// public methods only for internal purposes
1566/////////////////////////////////////////////////////////////////////////////
1567
1568void MachineDebugger::i_flushQueuedSettings()
1569{
1570 mFlushMode = true;
1571 if (mSingleStepQueued != -1)
1572 {
1573 COMSETTER(SingleStep)(mSingleStepQueued);
1574 mSingleStepQueued = -1;
1575 }
1576 for (unsigned i = 0; i < EMEXECPOLICY_END; i++)
1577 if (maiQueuedEmExecPolicyParams[i] != UINT8_MAX)
1578 {
1579 i_setEmExecPolicyProperty((EMEXECPOLICY)i, RT_BOOL(maiQueuedEmExecPolicyParams[i]));
1580 maiQueuedEmExecPolicyParams[i] = UINT8_MAX;
1581 }
1582 if (mPatmEnabledQueued != -1)
1583 {
1584 COMSETTER(PATMEnabled)(mPatmEnabledQueued);
1585 mPatmEnabledQueued = -1;
1586 }
1587 if (mCsamEnabledQueued != -1)
1588 {
1589 COMSETTER(CSAMEnabled)(mCsamEnabledQueued);
1590 mCsamEnabledQueued = -1;
1591 }
1592 if (mLogEnabledQueued != -1)
1593 {
1594 COMSETTER(LogEnabled)(mLogEnabledQueued);
1595 mLogEnabledQueued = -1;
1596 }
1597 if (mVirtualTimeRateQueued != UINT32_MAX)
1598 {
1599 COMSETTER(VirtualTimeRate)(mVirtualTimeRateQueued);
1600 mVirtualTimeRateQueued = UINT32_MAX;
1601 }
1602 mFlushMode = false;
1603}
1604
1605// private methods
1606/////////////////////////////////////////////////////////////////////////////
1607
1608bool MachineDebugger::i_queueSettings() const
1609{
1610 if (!mFlushMode)
1611 {
1612 // check if the machine is running
1613 MachineState_T machineState;
1614 mParent->COMGETTER(State)(&machineState);
1615 switch (machineState)
1616 {
1617 // queue the request
1618 default:
1619 return true;
1620
1621 case MachineState_Running:
1622 case MachineState_Paused:
1623 case MachineState_Stuck:
1624 case MachineState_LiveSnapshotting:
1625 case MachineState_Teleporting:
1626 break;
1627 }
1628 }
1629 return false;
1630}
1631/* 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