VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGF.cpp@ 101111

Last change on this file since 101111 was 100144, checked in by vboxsync, 18 months ago

VMM/EM: Renamed VINF_EM_RESCHEDULE_HM to VINF_EM_RESCHEDULE_EXEC_ENGINE and made the outer EM loop check if NEM can execute the current CPU state before changing the state to NEM. Removed VINF_EM_RESCHEDULE_RAW and VINF_EM_RESCHEDULE_PARAV. bugref:10369

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 77.2 KB
Line 
1/* $Id: DBGF.cpp 100144 2023-06-09 15:39:42Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/** @page pg_dbgf DBGF - The Debugger Facility
30 *
31 * The purpose of the DBGF is to provide an interface for debuggers to
32 * manipulate the VMM without having to mess up the source code for each of
33 * them. The DBGF is always built in and will always work when a debugger
34 * attaches to the VM. The DBGF provides the basic debugger features, such as
35 * halting execution, handling breakpoints, single step execution, instruction
36 * disassembly, info querying, OS specific diggers, symbol and module
37 * management.
38 *
39 * The interface is working in a manner similar to the win32, linux and os2
40 * debugger interfaces. The interface has an asynchronous nature. This comes
41 * from the fact that the VMM and the Debugger are running in different threads.
42 * They are referred to as the "emulation thread" and the "debugger thread", or
43 * as the "ping thread" and the "pong thread, respectivly. (The last set of
44 * names comes from the use of the Ping-Pong synchronization construct from the
45 * RTSem API.)
46 *
47 * @see grp_dbgf
48 *
49 *
50 * @section sec_dbgf_scenario Usage Scenario
51 *
52 * The debugger starts by attaching to the VM. For practical reasons we limit the
53 * number of concurrently attached debuggers to 1 per VM. The action of
54 * attaching to the VM causes the VM to check and generate debug events.
55 *
56 * The debugger then will wait/poll for debug events and issue commands.
57 *
58 * The waiting and polling is done by the DBGFEventWait() function. It will wait
59 * for the emulation thread to send a ping, thus indicating that there is an
60 * event waiting to be processed.
61 *
62 * An event can be a response to a command issued previously, the hitting of a
63 * breakpoint, or running into a bad/fatal VMM condition. The debugger now has
64 * the ping and must respond to the event at hand - the VMM is waiting. This
65 * usually means that the user of the debugger must do something, but it doesn't
66 * have to. The debugger is free to call any DBGF function (nearly at least)
67 * while processing the event.
68 *
69 * Typically the user will issue a request for the execution to be resumed, so
70 * the debugger calls DBGFResume() and goes back to waiting/polling for events.
71 *
72 * When the user eventually terminates the debugging session or selects another
73 * VM, the debugger detaches from the VM. This means that breakpoints are
74 * disabled and that the emulation thread no longer polls for debugger commands.
75 *
76 */
77
78
79/*********************************************************************************************************************************
80* Header Files *
81*********************************************************************************************************************************/
82#define LOG_GROUP LOG_GROUP_DBGF
83#include <VBox/vmm/dbgf.h>
84#include <VBox/vmm/selm.h>
85#include <VBox/vmm/em.h>
86#include <VBox/vmm/hm.h>
87#include <VBox/vmm/mm.h>
88#include <VBox/vmm/nem.h>
89#include "DBGFInternal.h"
90#include <VBox/vmm/vm.h>
91#include <VBox/vmm/uvm.h>
92#include <VBox/err.h>
93
94#include <VBox/log.h>
95#include <iprt/semaphore.h>
96#include <iprt/thread.h>
97#include <iprt/asm.h>
98#include <iprt/time.h>
99#include <iprt/assert.h>
100#include <iprt/stream.h>
101#include <iprt/env.h>
102
103
104/*********************************************************************************************************************************
105* Structures and Typedefs *
106*********************************************************************************************************************************/
107/**
108 * Instruction type returned by dbgfStepGetCurInstrType.
109 */
110typedef enum DBGFSTEPINSTRTYPE
111{
112 DBGFSTEPINSTRTYPE_INVALID = 0,
113 DBGFSTEPINSTRTYPE_OTHER,
114 DBGFSTEPINSTRTYPE_RET,
115 DBGFSTEPINSTRTYPE_CALL,
116 DBGFSTEPINSTRTYPE_END,
117 DBGFSTEPINSTRTYPE_32BIT_HACK = 0x7fffffff
118} DBGFSTEPINSTRTYPE;
119
120
121/*********************************************************************************************************************************
122* Internal Functions *
123*********************************************************************************************************************************/
124DECLINLINE(int) dbgfR3SendEventWait(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmType, DBGFEVENTCTX enmCtx);
125DECLINLINE(DBGFCMD) dbgfR3CpuGetCmd(PUVMCPU pUVCpu);
126static int dbgfR3CpuWait(PVMCPU pVCpu);
127static int dbgfR3CpuCmd(PVMCPU pVCpu, DBGFCMD enmCmd, PDBGFCMDDATA pCmdData, bool *pfResumeExecution);
128static DBGFSTEPINSTRTYPE dbgfStepGetCurInstrType(PVM pVM, PVMCPU pVCpu);
129static bool dbgfStepAreWeThereYet(PVM pVM, PVMCPU pVCpu);
130static int dbgfR3EventHaltAllVCpus(PVM pVM, PVMCPU pVCpuExclude);
131
132
133
134/**
135 * Initializes the DBGF.
136 *
137 * @returns VBox status code.
138 * @param pVM The cross context VM structure.
139 */
140VMMR3_INT_DECL(int) DBGFR3Init(PVM pVM)
141{
142 PUVM pUVM = pVM->pUVM;
143 AssertCompile(sizeof(pUVM->dbgf.s) <= sizeof(pUVM->dbgf.padding));
144 AssertCompile(sizeof(pUVM->aCpus[0].dbgf.s) <= sizeof(pUVM->aCpus[0].dbgf.padding));
145
146 pVM->dbgf.s.SteppingFilter.idCpu = NIL_VMCPUID;
147
148 /*
149 * The usual sideways mountain climbing style of init:
150 */
151 int rc = dbgfR3InfoInit(pUVM); /* (First, initalizes the shared critical section.) */
152 if (RT_SUCCESS(rc))
153 {
154 rc = dbgfR3TraceInit(pVM);
155 if (RT_SUCCESS(rc))
156 {
157 rc = dbgfR3RegInit(pUVM);
158 if (RT_SUCCESS(rc))
159 {
160 rc = dbgfR3AsInit(pUVM);
161 if (RT_SUCCESS(rc))
162 {
163 rc = dbgfR3BpInit(pUVM);
164 if (RT_SUCCESS(rc))
165 {
166 rc = dbgfR3OSInit(pUVM);
167 if (RT_SUCCESS(rc))
168 {
169 rc = dbgfR3PlugInInit(pUVM);
170 if (RT_SUCCESS(rc))
171 {
172 rc = dbgfR3BugCheckInit(pVM);
173 if (RT_SUCCESS(rc))
174 {
175#ifdef VBOX_WITH_DBGF_TRACING
176 rc = dbgfR3TracerInit(pVM);
177#endif
178 if (RT_SUCCESS(rc))
179 {
180 return VINF_SUCCESS;
181 }
182 }
183 dbgfR3PlugInTerm(pUVM);
184 }
185 dbgfR3OSTermPart1(pUVM);
186 dbgfR3OSTermPart2(pUVM);
187 }
188 dbgfR3BpTerm(pUVM);
189 }
190 dbgfR3AsTerm(pUVM);
191 }
192 dbgfR3RegTerm(pUVM);
193 }
194 dbgfR3TraceTerm(pVM);
195 }
196 dbgfR3InfoTerm(pUVM);
197 }
198 return rc;
199}
200
201
202/**
203 * Terminates and cleans up resources allocated by the DBGF.
204 *
205 * @returns VBox status code.
206 * @param pVM The cross context VM structure.
207 */
208VMMR3_INT_DECL(int) DBGFR3Term(PVM pVM)
209{
210 PUVM pUVM = pVM->pUVM;
211
212#ifdef VBOX_WITH_DBGF_TRACING
213 dbgfR3TracerTerm(pVM);
214#endif
215 dbgfR3OSTermPart1(pUVM);
216 dbgfR3PlugInTerm(pUVM);
217 dbgfR3OSTermPart2(pUVM);
218 dbgfR3BpTerm(pUVM);
219 dbgfR3AsTerm(pUVM);
220 dbgfR3RegTerm(pUVM);
221 dbgfR3TraceTerm(pVM);
222 dbgfR3InfoTerm(pUVM);
223
224 return VINF_SUCCESS;
225}
226
227
228/**
229 * This is for tstCFGM and others to avoid trigger leak detection.
230 *
231 * @param pUVM The user mode VM structure.
232 */
233VMMR3DECL(void) DBGFR3TermUVM(PUVM pUVM)
234{
235 dbgfR3InfoTerm(pUVM);
236}
237
238
239/**
240 * Called when the VM is powered off to detach debuggers.
241 *
242 * @param pVM The cross context VM structure.
243 */
244VMMR3_INT_DECL(void) DBGFR3PowerOff(PVM pVM)
245{
246 /*
247 * Send a termination event to any attached debugger.
248 */
249 if (pVM->dbgf.s.fAttached)
250 {
251 PVMCPU pVCpu = VMMGetCpu(pVM);
252 int rc = dbgfR3SendEventWait(pVM, pVCpu, DBGFEVENT_POWERING_OFF, DBGFEVENTCTX_OTHER);
253 AssertLogRelRC(rc);
254
255 /*
256 * Clear the FF so we won't get confused later on.
257 */
258 VM_FF_CLEAR(pVM, VM_FF_DBGF);
259 }
260}
261
262
263/**
264 * Applies relocations to data and code managed by this
265 * component. This function will be called at init and
266 * whenever the VMM need to relocate it self inside the GC.
267 *
268 * @param pVM The cross context VM structure.
269 * @param offDelta Relocation delta relative to old location.
270 */
271VMMR3_INT_DECL(void) DBGFR3Relocate(PVM pVM, RTGCINTPTR offDelta)
272{
273 dbgfR3TraceRelocate(pVM);
274 dbgfR3AsRelocate(pVM->pUVM, offDelta);
275}
276
277
278/**
279 * Waits a little while for a debuggger to attach.
280 *
281 * @returns True is a debugger have attached.
282 * @param pVM The cross context VM structure.
283 * @param pVCpu The cross context per CPU structure.
284 * @param enmEvent Event.
285 *
286 * @thread EMT(pVCpu)
287 */
288static bool dbgfR3WaitForAttach(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmEvent)
289{
290 /*
291 * First a message.
292 */
293#if !defined(DEBUG)
294 int cWait = 10;
295#else
296 int cWait = RTEnvExist("VBOX_DBGF_NO_WAIT_FOR_ATTACH")
297 || ( ( enmEvent == DBGFEVENT_ASSERTION_HYPER
298 || enmEvent == DBGFEVENT_FATAL_ERROR)
299 && !RTEnvExist("VBOX_DBGF_WAIT_FOR_ATTACH"))
300 ? 10
301 : 150;
302#endif
303 RTStrmPrintf(g_pStdErr,
304 "DBGF: No debugger attached, waiting %d second%s for one to attach (event=%d)\n"
305#ifdef DEBUG
306 " Set VBOX_DBGF_NO_WAIT_FOR_ATTACH=1 for short wait or VBOX_DBGF_WAIT_FOR_ATTACH=1 longer.\n"
307#endif
308 ,
309 cWait / 10, cWait != 10 ? "s" : "", enmEvent);
310 RTStrmFlush(g_pStdErr);
311 while (cWait > 0)
312 {
313 RTThreadSleep(100);
314 if (pVM->dbgf.s.fAttached)
315 {
316 RTStrmPrintf(g_pStdErr, "Attached!\n");
317 RTStrmFlush(g_pStdErr);
318 return true;
319 }
320
321 /* Process rendezvous (debugger attaching involves such). */
322 if (VM_FF_IS_SET(pVM, VM_FF_EMT_RENDEZVOUS))
323 {
324 int rc = VMMR3EmtRendezvousFF(pVM, pVCpu); AssertRC(rc);
325 if (rc != VINF_SUCCESS)
326 {
327 /** @todo Ignoring these could be bad. */
328 RTStrmPrintf(g_pStdErr, "[rcRendezvous=%Rrc, ignored!]", rc);
329 RTStrmFlush(g_pStdErr);
330 }
331 }
332
333 /* Process priority stuff. */
334 if ( VM_FF_IS_SET(pVM, VM_FF_REQUEST)
335 || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_REQUEST))
336 {
337 int rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY, true /*fPriorityOnly*/);
338 if (rc == VINF_SUCCESS)
339 rc = VMR3ReqProcessU(pVM->pUVM, pVCpu->idCpu, true /*fPriorityOnly*/);
340 if (rc != VINF_SUCCESS)
341 {
342 /** @todo Ignoring these could be bad. */
343 RTStrmPrintf(g_pStdErr, "[rcReq=%Rrc, ignored!]", rc);
344 RTStrmFlush(g_pStdErr);
345 }
346 }
347
348 /* next */
349 if (!(cWait % 10))
350 {
351 RTStrmPrintf(g_pStdErr, "%d.", cWait / 10);
352 RTStrmFlush(g_pStdErr);
353 }
354 cWait--;
355 }
356
357 RTStrmPrintf(g_pStdErr, "Stopping the VM!\n");
358 RTStrmFlush(g_pStdErr);
359 return false;
360}
361
362
363/**
364 * Forced action callback.
365 *
366 * The VMM will call this from it's main loop when either VM_FF_DBGF or
367 * VMCPU_FF_DBGF are set.
368 *
369 * The function checks for and executes pending commands from the debugger.
370 * Then it checks for pending debug events and serves these.
371 *
372 * @returns VINF_SUCCESS normally.
373 * @returns VERR_DBGF_RAISE_FATAL_ERROR to pretend a fatal error happened.
374 * @param pVM The cross context VM structure.
375 * @param pVCpu The cross context per CPU structure.
376 */
377VMMR3_INT_DECL(int) DBGFR3VMMForcedAction(PVM pVM, PVMCPU pVCpu)
378{
379 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
380
381 /*
382 * Dispatch pending events.
383 */
384 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_DBGF))
385 {
386 if ( pVCpu->dbgf.s.cEvents > 0
387 && pVCpu->dbgf.s.aEvents[pVCpu->dbgf.s.cEvents - 1].enmState == DBGFEVENTSTATE_CURRENT)
388 {
389 rcStrict = DBGFR3EventHandlePending(pVM, pVCpu);
390 /** @todo may end up with VERR_DBGF_NOT_ATTACHED here, which will prove fatal... */
391 }
392
393 /*
394 * Command pending? Process it.
395 */
396 PUVMCPU pUVCpu = pVCpu->pUVCpu;
397 if (pUVCpu->dbgf.s.enmDbgfCmd != DBGFCMD_NO_COMMAND)
398 {
399 bool fResumeExecution;
400 DBGFCMDDATA CmdData = pUVCpu->dbgf.s.DbgfCmdData;
401 DBGFCMD enmCmd = dbgfR3CpuGetCmd(pUVCpu);
402 VBOXSTRICTRC rcStrict2 = dbgfR3CpuCmd(pVCpu, enmCmd, &CmdData, &fResumeExecution);
403 if (!fResumeExecution)
404 rcStrict2 = dbgfR3CpuWait(pVCpu);
405 if ( rcStrict2 != VINF_SUCCESS
406 && ( rcStrict == VINF_SUCCESS
407 || RT_FAILURE(rcStrict2)
408 || rcStrict2 < rcStrict) ) /** @todo oversimplified? */
409 rcStrict = rcStrict2;
410 }
411 }
412
413 return VBOXSTRICTRC_TODO(rcStrict);
414}
415
416
417/**
418 * Try to determine the event context.
419 *
420 * @returns debug event context.
421 * @param pVCpu The cross context vCPU structure.
422 */
423static DBGFEVENTCTX dbgfR3FigureEventCtx(PVMCPU pVCpu)
424{
425 switch (EMGetState(pVCpu))
426 {
427 case EMSTATE_HM:
428 case EMSTATE_NEM:
429 case EMSTATE_DEBUG_GUEST_HM:
430 case EMSTATE_DEBUG_GUEST_NEM:
431 return DBGFEVENTCTX_HM;
432
433 case EMSTATE_IEM:
434 case EMSTATE_DEBUG_GUEST_IEM:
435 case EMSTATE_DEBUG_GUEST_RAW:
436 return DBGFEVENTCTX_RAW;
437
438
439 case EMSTATE_RECOMPILER:
440 case EMSTATE_DEBUG_GUEST_RECOMPILER:
441 return DBGFEVENTCTX_REM;
442
443 case EMSTATE_DEBUG_HYPER:
444 case EMSTATE_GURU_MEDITATION:
445 return DBGFEVENTCTX_HYPER;
446
447 default:
448 return DBGFEVENTCTX_OTHER;
449 }
450}
451
452
453/**
454 * Sends the event to the debugger (i.e. adds it to the event ring buffer).
455 *
456 * @returns VBox status code.
457 * @param pVM The cross context VM structure.
458 * @param pVCpu The CPU sending the event.
459 * @param enmType The event type to send.
460 * @param enmCtx The event context, DBGFEVENTCTX_INVALID will be resolved.
461 * @param pvPayload Event payload (DBGFEVENT::u data), optional.
462 * @param cbPayload The size of the event payload, optional.
463 */
464static int dbgfR3SendEventWorker(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmType, DBGFEVENTCTX enmCtx,
465 void const *pvPayload, size_t cbPayload)
466{
467 PUVM pUVM = pVM->pUVM;
468 pVM->dbgf.s.SteppingFilter.idCpu = NIL_VMCPUID; /** @todo per vCPU stepping filter. */
469
470 /*
471 * Massage the input a little.
472 */
473 AssertStmt(cbPayload <= RT_SIZEOFMEMB(DBGFEVENT, u), cbPayload = RT_SIZEOFMEMB(DBGFEVENT, u));
474 if (enmCtx == DBGFEVENTCTX_INVALID)
475 enmCtx = dbgfR3FigureEventCtx(pVCpu);
476
477 /*
478 * Put the event into the ring buffer.
479 */
480 RTSemFastMutexRequest(pUVM->dbgf.s.hMtxDbgEvtWr);
481
482 uint32_t const cDbgEvtMax = RT_MAX(1, pUVM->dbgf.s.cDbgEvtMax);
483 uint32_t const idxDbgEvtWrite = ASMAtomicReadU32(&pUVM->dbgf.s.idxDbgEvtWrite);
484 uint32_t const idxDbgEvtRead = ASMAtomicReadU32(&pUVM->dbgf.s.idxDbgEvtRead);
485 /** @todo Handle full buffer. */ RT_NOREF(idxDbgEvtRead);
486
487 PDBGFEVENT pEvent = &pUVM->dbgf.s.paDbgEvts[idxDbgEvtWrite % cDbgEvtMax];
488
489#ifdef DEBUG
490 ASMMemFill32(pEvent, sizeof(*pEvent), UINT32_C(0xdeadbeef));
491#endif
492 pEvent->enmType = enmType;
493 pEvent->enmCtx = enmCtx;
494 pEvent->idCpu = pVCpu->idCpu;
495 pEvent->uReserved = 0;
496 if (cbPayload)
497 memcpy(&pEvent->u, pvPayload, cbPayload);
498
499 ASMAtomicWriteU32(&pUVM->dbgf.s.idxDbgEvtWrite, (idxDbgEvtWrite + 1) % cDbgEvtMax);
500
501 RTSemFastMutexRelease(pUVM->dbgf.s.hMtxDbgEvtWr);
502
503 /*
504 * Signal the debugger.
505 */
506 return RTSemEventSignal(pUVM->dbgf.s.hEvtWait);
507}
508
509
510/**
511 * Send event and wait for the debugger to respond.
512 *
513 * @returns Strict VBox status code.
514 * @param pVM The cross context VM structure.
515 * @param pVCpu The CPU sending the event.
516 * @param enmType The event type to send.
517 * @param enmCtx The event context, DBGFEVENTCTX_INVALID will be resolved.
518 */
519DECLINLINE(int) dbgfR3SendEventWait(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmType, DBGFEVENTCTX enmCtx)
520{
521 int rc = dbgfR3SendEventWorker(pVM, pVCpu, enmType, enmCtx, NULL, 0);
522 if (RT_SUCCESS(rc))
523 rc = dbgfR3CpuWait(pVCpu);
524 return rc;
525}
526
527
528/**
529 * Send event and wait for the debugger to respond, extended version.
530 *
531 * @returns Strict VBox status code.
532 * @param pVM The cross context VM structure.
533 * @param pVCpu The CPU sending the event.
534 * @param enmType The event type to send.
535 * @param enmCtx The event context, DBGFEVENTCTX_INVALID will be resolved.
536 * @param pvPayload Event payload (DBGFEVENT::u data), optional.
537 * @param cbPayload The size of the event payload, optional.
538 */
539DECLINLINE(int) dbgfR3SendEventWaitEx(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmType, DBGFEVENTCTX enmCtx,
540 void const *pvPayload, size_t cbPayload)
541{
542 int rc = dbgfR3SendEventWorker(pVM, pVCpu, enmType, enmCtx, pvPayload, cbPayload);
543 if (RT_SUCCESS(rc))
544 rc = dbgfR3CpuWait(pVCpu);
545 return rc;
546}
547
548
549/**
550 * Send event but do NOT wait for the debugger.
551 *
552 * Currently only used by dbgfR3CpuCmd().
553 *
554 * @param pVM The cross context VM structure.
555 * @param pVCpu The CPU sending the event.
556 * @param enmType The event type to send.
557 * @param enmCtx The event context, DBGFEVENTCTX_INVALID will be resolved.
558 */
559DECLINLINE(int) dbgfR3SendEventNoWait(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmType, DBGFEVENTCTX enmCtx)
560{
561 return dbgfR3SendEventWorker(pVM, pVCpu, enmType, enmCtx, NULL, 0);
562}
563
564
565/**
566 * The common event prologue code.
567 *
568 * It will make sure someone is attached, and perhaps process any high priority
569 * pending actions (none yet).
570 *
571 * @returns VBox status code.
572 * @param pVM The cross context VM structure.
573 * @param pVCpu The vCPU cross context structure.
574 * @param enmEvent The event to be sent.
575 */
576static int dbgfR3EventPrologue(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmEvent)
577{
578 /*
579 * Check if a debugger is attached.
580 */
581 if ( !pVM->dbgf.s.fAttached
582 && !dbgfR3WaitForAttach(pVM, pVCpu, enmEvent))
583 {
584 Log(("dbgfR3EventPrologue: enmEvent=%d - debugger not attached\n", enmEvent));
585 return VERR_DBGF_NOT_ATTACHED;
586 }
587
588 /*
589 * Look thru pending commands and finish those which make sense now.
590 */
591 /** @todo Process/purge pending commands. */
592 //int rc = DBGFR3VMMForcedAction(pVM);
593 return VINF_SUCCESS;
594}
595
596
597/**
598 * Processes a pending event on the current CPU.
599 *
600 * This is called by EM in response to VINF_EM_DBG_EVENT.
601 *
602 * @returns Strict VBox status code.
603 * @param pVM The cross context VM structure.
604 * @param pVCpu The cross context per CPU structure.
605 *
606 * @thread EMT(pVCpu)
607 */
608VMMR3_INT_DECL(VBOXSTRICTRC) DBGFR3EventHandlePending(PVM pVM, PVMCPU pVCpu)
609{
610 VMCPU_ASSERT_EMT(pVCpu);
611 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_DBGF);
612
613 /*
614 * Check that we've got an event first.
615 */
616 AssertReturn(pVCpu->dbgf.s.cEvents > 0, VINF_SUCCESS);
617 AssertReturn(pVCpu->dbgf.s.aEvents[pVCpu->dbgf.s.cEvents - 1].enmState == DBGFEVENTSTATE_CURRENT, VINF_SUCCESS);
618 PDBGFEVENT pEvent = &pVCpu->dbgf.s.aEvents[pVCpu->dbgf.s.cEvents - 1].Event;
619
620 /*
621 * Make sure we've got a debugger and is allowed to speak to it.
622 */
623 int rc = dbgfR3EventPrologue(pVM, pVCpu, pEvent->enmType);
624 if (RT_FAILURE(rc))
625 {
626 /** @todo drop them events? */
627 return rc; /** @todo this will cause trouble if we're here via an FF! */
628 }
629
630 /*
631 * Send the event and mark it as ignore.
632 * ASSUMES no new events get generate while dbgfR3CpuWait is executing!
633 */
634 VBOXSTRICTRC rcStrict = dbgfR3SendEventWaitEx(pVM, pVCpu, pEvent->enmType, pEvent->enmCtx, &pEvent->u, sizeof(pEvent->u));
635 pVCpu->dbgf.s.aEvents[pVCpu->dbgf.s.cEvents - 1].enmState = DBGFEVENTSTATE_IGNORE;
636 return rcStrict;
637}
638
639
640/**
641 * Send a generic debugger event which takes no data.
642 *
643 * @returns VBox status code.
644 * @param pVM The cross context VM structure.
645 * @param enmEvent The event to send.
646 * @internal
647 */
648VMMR3DECL(int) DBGFR3Event(PVM pVM, DBGFEVENTTYPE enmEvent)
649{
650 PVMCPU pVCpu = VMMGetCpu(pVM);
651 AssertReturn(pVCpu, VERR_VM_THREAD_NOT_EMT);
652
653 /*
654 * Do stepping filtering.
655 */
656 /** @todo Would be better if we did some of this inside the execution
657 * engines. */
658 if ( enmEvent == DBGFEVENT_STEPPED
659 || enmEvent == DBGFEVENT_STEPPED_HYPER)
660 {
661 if (!dbgfStepAreWeThereYet(pVM, pVCpu))
662 return VINF_EM_DBG_STEP;
663 }
664
665 int rc = dbgfR3EventPrologue(pVM, pVCpu, enmEvent);
666 if (RT_FAILURE(rc))
667 return rc;
668
669 /*
670 * Send the event and process the reply communication.
671 */
672 return dbgfR3SendEventWait(pVM, pVCpu, enmEvent, DBGFEVENTCTX_INVALID);
673}
674
675
676/**
677 * Send a debugger event which takes the full source file location.
678 *
679 * @returns VBox status code.
680 * @param pVM The cross context VM structure.
681 * @param enmEvent The event to send.
682 * @param pszFile Source file.
683 * @param uLine Line number in source file.
684 * @param pszFunction Function name.
685 * @param pszFormat Message which accompanies the event.
686 * @param ... Message arguments.
687 * @internal
688 */
689VMMR3DECL(int) DBGFR3EventSrc(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, const char *pszFunction, const char *pszFormat, ...)
690{
691 va_list args;
692 va_start(args, pszFormat);
693 int rc = DBGFR3EventSrcV(pVM, enmEvent, pszFile, uLine, pszFunction, pszFormat, args);
694 va_end(args);
695 return rc;
696}
697
698
699/**
700 * Send a debugger event which takes the full source file location.
701 *
702 * @returns VBox status code.
703 * @param pVM The cross context VM structure.
704 * @param enmEvent The event to send.
705 * @param pszFile Source file.
706 * @param uLine Line number in source file.
707 * @param pszFunction Function name.
708 * @param pszFormat Message which accompanies the event.
709 * @param args Message arguments.
710 * @internal
711 */
712VMMR3DECL(int) DBGFR3EventSrcV(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, const char *pszFunction, const char *pszFormat, va_list args)
713{
714 PVMCPU pVCpu = VMMGetCpu(pVM);
715 AssertReturn(pVCpu, VERR_VM_THREAD_NOT_EMT);
716
717 int rc = dbgfR3EventPrologue(pVM, pVCpu, enmEvent);
718 if (RT_FAILURE(rc))
719 return rc;
720
721 /*
722 * Format the message.
723 */
724 char *pszMessage = NULL;
725 char szMessage[8192];
726 if (pszFormat && *pszFormat)
727 {
728 pszMessage = &szMessage[0];
729 RTStrPrintfV(szMessage, sizeof(szMessage), pszFormat, args);
730 }
731
732 /*
733 * Send the event and process the reply communication.
734 */
735 DBGFEVENT DbgEvent; /** @todo split up DBGFEVENT so we can skip the dead wait on the stack? */
736 DbgEvent.u.Src.pszFile = pszFile;
737 DbgEvent.u.Src.uLine = uLine;
738 DbgEvent.u.Src.pszFunction = pszFunction;
739 DbgEvent.u.Src.pszMessage = pszMessage;
740 return dbgfR3SendEventWaitEx(pVM, pVCpu, enmEvent, DBGFEVENTCTX_INVALID, &DbgEvent.u, sizeof(DbgEvent.u.Src));
741}
742
743
744/**
745 * Send a debugger event which takes the two assertion messages.
746 *
747 * @returns VBox status code.
748 * @param pVM The cross context VM structure.
749 * @param enmEvent The event to send.
750 * @param pszMsg1 First assertion message.
751 * @param pszMsg2 Second assertion message.
752 */
753VMMR3_INT_DECL(int) DBGFR3EventAssertion(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszMsg1, const char *pszMsg2)
754{
755 PVMCPU pVCpu = VMMGetCpu(pVM);
756 AssertReturn(pVCpu, VERR_VM_THREAD_NOT_EMT);
757
758 int rc = dbgfR3EventPrologue(pVM, pVCpu, enmEvent);
759 if (RT_FAILURE(rc))
760 return rc;
761
762 /*
763 * Send the event and process the reply communication.
764 */
765 DBGFEVENT DbgEvent;
766 DbgEvent.u.Assert.pszMsg1 = pszMsg1;
767 DbgEvent.u.Assert.pszMsg2 = pszMsg2;
768 return dbgfR3SendEventWaitEx(pVM, pVCpu, enmEvent, DBGFEVENTCTX_INVALID, &DbgEvent.u, sizeof(DbgEvent.u.Assert));
769}
770
771
772/**
773 * Breakpoint was hit somewhere.
774 * Figure out which breakpoint it is and notify the debugger.
775 *
776 * @returns VBox status code.
777 * @param pVM The cross context VM structure.
778 * @param enmEvent DBGFEVENT_BREAKPOINT_HYPER or DBGFEVENT_BREAKPOINT.
779 */
780VMMR3_INT_DECL(int) DBGFR3EventBreakpoint(PVM pVM, DBGFEVENTTYPE enmEvent)
781{
782 PVMCPU pVCpu = VMMGetCpu(pVM);
783 AssertReturn(pVCpu, VERR_VM_THREAD_NOT_EMT);
784
785 int rc = dbgfR3EventPrologue(pVM, pVCpu, enmEvent);
786 if (RT_FAILURE(rc))
787 return rc;
788
789 /*
790 * Halt all other vCPUs as well to give the user the ability to inspect other
791 * vCPU states as well.
792 */
793 rc = dbgfR3EventHaltAllVCpus(pVM, pVCpu);
794 if (RT_FAILURE(rc))
795 return rc;
796
797 /*
798 * Send the event and process the reply communication.
799 */
800 DBGFEVENT DbgEvent;
801 DbgEvent.u.Bp.hBp = pVCpu->dbgf.s.hBpActive;
802 pVCpu->dbgf.s.hBpActive = NIL_DBGFBP;
803 if (DbgEvent.u.Bp.hBp != NIL_DBGFBP)
804 {
805 DbgEvent.enmCtx = DBGFEVENTCTX_RAW;
806 return dbgfR3SendEventWaitEx(pVM, pVCpu, enmEvent, DBGFEVENTCTX_RAW, &DbgEvent.u, sizeof(DbgEvent.u.Bp));
807 }
808
809 return VERR_DBGF_IPE_1;
810}
811
812
813/**
814 * Returns whether the given vCPU is waiting for the debugger.
815 *
816 * @returns Flags whether the vCPU is currently waiting for the debugger.
817 * @param pUVCpu The user mode vCPU structure.
818 */
819DECLINLINE(bool) dbgfR3CpuIsHalted(PUVMCPU pUVCpu)
820{
821 return ASMAtomicReadBool(&pUVCpu->dbgf.s.fStopped);
822}
823
824
825/**
826 * Checks whether the given vCPU is waiting in the debugger.
827 *
828 * @returns Flag whether the indicated vCPU is halted, when VMCPUID_ALL
829 * is given true is returned when at least one vCPU is halted.
830 * @param pUVM The user mode VM structure.
831 * @param idCpu The CPU ID to check, VMCPUID_ALL to check all vCPUs.
832 */
833DECLINLINE(bool) dbgfR3CpuAreAnyHaltedByCpuId(PUVM pUVM, VMCPUID idCpu)
834{
835 AssertReturn(idCpu < pUVM->cCpus || idCpu == VMCPUID_ALL, false);
836
837 /* Check that either the given vCPU or all are actually halted. */
838 if (idCpu != VMCPUID_ALL)
839 return dbgfR3CpuIsHalted(&pUVM->aCpus[idCpu]);
840
841 for (VMCPUID i = 0; i < pUVM->cCpus; i++)
842 if (dbgfR3CpuIsHalted(&pUVM->aCpus[i]))
843 return true;
844 return false;
845}
846
847
848/**
849 * Gets the pending debug command for this EMT/CPU, replacing it with
850 * DBGFCMD_NO_COMMAND.
851 *
852 * @returns Pending command.
853 * @param pUVCpu The user mode virtual CPU structure.
854 * @thread EMT(pUVCpu)
855 */
856DECLINLINE(DBGFCMD) dbgfR3CpuGetCmd(PUVMCPU pUVCpu)
857{
858 DBGFCMD enmCmd = (DBGFCMD)ASMAtomicXchgU32((uint32_t volatile *)(void *)&pUVCpu->dbgf.s.enmDbgfCmd, DBGFCMD_NO_COMMAND);
859 Log2(("DBGF: Getting command: %d\n", enmCmd));
860 return enmCmd;
861}
862
863
864/**
865 * Send a debug command to a CPU, making sure to notify it.
866 *
867 * @returns VBox status code.
868 * @param pUVCpu The user mode virtual CPU structure.
869 * @param enmCmd The command to submit to the CPU.
870 */
871DECLINLINE(int) dbgfR3CpuSetCmdAndNotify(PUVMCPU pUVCpu, DBGFCMD enmCmd)
872{
873 Log2(("DBGF: Setting command to %d\n", enmCmd));
874 Assert(enmCmd != DBGFCMD_NO_COMMAND);
875 AssertMsg(pUVCpu->dbgf.s.enmDbgfCmd == DBGFCMD_NO_COMMAND, ("enmCmd=%d enmDbgfCmd=%d\n", enmCmd, pUVCpu->dbgf.s.enmDbgfCmd));
876
877 ASMAtomicWriteU32((uint32_t volatile *)(void *)&pUVCpu->dbgf.s.enmDbgfCmd, enmCmd);
878 VMCPU_FF_SET(pUVCpu->pVCpu, VMCPU_FF_DBGF);
879
880 VMR3NotifyCpuFFU(pUVCpu, 0 /*fFlags*/);
881 return VINF_SUCCESS;
882}
883
884
885/**
886 * @callback_method_impl{FNVMMEMTRENDEZVOUS}
887 */
888static DECLCALLBACK(VBOXSTRICTRC) dbgfR3EventHaltEmtWorker(PVM pVM, PVMCPU pVCpu, void *pvUser)
889{
890 RT_NOREF(pvUser);
891
892 VMCPU_ASSERT_EMT(pVCpu);
893 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
894
895 PUVMCPU pUVCpu = pVCpu->pUVCpu;
896 if ( pVCpu != (PVMCPU)pvUser
897 && !dbgfR3CpuIsHalted(pUVCpu))
898 dbgfR3CpuSetCmdAndNotify(pUVCpu, DBGFCMD_HALT);
899
900 return VINF_SUCCESS;
901}
902
903
904/**
905 * Halts all vCPUs of the given VM except for the given one.
906 *
907 * @returns VBox status code.
908 * @param pVM The cross context VM structure.
909 * @param pVCpuExclude The vCPU cross context structure of the vCPU to exclude.
910 */
911static int dbgfR3EventHaltAllVCpus(PVM pVM, PVMCPU pVCpuExclude)
912{
913 return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3EventHaltEmtWorker, pVCpuExclude);
914}
915
916
917/**
918 * Waits for the debugger to respond.
919 *
920 * @returns VBox status code. (clearify)
921 * @param pVCpu The cross context vCPU structure.
922 */
923static int dbgfR3CpuWait(PVMCPU pVCpu)
924{
925 PVM pVM = pVCpu->CTX_SUFF(pVM);
926 PUVMCPU pUVCpu = pVCpu->pUVCpu;
927
928 LogFlow(("dbgfR3CpuWait:\n"));
929 int rcRet = VINF_SUCCESS;
930
931 ASMAtomicWriteBool(&pUVCpu->dbgf.s.fStopped, true);
932
933 /*
934 * Waits for the debugger to reply (i.e. issue an command).
935 */
936 for (;;)
937 {
938 /*
939 * Wait.
940 */
941 for (;;)
942 {
943 /*
944 * Process forced flags before we go sleep.
945 */
946 if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_DBGF | VMCPU_FF_REQUEST)
947 || VM_FF_IS_ANY_SET(pVM, VM_FF_EMT_RENDEZVOUS | VMCPU_FF_REQUEST | VM_FF_CHECK_VM_STATE))
948 {
949 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_DBGF))
950 break;
951
952 int rc;
953 if (VM_FF_IS_SET(pVM, VM_FF_EMT_RENDEZVOUS))
954 rc = VMMR3EmtRendezvousFF(pVM, pVCpu);
955 else if ( VM_FF_IS_SET(pVM, VM_FF_REQUEST)
956 || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_REQUEST))
957 {
958 LogFlow(("dbgfR3CpuWait: Processes requests...\n"));
959 rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY, false /*fPriorityOnly*/);
960 if (rc == VINF_SUCCESS)
961 rc = VMR3ReqProcessU(pVM->pUVM, pVCpu->idCpu, false /*fPriorityOnly*/);
962 LogFlow(("dbgfR3CpuWait: VMR3ReqProcess -> %Rrc rcRet=%Rrc\n", rc, rcRet));
963 }
964 else if (VM_FF_IS_SET(pVM, VM_FF_CHECK_VM_STATE))
965 {
966 VMSTATE enmState = VMR3GetState(pVM);
967 switch (enmState)
968 {
969 case VMSTATE_FATAL_ERROR:
970 case VMSTATE_FATAL_ERROR_LS:
971 case VMSTATE_GURU_MEDITATION:
972 case VMSTATE_GURU_MEDITATION_LS:
973 rc = VINF_EM_SUSPEND;
974 break;
975 case VMSTATE_DESTROYING:
976 rc = VINF_EM_TERMINATE;
977 break;
978 default:
979 rc = VERR_DBGF_IPE_1;
980 AssertMsgFailed(("%s\n", VMGetStateName(enmState)));
981 }
982 }
983 else
984 rc = VINF_SUCCESS;
985 if (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST)
986 {
987 switch (rc)
988 {
989 case VINF_EM_DBG_BREAKPOINT:
990 case VINF_EM_DBG_STEPPED:
991 case VINF_EM_DBG_STEP:
992 case VINF_EM_DBG_STOP:
993 case VINF_EM_DBG_EVENT:
994 AssertMsgFailed(("rc=%Rrc\n", rc));
995 break;
996
997 /* return straight away */
998 case VINF_EM_TERMINATE:
999 case VINF_EM_OFF:
1000 LogFlow(("dbgfR3CpuWait: returns %Rrc\n", rc));
1001 ASMAtomicWriteBool(&pUVCpu->dbgf.s.fStopped, false);
1002 return rc;
1003
1004 /* remember return code. */
1005 default:
1006 AssertReleaseMsgFailed(("rc=%Rrc is not in the switch!\n", rc));
1007 RT_FALL_THRU();
1008 case VINF_EM_RESET:
1009 case VINF_EM_SUSPEND:
1010 case VINF_EM_HALT:
1011 case VINF_EM_RESUME:
1012 case VINF_EM_RESCHEDULE:
1013 case VINF_EM_RESCHEDULE_REM:
1014 if (rc < rcRet || rcRet == VINF_SUCCESS)
1015 rcRet = rc;
1016 break;
1017 }
1018 }
1019 else if (RT_FAILURE(rc))
1020 {
1021 LogFlow(("dbgfR3CpuWait: returns %Rrc\n", rc));
1022 ASMAtomicWriteBool(&pUVCpu->dbgf.s.fStopped, false);
1023 return rc;
1024 }
1025 }
1026 else if (pVM->dbgf.s.fAttached)
1027 {
1028 int rc = VMR3WaitU(pUVCpu);
1029 if (RT_FAILURE(rc))
1030 {
1031 LogFlow(("dbgfR3CpuWait: returns %Rrc (VMR3WaitU)\n", rc));
1032 ASMAtomicWriteBool(&pUVCpu->dbgf.s.fStopped, false);
1033 return rc;
1034 }
1035 }
1036 else
1037 {
1038 LogFlow(("dbgfR3CpuWait: Debugger detached, continuing normal execution (%Rrc)\n", rcRet));
1039 ASMAtomicWriteBool(&pUVCpu->dbgf.s.fStopped, false);
1040 return rcRet;
1041 }
1042 }
1043
1044 /*
1045 * Process the command.
1046 */
1047 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_DBGF);
1048 bool fResumeExecution;
1049 DBGFCMDDATA CmdData = pUVCpu->dbgf.s.DbgfCmdData;
1050 DBGFCMD enmCmd = dbgfR3CpuGetCmd(pUVCpu);
1051 int rc = dbgfR3CpuCmd(pVCpu, enmCmd, &CmdData, &fResumeExecution);
1052 if (fResumeExecution)
1053 {
1054 if (RT_FAILURE(rc))
1055 rcRet = rc;
1056 else if ( rc >= VINF_EM_FIRST
1057 && rc <= VINF_EM_LAST
1058 && (rc < rcRet || rcRet == VINF_SUCCESS))
1059 rcRet = rc;
1060 LogFlow(("dbgfR3CpuWait: returns %Rrc\n", rcRet));
1061 ASMAtomicWriteBool(&pUVCpu->dbgf.s.fStopped, false);
1062 return rcRet;
1063 }
1064 }
1065}
1066
1067
1068/**
1069 * Executes command from debugger.
1070 *
1071 * The caller is responsible for waiting or resuming execution based on the
1072 * value returned in the *pfResumeExecution indicator.
1073 *
1074 * @returns VBox status code. (clearify!)
1075 * @param pVCpu The cross context vCPU structure.
1076 * @param enmCmd The command in question.
1077 * @param pCmdData Pointer to the command data.
1078 * @param pfResumeExecution Where to store the resume execution / continue waiting indicator.
1079 */
1080static int dbgfR3CpuCmd(PVMCPU pVCpu, DBGFCMD enmCmd, PDBGFCMDDATA pCmdData, bool *pfResumeExecution)
1081{
1082 RT_NOREF(pCmdData); /* for later */
1083
1084 /*
1085 * The cases in this switch returns directly if no event to send.
1086 */
1087 DBGFEVENTTYPE enmEvent;
1088 DBGFEVENTCTX enmCtx = DBGFEVENTCTX_INVALID;
1089 switch (enmCmd)
1090 {
1091 /*
1092 * Halt is answered by an event say that we've halted.
1093 */
1094 case DBGFCMD_HALT:
1095 {
1096 *pfResumeExecution = false;
1097 enmEvent = DBGFEVENT_HALT_DONE;
1098 break;
1099 }
1100
1101
1102 /*
1103 * Resume is not answered, we just resume execution.
1104 */
1105 case DBGFCMD_GO:
1106 {
1107 pVCpu->dbgf.s.fSingleSteppingRaw = false;
1108 *pfResumeExecution = true;
1109 return VINF_SUCCESS;
1110 }
1111
1112 /** @todo implement (and define) the rest of the commands. */
1113
1114 /*
1115 * Single step, with trace into.
1116 */
1117 case DBGFCMD_SINGLE_STEP:
1118 {
1119 Log2(("Single step\n"));
1120 PVM pVM = pVCpu->CTX_SUFF(pVM);
1121 if (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_OVER)
1122 {
1123 if (dbgfStepGetCurInstrType(pVM, pVCpu) == DBGFSTEPINSTRTYPE_CALL)
1124 pVM->dbgf.s.SteppingFilter.uCallDepth++;
1125 }
1126 if (pVM->dbgf.s.SteppingFilter.cMaxSteps > 0)
1127 {
1128 pVCpu->dbgf.s.fSingleSteppingRaw = true;
1129 *pfResumeExecution = true;
1130 return VINF_EM_DBG_STEP;
1131 }
1132 /* Stop after zero steps. Nonsense, but whatever. */
1133 pVM->dbgf.s.SteppingFilter.idCpu = NIL_VMCPUID;
1134 *pfResumeExecution = false;
1135 enmCtx = dbgfR3FigureEventCtx(pVCpu);
1136 enmEvent = enmCtx != DBGFEVENTCTX_HYPER ? DBGFEVENT_STEPPED : DBGFEVENT_STEPPED_HYPER;
1137 break;
1138 }
1139
1140 /*
1141 * Default is to send an invalid command event.
1142 */
1143 default:
1144 {
1145 *pfResumeExecution = false;
1146 enmEvent = DBGFEVENT_INVALID_COMMAND;
1147 break;
1148 }
1149 }
1150
1151 /*
1152 * Send the pending event.
1153 */
1154 Log2(("DBGF: Emulation thread: sending event %d\n", enmEvent));
1155 int rc = dbgfR3SendEventNoWait(pVCpu->CTX_SUFF(pVM), pVCpu, enmEvent, enmCtx);
1156 AssertRCStmt(rc, *pfResumeExecution = true);
1157 return rc;
1158}
1159
1160
1161/**
1162 * @callback_method_impl{FNVMMEMTRENDEZVOUS,
1163 * EMT rendezvous worker for DBGFR3Attach - only called on one EMT.}
1164 */
1165static DECLCALLBACK(VBOXSTRICTRC) dbgfR3Attach(PVM pVM, PVMCPU pVCpu, void *pvUser)
1166{
1167 PUVM pUVM = pVM->pUVM;
1168 int *prcAttach = (int *)pvUser;
1169 RT_NOREF(pVCpu);
1170
1171 if (pVM->dbgf.s.fAttached)
1172 {
1173 Log(("dbgfR3Attach: Debugger already attached\n"));
1174 *prcAttach = VERR_DBGF_ALREADY_ATTACHED;
1175 return VINF_SUCCESS;
1176 }
1177
1178 /*
1179 * The per-CPU bits.
1180 */
1181 for (uint32_t i = 0; i < pUVM->cCpus; i++)
1182 {
1183 PUVMCPU pUVCpu = &pUVM->aCpus[i];
1184
1185 pUVCpu->dbgf.s.enmDbgfCmd = DBGFCMD_NO_COMMAND;
1186 RT_ZERO(pUVCpu->dbgf.s.DbgfCmdData);
1187 }
1188
1189 /*
1190 * Init of the VM -> Debugger communication part living in the global VM structure.
1191 */
1192 pUVM->dbgf.s.cDbgEvtMax = pVM->cCpus * 5 + 10; /* Initial size of event ring, increased when being full. */
1193 pUVM->dbgf.s.idxDbgEvtWrite = 0;
1194 pUVM->dbgf.s.idxDbgEvtRead = 0;
1195 pUVM->dbgf.s.hEvtWait = NIL_RTSEMEVENT;
1196 pUVM->dbgf.s.hEvtRingBufFull = NIL_RTSEMEVENTMULTI;
1197 pUVM->dbgf.s.hMtxDbgEvtWr = NIL_RTSEMFASTMUTEX;
1198 int rc;
1199 pUVM->dbgf.s.paDbgEvts = (PDBGFEVENT)MMR3HeapAllocU(pUVM, MM_TAG_DBGF, pUVM->dbgf.s.cDbgEvtMax * sizeof(DBGFEVENT));
1200 if (pUVM->dbgf.s.paDbgEvts)
1201 {
1202 rc = RTSemEventCreate(&pUVM->dbgf.s.hEvtWait);
1203 if (RT_SUCCESS(rc))
1204 {
1205 rc = RTSemFastMutexCreate(&pUVM->dbgf.s.hMtxDbgEvtWr);
1206 if (RT_SUCCESS(rc))
1207 {
1208 rc = RTSemEventMultiCreate(&pUVM->dbgf.s.hEvtRingBufFull);
1209 if (RT_SUCCESS(rc))
1210 {
1211 /*
1212 * At last, set the attached flag.
1213 */
1214 ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, true);
1215 *prcAttach = VINF_SUCCESS;
1216 return VINF_SUCCESS;
1217 }
1218
1219 RTSemFastMutexDestroy(pUVM->dbgf.s.hMtxDbgEvtWr);
1220 pUVM->dbgf.s.hMtxDbgEvtWr = NIL_RTSEMFASTMUTEX;
1221 }
1222 RTSemEventDestroy(pUVM->dbgf.s.hEvtWait);
1223 pUVM->dbgf.s.hEvtWait = NIL_RTSEMEVENT;
1224 }
1225 }
1226 else
1227 rc = VERR_NO_MEMORY;
1228
1229 *prcAttach = rc;
1230 return VINF_SUCCESS;
1231}
1232
1233
1234/**
1235 * Attaches a debugger to the specified VM.
1236 *
1237 * Only one debugger at a time.
1238 *
1239 * @returns VBox status code.
1240 * @param pUVM The user mode VM handle.
1241 */
1242VMMR3DECL(int) DBGFR3Attach(PUVM pUVM)
1243{
1244 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1245 PVM pVM = pUVM->pVM;
1246 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1247
1248 /*
1249 * Call the VM, use EMT rendezvous for serialization.
1250 */
1251 int rcAttach = VERR_IPE_UNINITIALIZED_STATUS;
1252 int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE | VMMEMTRENDEZVOUS_FLAGS_PRIORITY, dbgfR3Attach, &rcAttach);
1253 if (RT_SUCCESS(rc))
1254 rc = rcAttach;
1255
1256 return rc;
1257}
1258
1259
1260/**
1261 * @callback_method_impl{FNVMMEMTRENDEZVOUS,
1262 * EMT rendezvous worker for DBGFR3Detach - called on all EMTs (why?).}
1263 */
1264static DECLCALLBACK(VBOXSTRICTRC) dbgfR3Detach(PVM pVM, PVMCPU pVCpu, void *pvUser)
1265{
1266 if (pVCpu->idCpu == 0)
1267 {
1268 PUVM pUVM = (PUVM)pvUser;
1269
1270 /*
1271 * Per-CPU cleanup.
1272 */
1273 for (VMCPUID i = 0; i < pUVM->cCpus; i++)
1274 {
1275 PUVMCPU pUVCpu = &pUVM->aCpus[i];
1276
1277 pUVCpu->dbgf.s.enmDbgfCmd = DBGFCMD_NO_COMMAND;
1278 RT_ZERO(pUVCpu->dbgf.s.DbgfCmdData);
1279 }
1280
1281 /*
1282 * De-init of the VM -> Debugger communication part living in the global VM structure.
1283 */
1284 if (pUVM->dbgf.s.paDbgEvts)
1285 {
1286 MMR3HeapFree(pUVM->dbgf.s.paDbgEvts);
1287 pUVM->dbgf.s.paDbgEvts = NULL;
1288 }
1289
1290 if (pUVM->dbgf.s.hEvtWait != NIL_RTSEMEVENT)
1291 {
1292 RTSemEventDestroy(pUVM->dbgf.s.hEvtWait);
1293 pUVM->dbgf.s.hEvtWait = NIL_RTSEMEVENT;
1294 }
1295
1296 if (pUVM->dbgf.s.hMtxDbgEvtWr != NIL_RTSEMFASTMUTEX)
1297 {
1298 RTSemFastMutexDestroy(pUVM->dbgf.s.hMtxDbgEvtWr);
1299 pUVM->dbgf.s.hMtxDbgEvtWr = NIL_RTSEMFASTMUTEX;
1300 }
1301
1302 if (pUVM->dbgf.s.hEvtRingBufFull != NIL_RTSEMEVENTMULTI)
1303 {
1304 RTSemEventMultiDestroy(pUVM->dbgf.s.hEvtRingBufFull);
1305 pUVM->dbgf.s.hEvtRingBufFull = NIL_RTSEMEVENTMULTI;
1306 }
1307
1308 pUVM->dbgf.s.cDbgEvtMax = 0;
1309 pUVM->dbgf.s.idxDbgEvtWrite = 0;
1310 pUVM->dbgf.s.idxDbgEvtRead = 0;
1311 pUVM->dbgf.s.hEvtWait = NIL_RTSEMEVENT;
1312 pUVM->dbgf.s.hEvtRingBufFull = NIL_RTSEMEVENTMULTI;
1313 pUVM->dbgf.s.hMtxDbgEvtWr = NIL_RTSEMFASTMUTEX;
1314
1315 ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, false);
1316 }
1317
1318 return VINF_SUCCESS;
1319}
1320
1321
1322/**
1323 * Detaches a debugger from the specified VM.
1324 *
1325 * Caller must be attached to the VM.
1326 *
1327 * @returns VBox status code.
1328 * @param pUVM The user mode VM handle.
1329 */
1330VMMR3DECL(int) DBGFR3Detach(PUVM pUVM)
1331{
1332 LogFlow(("DBGFR3Detach:\n"));
1333
1334 /*
1335 * Validate input. The UVM handle shall be valid, the VM handle might be
1336 * in the processes of being destroyed already, so deal quietly with that.
1337 */
1338 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1339 PVM pVM = pUVM->pVM;
1340 if (!VM_IS_VALID_EXT(pVM))
1341 return VERR_INVALID_VM_HANDLE;
1342
1343 /*
1344 * Check if attached.
1345 */
1346 if (!pVM->dbgf.s.fAttached)
1347 return VERR_DBGF_NOT_ATTACHED;
1348
1349 return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE | VMMEMTRENDEZVOUS_FLAGS_PRIORITY, dbgfR3Detach, pUVM);
1350}
1351
1352
1353/**
1354 * Wait for a debug event.
1355 *
1356 * @returns VBox status code. Will not return VBOX_INTERRUPTED.
1357 * @param pUVM The user mode VM handle.
1358 * @param cMillies Number of millis to wait.
1359 * @param pEvent Where to store the event data.
1360 */
1361VMMR3DECL(int) DBGFR3EventWait(PUVM pUVM, RTMSINTERVAL cMillies, PDBGFEVENT pEvent)
1362{
1363 /*
1364 * Check state.
1365 */
1366 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1367 PVM pVM = pUVM->pVM;
1368 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1369 AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
1370
1371 RT_BZERO(pEvent, sizeof(*pEvent));
1372
1373 /*
1374 * Wait for an event to arrive if there are none.
1375 */
1376 int rc = VINF_SUCCESS;
1377 uint32_t idxDbgEvtRead = ASMAtomicReadU32(&pUVM->dbgf.s.idxDbgEvtRead);
1378 if (idxDbgEvtRead == ASMAtomicReadU32(&pUVM->dbgf.s.idxDbgEvtWrite))
1379 {
1380 do
1381 {
1382 rc = RTSemEventWait(pUVM->dbgf.s.hEvtWait, cMillies);
1383 } while ( RT_SUCCESS(rc)
1384 && idxDbgEvtRead == ASMAtomicReadU32(&pUVM->dbgf.s.idxDbgEvtWrite));
1385 }
1386
1387 if (RT_SUCCESS(rc))
1388 {
1389 Assert(idxDbgEvtRead != ASMAtomicReadU32(&pUVM->dbgf.s.idxDbgEvtWrite));
1390
1391 uint32_t const cDbgEvtMax = RT_MAX(1, pUVM->dbgf.s.cDbgEvtMax);
1392 memcpy(pEvent, &pUVM->dbgf.s.paDbgEvts[idxDbgEvtRead % cDbgEvtMax], sizeof(*pEvent));
1393 ASMAtomicWriteU32(&pUVM->dbgf.s.idxDbgEvtRead, (idxDbgEvtRead + 1) % cDbgEvtMax);
1394 }
1395
1396 Log2(("DBGFR3EventWait: rc=%Rrc (event type %d)\n", rc, pEvent->enmType));
1397 return rc;
1398}
1399
1400
1401/**
1402 * Halts VM execution.
1403 *
1404 * After calling this the VM isn't actually halted till an DBGFEVENT_HALT_DONE
1405 * arrives. Until that time it's not possible to issue any new commands.
1406 *
1407 * @returns VBox status code.
1408 * @retval VWRN_DBGF_ALREADY_HALTED if @a idCpu is VMCPUID_ALL and all vCPUs
1409 * are halted.
1410 * @param pUVM The user mode VM handle.
1411 * @param idCpu The vCPU to halt, VMCPUID_ALL halts all still running vCPUs.
1412 */
1413VMMR3DECL(int) DBGFR3Halt(PUVM pUVM, VMCPUID idCpu)
1414{
1415 /*
1416 * Check state.
1417 */
1418 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1419 PVM pVM = pUVM->pVM;
1420 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1421 AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
1422 AssertReturn(idCpu == VMCPUID_ALL || idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
1423
1424 /*
1425 * Halt the requested CPUs as needed.
1426 */
1427 int rc;
1428 if (idCpu != VMCPUID_ALL)
1429 {
1430 PUVMCPU pUVCpu = &pUVM->aCpus[idCpu];
1431 if (!dbgfR3CpuIsHalted(pUVCpu))
1432 {
1433 dbgfR3CpuSetCmdAndNotify(pUVCpu, DBGFCMD_HALT);
1434 rc = VINF_SUCCESS;
1435 }
1436 else
1437 rc = VWRN_DBGF_ALREADY_HALTED;
1438 }
1439 else
1440 {
1441 rc = VWRN_DBGF_ALREADY_HALTED;
1442 for (VMCPUID i = 0; i < pUVM->cCpus; i++)
1443 {
1444 PUVMCPU pUVCpu = &pUVM->aCpus[i];
1445 if (!dbgfR3CpuIsHalted(pUVCpu))
1446 {
1447 dbgfR3CpuSetCmdAndNotify(pUVCpu, DBGFCMD_HALT);
1448 rc = VINF_SUCCESS;
1449 }
1450 }
1451 }
1452
1453 return rc;
1454}
1455
1456
1457/**
1458 * Checks if any of the specified vCPUs have been halted by the debugger.
1459 *
1460 * @returns True if at least one halted vCPUs.
1461 * @returns False if no halted vCPUs.
1462 * @param pUVM The user mode VM handle.
1463 * @param idCpu The CPU id to check for, VMCPUID_ALL will return true if
1464 * at least a single vCPU is halted in the debugger.
1465 */
1466VMMR3DECL(bool) DBGFR3IsHalted(PUVM pUVM, VMCPUID idCpu)
1467{
1468 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
1469 PVM pVM = pUVM->pVM;
1470 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
1471 AssertReturn(pVM->dbgf.s.fAttached, false);
1472
1473 return dbgfR3CpuAreAnyHaltedByCpuId(pUVM, idCpu);
1474}
1475
1476
1477/**
1478 * Checks if the debugger can wait for events or not.
1479 *
1480 * This function is only used by lazy, multiplexing debuggers. :-)
1481 *
1482 * @returns VBox status code.
1483 * @retval VINF_SUCCESS if waitable.
1484 * @retval VERR_SEM_OUT_OF_TURN if not waitable.
1485 * @retval VERR_INVALID_VM_HANDLE if the VM is being (/ has been) destroyed
1486 * (not asserted) or if the handle is invalid (asserted).
1487 * @retval VERR_DBGF_NOT_ATTACHED if not attached.
1488 *
1489 * @param pUVM The user mode VM handle.
1490 */
1491VMMR3DECL(int) DBGFR3QueryWaitable(PUVM pUVM)
1492{
1493 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1494
1495 /* Note! There is a slight race here, unfortunately. */
1496 PVM pVM = pUVM->pVM;
1497 if (!RT_VALID_PTR(pVM))
1498 return VERR_INVALID_VM_HANDLE;
1499 if (pVM->enmVMState >= VMSTATE_DESTROYING)
1500 return VERR_INVALID_VM_HANDLE;
1501 if (!pVM->dbgf.s.fAttached)
1502 return VERR_DBGF_NOT_ATTACHED;
1503
1504 /** @todo was: if (!RTSemPongShouldWait(...)) return VERR_SEM_OUT_OF_TURN; */
1505 return VINF_SUCCESS;
1506}
1507
1508
1509/**
1510 * Resumes VM execution.
1511 *
1512 * There is no receipt event on this command.
1513 *
1514 * @returns VBox status code.
1515 * @retval VWRN_DBGF_ALREADY_RUNNING if the specified vCPUs are all running.
1516 * @param pUVM The user mode VM handle.
1517 * @param idCpu The vCPU to resume, VMCPUID_ALL resumes all still halted vCPUs.
1518 */
1519VMMR3DECL(int) DBGFR3Resume(PUVM pUVM, VMCPUID idCpu)
1520{
1521 /*
1522 * Validate input and attachment state.
1523 */
1524 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1525 PVM pVM = pUVM->pVM;
1526 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1527 AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
1528
1529 /*
1530 * Ping the halted emulation threads, telling them to run.
1531 */
1532 int rc = VWRN_DBGF_ALREADY_RUNNING;
1533 if (idCpu != VMCPUID_ALL)
1534 {
1535 PUVMCPU pUVCpu = &pUVM->aCpus[idCpu];
1536 if (dbgfR3CpuIsHalted(pUVCpu))
1537 {
1538 rc = dbgfR3CpuSetCmdAndNotify(pUVCpu, DBGFCMD_GO);
1539 AssertRC(rc);
1540 }
1541 }
1542 else
1543 {
1544 for (VMCPUID i = 0; i < pUVM->cCpus; i++)
1545 {
1546 PUVMCPU pUVCpu = &pUVM->aCpus[i];
1547 if (dbgfR3CpuIsHalted(pUVCpu))
1548 {
1549 int rc2 = dbgfR3CpuSetCmdAndNotify(pUVCpu, DBGFCMD_GO);
1550 AssertRC(rc2);
1551 if (rc == VWRN_DBGF_ALREADY_RUNNING || RT_FAILURE(rc2))
1552 rc = rc2;
1553 }
1554 }
1555 }
1556
1557 return rc;
1558}
1559
1560
1561/**
1562 * Classifies the current instruction.
1563 *
1564 * @returns Type of instruction.
1565 * @param pVM The cross context VM structure.
1566 * @param pVCpu The current CPU.
1567 * @thread EMT(pVCpu)
1568 */
1569static DBGFSTEPINSTRTYPE dbgfStepGetCurInstrType(PVM pVM, PVMCPU pVCpu)
1570{
1571 /*
1572 * Read the instruction.
1573 */
1574 size_t cbRead = 0;
1575 uint8_t abOpcode[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1576 int rc = PGMR3DbgReadGCPtr(pVM, abOpcode, CPUMGetGuestFlatPC(pVCpu), sizeof(abOpcode) - 1, 0 /*fFlags*/, &cbRead);
1577 if (RT_SUCCESS(rc))
1578 {
1579 /*
1580 * Do minimal parsing. No real need to involve the disassembler here.
1581 */
1582 uint8_t *pb = abOpcode;
1583 for (;;)
1584 {
1585 switch (*pb++)
1586 {
1587 default:
1588 return DBGFSTEPINSTRTYPE_OTHER;
1589
1590 case 0xe8: /* call rel16/32 */
1591 case 0x9a: /* call farptr */
1592 case 0xcc: /* int3 */
1593 case 0xcd: /* int xx */
1594 // case 0xce: /* into */
1595 return DBGFSTEPINSTRTYPE_CALL;
1596
1597 case 0xc2: /* ret xx */
1598 case 0xc3: /* ret */
1599 case 0xca: /* retf xx */
1600 case 0xcb: /* retf */
1601 case 0xcf: /* iret */
1602 return DBGFSTEPINSTRTYPE_RET;
1603
1604 case 0xff:
1605 if ( ((*pb >> X86_MODRM_REG_SHIFT) & X86_MODRM_REG_SMASK) == 2 /* call indir */
1606 || ((*pb >> X86_MODRM_REG_SHIFT) & X86_MODRM_REG_SMASK) == 3) /* call indir-farptr */
1607 return DBGFSTEPINSTRTYPE_CALL;
1608 return DBGFSTEPINSTRTYPE_OTHER;
1609
1610 case 0x0f:
1611 switch (*pb++)
1612 {
1613 case 0x05: /* syscall */
1614 case 0x34: /* sysenter */
1615 return DBGFSTEPINSTRTYPE_CALL;
1616 case 0x07: /* sysret */
1617 case 0x35: /* sysexit */
1618 return DBGFSTEPINSTRTYPE_RET;
1619 }
1620 break;
1621
1622 /* Must handle some REX prefixes. So we do all normal prefixes. */
1623 case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
1624 case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
1625 if (!CPUMIsGuestIn64BitCode(pVCpu))
1626 return DBGFSTEPINSTRTYPE_OTHER;
1627 break;
1628
1629 case 0x2e: /* CS */
1630 case 0x36: /* SS */
1631 case 0x3e: /* DS */
1632 case 0x26: /* ES */
1633 case 0x64: /* FS */
1634 case 0x65: /* GS */
1635 case 0x66: /* op size */
1636 case 0x67: /* addr size */
1637 case 0xf0: /* lock */
1638 case 0xf2: /* REPNZ */
1639 case 0xf3: /* REPZ */
1640 break;
1641 }
1642 }
1643 }
1644
1645 return DBGFSTEPINSTRTYPE_INVALID;
1646}
1647
1648
1649/**
1650 * Checks if the stepping has reached a stop point.
1651 *
1652 * Called when raising a stepped event.
1653 *
1654 * @returns true if the event should be raised, false if we should take one more
1655 * step first.
1656 * @param pVM The cross context VM structure.
1657 * @param pVCpu The cross context per CPU structure of the calling EMT.
1658 * @thread EMT(pVCpu)
1659 */
1660static bool dbgfStepAreWeThereYet(PVM pVM, PVMCPU pVCpu)
1661{
1662 /*
1663 * Check valid pVCpu and that it matches the CPU one stepping.
1664 */
1665 if (pVCpu)
1666 {
1667 if (pVCpu->idCpu == pVM->dbgf.s.SteppingFilter.idCpu)
1668 {
1669 /*
1670 * Increase the number of steps and see if we've reached the max.
1671 */
1672 pVM->dbgf.s.SteppingFilter.cSteps++;
1673 if (pVM->dbgf.s.SteppingFilter.cSteps < pVM->dbgf.s.SteppingFilter.cMaxSteps)
1674 {
1675 /*
1676 * Check PC and SP address filtering.
1677 */
1678 if (pVM->dbgf.s.SteppingFilter.fFlags & (DBGF_STEP_F_STOP_ON_ADDRESS | DBGF_STEP_F_STOP_ON_STACK_POP))
1679 {
1680 if ( (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_ON_ADDRESS)
1681 && pVM->dbgf.s.SteppingFilter.AddrPc == CPUMGetGuestFlatPC(pVCpu))
1682 return true;
1683 if ( (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_ON_STACK_POP)
1684 && CPUMGetGuestFlatSP(pVCpu) - pVM->dbgf.s.SteppingFilter.AddrStackPop
1685 < pVM->dbgf.s.SteppingFilter.cbStackPop)
1686 return true;
1687 }
1688
1689 /*
1690 * Do step-over filtering separate from the step-into one.
1691 */
1692 if (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_OVER)
1693 {
1694 DBGFSTEPINSTRTYPE enmType = dbgfStepGetCurInstrType(pVM, pVCpu);
1695 switch (enmType)
1696 {
1697 default:
1698 if ( pVM->dbgf.s.SteppingFilter.uCallDepth != 0
1699 || (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_FILTER_MASK))
1700 break;
1701 return true;
1702 case DBGFSTEPINSTRTYPE_CALL:
1703 if ( (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_ON_CALL)
1704 && pVM->dbgf.s.SteppingFilter.uCallDepth == 0)
1705 return true;
1706 pVM->dbgf.s.SteppingFilter.uCallDepth++;
1707 break;
1708 case DBGFSTEPINSTRTYPE_RET:
1709 if (pVM->dbgf.s.SteppingFilter.uCallDepth == 0)
1710 {
1711 if (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_ON_RET)
1712 return true;
1713 /* If after return, we use the cMaxStep limit to stop the next time. */
1714 if (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_AFTER_RET)
1715 pVM->dbgf.s.SteppingFilter.cMaxSteps = pVM->dbgf.s.SteppingFilter.cSteps + 1;
1716 }
1717 else if (pVM->dbgf.s.SteppingFilter.uCallDepth > 0)
1718 pVM->dbgf.s.SteppingFilter.uCallDepth--;
1719 break;
1720 }
1721 return false;
1722 }
1723 /*
1724 * Filtered step-into.
1725 */
1726 else if ( pVM->dbgf.s.SteppingFilter.fFlags
1727 & (DBGF_STEP_F_STOP_ON_CALL | DBGF_STEP_F_STOP_ON_RET | DBGF_STEP_F_STOP_AFTER_RET))
1728 {
1729 DBGFSTEPINSTRTYPE enmType = dbgfStepGetCurInstrType(pVM, pVCpu);
1730 switch (enmType)
1731 {
1732 default:
1733 break;
1734 case DBGFSTEPINSTRTYPE_CALL:
1735 if (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_ON_CALL)
1736 return true;
1737 break;
1738 case DBGFSTEPINSTRTYPE_RET:
1739 if (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_ON_RET)
1740 return true;
1741 /* If after return, we use the cMaxStep limit to stop the next time. */
1742 if (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_AFTER_RET)
1743 pVM->dbgf.s.SteppingFilter.cMaxSteps = pVM->dbgf.s.SteppingFilter.cSteps + 1;
1744 break;
1745 }
1746 return false;
1747 }
1748 }
1749 }
1750 }
1751
1752 return true;
1753}
1754
1755
1756/**
1757 * Step Into.
1758 *
1759 * A single step event is generated from this command.
1760 * The current implementation is not reliable, so don't rely on the event coming.
1761 *
1762 * @returns VBox status code.
1763 * @param pUVM The user mode VM handle.
1764 * @param idCpu The ID of the CPU to single step on.
1765 */
1766VMMR3DECL(int) DBGFR3Step(PUVM pUVM, VMCPUID idCpu)
1767{
1768 return DBGFR3StepEx(pUVM, idCpu, DBGF_STEP_F_INTO, NULL, NULL, 0, 1);
1769}
1770
1771
1772/**
1773 * Full fleged step.
1774 *
1775 * This extended stepping API allows for doing multiple steps before raising an
1776 * event, helping implementing step over, step out and other more advanced
1777 * features.
1778 *
1779 * Like the DBGFR3Step() API, this will normally generate a DBGFEVENT_STEPPED or
1780 * DBGFEVENT_STEPPED_EVENT. However the stepping may be interrupted by other
1781 * events, which will abort the stepping.
1782 *
1783 * The stop on pop area feature is for safeguarding step out.
1784 *
1785 * Please note though, that it will always use stepping and never breakpoints.
1786 * While this allows for a much greater flexibility it can at times be rather
1787 * slow.
1788 *
1789 * @returns VBox status code.
1790 * @param pUVM The user mode VM handle.
1791 * @param idCpu The ID of the CPU to single step on.
1792 * @param fFlags Flags controlling the stepping, DBGF_STEP_F_XXX.
1793 * Either DBGF_STEP_F_INTO or DBGF_STEP_F_OVER must
1794 * always be specified.
1795 * @param pStopPcAddr Address to stop executing at. Completely ignored
1796 * unless DBGF_STEP_F_STOP_ON_ADDRESS is specified.
1797 * @param pStopPopAddr Stack address that SP must be lower than when
1798 * performing DBGF_STEP_F_STOP_ON_STACK_POP filtering.
1799 * @param cbStopPop The range starting at @a pStopPopAddr which is
1800 * considered to be within the same thread stack. Note
1801 * that the API allows @a pStopPopAddr and @a cbStopPop
1802 * to form an area that wraps around and it will
1803 * consider the part starting at 0 as included.
1804 * @param cMaxSteps The maximum number of steps to take. This is to
1805 * prevent stepping for ever, so passing UINT32_MAX is
1806 * not recommended.
1807 *
1808 * @remarks The two address arguments must be guest context virtual addresses,
1809 * or HMA. The code doesn't make much of a point of out HMA, though.
1810 */
1811VMMR3DECL(int) DBGFR3StepEx(PUVM pUVM, VMCPUID idCpu, uint32_t fFlags, PCDBGFADDRESS pStopPcAddr,
1812 PCDBGFADDRESS pStopPopAddr, RTGCUINTPTR cbStopPop, uint32_t cMaxSteps)
1813{
1814 /*
1815 * Check state.
1816 */
1817 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1818 PVM pVM = pUVM->pVM;
1819 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1820 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
1821 AssertReturn(!(fFlags & ~DBGF_STEP_F_VALID_MASK), VERR_INVALID_FLAGS);
1822 AssertReturn(RT_BOOL(fFlags & DBGF_STEP_F_INTO) != RT_BOOL(fFlags & DBGF_STEP_F_OVER), VERR_INVALID_FLAGS);
1823 if (fFlags & DBGF_STEP_F_STOP_ON_ADDRESS)
1824 {
1825 AssertReturn(RT_VALID_PTR(pStopPcAddr), VERR_INVALID_POINTER);
1826 AssertReturn(DBGFADDRESS_IS_VALID(pStopPcAddr), VERR_INVALID_PARAMETER);
1827 AssertReturn(DBGFADDRESS_IS_VIRT_GC(pStopPcAddr), VERR_INVALID_PARAMETER);
1828 }
1829 AssertReturn(!(fFlags & DBGF_STEP_F_STOP_ON_STACK_POP) || RT_VALID_PTR(pStopPopAddr), VERR_INVALID_POINTER);
1830 if (fFlags & DBGF_STEP_F_STOP_ON_STACK_POP)
1831 {
1832 AssertReturn(RT_VALID_PTR(pStopPopAddr), VERR_INVALID_POINTER);
1833 AssertReturn(DBGFADDRESS_IS_VALID(pStopPopAddr), VERR_INVALID_PARAMETER);
1834 AssertReturn(DBGFADDRESS_IS_VIRT_GC(pStopPopAddr), VERR_INVALID_PARAMETER);
1835 AssertReturn(cbStopPop > 0, VERR_INVALID_PARAMETER);
1836 }
1837
1838 AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
1839 PUVMCPU pUVCpu = &pUVM->aCpus[idCpu];
1840 if (RT_LIKELY(dbgfR3CpuIsHalted(pUVCpu)))
1841 { /* likely */ }
1842 else
1843 return VERR_SEM_OUT_OF_TURN;
1844 Assert(pVM->dbgf.s.SteppingFilter.idCpu == NIL_VMCPUID);
1845
1846 /*
1847 * Send the emulation thread a single-step command.
1848 */
1849 if (fFlags == DBGF_STEP_F_INTO)
1850 pVM->dbgf.s.SteppingFilter.idCpu = NIL_VMCPUID;
1851 else
1852 pVM->dbgf.s.SteppingFilter.idCpu = idCpu;
1853 pVM->dbgf.s.SteppingFilter.fFlags = fFlags;
1854 if (fFlags & DBGF_STEP_F_STOP_ON_ADDRESS)
1855 pVM->dbgf.s.SteppingFilter.AddrPc = pStopPcAddr->FlatPtr;
1856 else
1857 pVM->dbgf.s.SteppingFilter.AddrPc = 0;
1858 if (fFlags & DBGF_STEP_F_STOP_ON_STACK_POP)
1859 {
1860 pVM->dbgf.s.SteppingFilter.AddrStackPop = pStopPopAddr->FlatPtr;
1861 pVM->dbgf.s.SteppingFilter.cbStackPop = cbStopPop;
1862 }
1863 else
1864 {
1865 pVM->dbgf.s.SteppingFilter.AddrStackPop = 0;
1866 pVM->dbgf.s.SteppingFilter.cbStackPop = RTGCPTR_MAX;
1867 }
1868
1869 pVM->dbgf.s.SteppingFilter.cMaxSteps = cMaxSteps;
1870 pVM->dbgf.s.SteppingFilter.cSteps = 0;
1871 pVM->dbgf.s.SteppingFilter.uCallDepth = 0;
1872
1873 Assert(dbgfR3CpuIsHalted(pUVCpu));
1874 return dbgfR3CpuSetCmdAndNotify(pUVCpu, DBGFCMD_SINGLE_STEP);
1875}
1876
1877
1878
1879/**
1880 * dbgfR3EventConfigEx argument packet.
1881 */
1882typedef struct DBGFR3EVENTCONFIGEXARGS
1883{
1884 PCDBGFEVENTCONFIG paConfigs;
1885 size_t cConfigs;
1886 int rc;
1887} DBGFR3EVENTCONFIGEXARGS;
1888/** Pointer to a dbgfR3EventConfigEx argument packet. */
1889typedef DBGFR3EVENTCONFIGEXARGS *PDBGFR3EVENTCONFIGEXARGS;
1890
1891
1892/**
1893 * @callback_method_impl{FNVMMEMTRENDEZVOUS, Worker for DBGFR3EventConfigEx.}
1894 */
1895static DECLCALLBACK(VBOXSTRICTRC) dbgfR3EventConfigEx(PVM pVM, PVMCPU pVCpu, void *pvUser)
1896{
1897 if (pVCpu->idCpu == 0)
1898 {
1899 PDBGFR3EVENTCONFIGEXARGS pArgs = (PDBGFR3EVENTCONFIGEXARGS)pvUser;
1900 DBGFEVENTCONFIG volatile const *paConfigs = pArgs->paConfigs;
1901 size_t cConfigs = pArgs->cConfigs;
1902
1903 /*
1904 * Apply the changes.
1905 */
1906 unsigned cChanges = 0;
1907 for (uint32_t i = 0; i < cConfigs; i++)
1908 {
1909 DBGFEVENTTYPE enmType = paConfigs[i].enmType;
1910 AssertReturn(enmType >= DBGFEVENT_FIRST_SELECTABLE && enmType < DBGFEVENT_END, VERR_INVALID_PARAMETER);
1911 if (paConfigs[i].fEnabled)
1912 cChanges += ASMAtomicBitTestAndSet(&pVM->dbgf.s.bmSelectedEvents, enmType) == false;
1913 else
1914 cChanges += ASMAtomicBitTestAndClear(&pVM->dbgf.s.bmSelectedEvents, enmType) == true;
1915 }
1916
1917 /*
1918 * Inform HM about changes.
1919 */
1920 if (cChanges > 0)
1921 {
1922 if (HMIsEnabled(pVM))
1923 {
1924 HMR3NotifyDebugEventChanged(pVM);
1925 HMR3NotifyDebugEventChangedPerCpu(pVM, pVCpu);
1926 }
1927 else if (VM_IS_NEM_ENABLED(pVM))
1928 {
1929 NEMR3NotifyDebugEventChanged(pVM);
1930 NEMR3NotifyDebugEventChangedPerCpu(pVM, pVCpu);
1931 }
1932 }
1933 }
1934 else if (HMIsEnabled(pVM))
1935 HMR3NotifyDebugEventChangedPerCpu(pVM, pVCpu);
1936 else if (VM_IS_NEM_ENABLED(pVM))
1937 NEMR3NotifyDebugEventChangedPerCpu(pVM, pVCpu);
1938
1939 return VINF_SUCCESS;
1940}
1941
1942
1943/**
1944 * Configures (enables/disables) multiple selectable debug events.
1945 *
1946 * @returns VBox status code.
1947 * @param pUVM The user mode VM handle.
1948 * @param paConfigs The event to configure and their new state.
1949 * @param cConfigs Number of entries in @a paConfigs.
1950 */
1951VMMR3DECL(int) DBGFR3EventConfigEx(PUVM pUVM, PCDBGFEVENTCONFIG paConfigs, size_t cConfigs)
1952{
1953 /*
1954 * Validate input.
1955 */
1956 size_t i = cConfigs;
1957 while (i-- > 0)
1958 {
1959 AssertReturn(paConfigs[i].enmType >= DBGFEVENT_FIRST_SELECTABLE, VERR_INVALID_PARAMETER);
1960 AssertReturn(paConfigs[i].enmType < DBGFEVENT_END, VERR_INVALID_PARAMETER);
1961 }
1962 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1963 PVM pVM = pUVM->pVM;
1964 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1965
1966 /*
1967 * Apply the changes in EMT(0) and rendezvous with the other CPUs so they
1968 * can sync their data and execution with new debug state.
1969 */
1970 DBGFR3EVENTCONFIGEXARGS Args = { paConfigs, cConfigs, VINF_SUCCESS };
1971 int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING | VMMEMTRENDEZVOUS_FLAGS_PRIORITY,
1972 dbgfR3EventConfigEx, &Args);
1973 if (RT_SUCCESS(rc))
1974 rc = Args.rc;
1975 return rc;
1976}
1977
1978
1979/**
1980 * Enables or disables a selectable debug event.
1981 *
1982 * @returns VBox status code.
1983 * @param pUVM The user mode VM handle.
1984 * @param enmEvent The selectable debug event.
1985 * @param fEnabled The new state.
1986 */
1987VMMR3DECL(int) DBGFR3EventConfig(PUVM pUVM, DBGFEVENTTYPE enmEvent, bool fEnabled)
1988{
1989 /*
1990 * Convert to an array call.
1991 */
1992 DBGFEVENTCONFIG EvtCfg = { enmEvent, fEnabled };
1993 return DBGFR3EventConfigEx(pUVM, &EvtCfg, 1);
1994}
1995
1996
1997/**
1998 * Checks if the given selectable event is enabled.
1999 *
2000 * @returns true if enabled, false if not or invalid input.
2001 * @param pUVM The user mode VM handle.
2002 * @param enmEvent The selectable debug event.
2003 * @sa DBGFR3EventQuery
2004 */
2005VMMR3DECL(bool) DBGFR3EventIsEnabled(PUVM pUVM, DBGFEVENTTYPE enmEvent)
2006{
2007 /*
2008 * Validate input.
2009 */
2010 AssertReturn( enmEvent >= DBGFEVENT_HALT_DONE
2011 && enmEvent < DBGFEVENT_END, false);
2012 Assert( enmEvent >= DBGFEVENT_FIRST_SELECTABLE
2013 || enmEvent == DBGFEVENT_BREAKPOINT
2014 || enmEvent == DBGFEVENT_BREAKPOINT_IO
2015 || enmEvent == DBGFEVENT_BREAKPOINT_MMIO);
2016
2017 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
2018 PVM pVM = pUVM->pVM;
2019 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
2020
2021 /*
2022 * Check the event status.
2023 */
2024 return ASMBitTest(&pVM->dbgf.s.bmSelectedEvents, enmEvent);
2025}
2026
2027
2028/**
2029 * Queries the status of a set of events.
2030 *
2031 * @returns VBox status code.
2032 * @param pUVM The user mode VM handle.
2033 * @param paConfigs The events to query and where to return the state.
2034 * @param cConfigs The number of elements in @a paConfigs.
2035 * @sa DBGFR3EventIsEnabled, DBGF_IS_EVENT_ENABLED
2036 */
2037VMMR3DECL(int) DBGFR3EventQuery(PUVM pUVM, PDBGFEVENTCONFIG paConfigs, size_t cConfigs)
2038{
2039 /*
2040 * Validate input.
2041 */
2042 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
2043 PVM pVM = pUVM->pVM;
2044 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
2045
2046 for (size_t i = 0; i < cConfigs; i++)
2047 {
2048 DBGFEVENTTYPE enmType = paConfigs[i].enmType;
2049 AssertReturn( enmType >= DBGFEVENT_HALT_DONE
2050 && enmType < DBGFEVENT_END, VERR_INVALID_PARAMETER);
2051 Assert( enmType >= DBGFEVENT_FIRST_SELECTABLE
2052 || enmType == DBGFEVENT_BREAKPOINT
2053 || enmType == DBGFEVENT_BREAKPOINT_IO
2054 || enmType == DBGFEVENT_BREAKPOINT_MMIO);
2055 paConfigs[i].fEnabled = ASMBitTest(&pVM->dbgf.s.bmSelectedEvents, paConfigs[i].enmType);
2056 }
2057
2058 return VINF_SUCCESS;
2059}
2060
2061
2062/**
2063 * dbgfR3InterruptConfigEx argument packet.
2064 */
2065typedef struct DBGFR3INTERRUPTCONFIGEXARGS
2066{
2067 PCDBGFINTERRUPTCONFIG paConfigs;
2068 size_t cConfigs;
2069 int rc;
2070} DBGFR3INTERRUPTCONFIGEXARGS;
2071/** Pointer to a dbgfR3InterruptConfigEx argument packet. */
2072typedef DBGFR3INTERRUPTCONFIGEXARGS *PDBGFR3INTERRUPTCONFIGEXARGS;
2073
2074/**
2075 * @callback_method_impl{FNVMMEMTRENDEZVOUS,
2076 * Worker for DBGFR3InterruptConfigEx.}
2077 */
2078static DECLCALLBACK(VBOXSTRICTRC) dbgfR3InterruptConfigEx(PVM pVM, PVMCPU pVCpu, void *pvUser)
2079{
2080 if (pVCpu->idCpu == 0)
2081 {
2082 PDBGFR3INTERRUPTCONFIGEXARGS pArgs = (PDBGFR3INTERRUPTCONFIGEXARGS)pvUser;
2083 PCDBGFINTERRUPTCONFIG paConfigs = pArgs->paConfigs;
2084 size_t cConfigs = pArgs->cConfigs;
2085
2086 /*
2087 * Apply the changes.
2088 */
2089 bool fChanged = false;
2090 bool fThis;
2091 for (uint32_t i = 0; i < cConfigs; i++)
2092 {
2093 /*
2094 * Hardware interrupts.
2095 */
2096 if (paConfigs[i].enmHardState == DBGFINTERRUPTSTATE_ENABLED)
2097 {
2098 fChanged |= fThis = ASMAtomicBitTestAndSet(&pVM->dbgf.s.bmHardIntBreakpoints, paConfigs[i].iInterrupt) == false;
2099 if (fThis)
2100 {
2101 Assert(pVM->dbgf.s.cHardIntBreakpoints < 256);
2102 pVM->dbgf.s.cHardIntBreakpoints++;
2103 }
2104 }
2105 else if (paConfigs[i].enmHardState == DBGFINTERRUPTSTATE_DISABLED)
2106 {
2107 fChanged |= fThis = ASMAtomicBitTestAndClear(&pVM->dbgf.s.bmHardIntBreakpoints, paConfigs[i].iInterrupt) == true;
2108 if (fThis)
2109 {
2110 Assert(pVM->dbgf.s.cHardIntBreakpoints > 0);
2111 pVM->dbgf.s.cHardIntBreakpoints--;
2112 }
2113 }
2114
2115 /*
2116 * Software interrupts.
2117 */
2118 if (paConfigs[i].enmHardState == DBGFINTERRUPTSTATE_ENABLED)
2119 {
2120 fChanged |= fThis = ASMAtomicBitTestAndSet(&pVM->dbgf.s.bmSoftIntBreakpoints, paConfigs[i].iInterrupt) == false;
2121 if (fThis)
2122 {
2123 Assert(pVM->dbgf.s.cSoftIntBreakpoints < 256);
2124 pVM->dbgf.s.cSoftIntBreakpoints++;
2125 }
2126 }
2127 else if (paConfigs[i].enmSoftState == DBGFINTERRUPTSTATE_DISABLED)
2128 {
2129 fChanged |= fThis = ASMAtomicBitTestAndClear(&pVM->dbgf.s.bmSoftIntBreakpoints, paConfigs[i].iInterrupt) == true;
2130 if (fThis)
2131 {
2132 Assert(pVM->dbgf.s.cSoftIntBreakpoints > 0);
2133 pVM->dbgf.s.cSoftIntBreakpoints--;
2134 }
2135 }
2136 }
2137
2138 /*
2139 * Update the event bitmap entries.
2140 */
2141 if (pVM->dbgf.s.cHardIntBreakpoints > 0)
2142 fChanged |= ASMAtomicBitTestAndSet(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_INTERRUPT_HARDWARE) == false;
2143 else
2144 fChanged |= ASMAtomicBitTestAndClear(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_INTERRUPT_HARDWARE) == true;
2145
2146 if (pVM->dbgf.s.cSoftIntBreakpoints > 0)
2147 fChanged |= ASMAtomicBitTestAndSet(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_INTERRUPT_SOFTWARE) == false;
2148 else
2149 fChanged |= ASMAtomicBitTestAndClear(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_INTERRUPT_SOFTWARE) == true;
2150
2151 /*
2152 * Inform HM about changes.
2153 */
2154 if (fChanged)
2155 {
2156 if (HMIsEnabled(pVM))
2157 {
2158 HMR3NotifyDebugEventChanged(pVM);
2159 HMR3NotifyDebugEventChangedPerCpu(pVM, pVCpu);
2160 }
2161 else if (VM_IS_NEM_ENABLED(pVM))
2162 {
2163 NEMR3NotifyDebugEventChanged(pVM);
2164 NEMR3NotifyDebugEventChangedPerCpu(pVM, pVCpu);
2165 }
2166 }
2167 }
2168 else if (HMIsEnabled(pVM))
2169 HMR3NotifyDebugEventChangedPerCpu(pVM, pVCpu);
2170 else if (VM_IS_NEM_ENABLED(pVM))
2171 NEMR3NotifyDebugEventChangedPerCpu(pVM, pVCpu);
2172
2173 return VINF_SUCCESS;
2174}
2175
2176
2177/**
2178 * Changes
2179 *
2180 * @returns VBox status code.
2181 * @param pUVM The user mode VM handle.
2182 * @param paConfigs The events to query and where to return the state.
2183 * @param cConfigs The number of elements in @a paConfigs.
2184 * @sa DBGFR3InterruptConfigHardware, DBGFR3InterruptConfigSoftware
2185 */
2186VMMR3DECL(int) DBGFR3InterruptConfigEx(PUVM pUVM, PCDBGFINTERRUPTCONFIG paConfigs, size_t cConfigs)
2187{
2188 /*
2189 * Validate input.
2190 */
2191 size_t i = cConfigs;
2192 while (i-- > 0)
2193 {
2194 AssertReturn(paConfigs[i].enmHardState <= DBGFINTERRUPTSTATE_DONT_TOUCH, VERR_INVALID_PARAMETER);
2195 AssertReturn(paConfigs[i].enmSoftState <= DBGFINTERRUPTSTATE_DONT_TOUCH, VERR_INVALID_PARAMETER);
2196 }
2197
2198 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
2199 PVM pVM = pUVM->pVM;
2200 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
2201
2202 /*
2203 * Apply the changes in EMT(0) and rendezvous with the other CPUs so they
2204 * can sync their data and execution with new debug state.
2205 */
2206 DBGFR3INTERRUPTCONFIGEXARGS Args = { paConfigs, cConfigs, VINF_SUCCESS };
2207 int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING | VMMEMTRENDEZVOUS_FLAGS_PRIORITY,
2208 dbgfR3InterruptConfigEx, &Args);
2209 if (RT_SUCCESS(rc))
2210 rc = Args.rc;
2211 return rc;
2212}
2213
2214
2215/**
2216 * Configures interception of a hardware interrupt.
2217 *
2218 * @returns VBox status code.
2219 * @param pUVM The user mode VM handle.
2220 * @param iInterrupt The interrupt number.
2221 * @param fEnabled Whether interception is enabled or not.
2222 * @sa DBGFR3InterruptSoftwareConfig, DBGFR3InterruptConfigEx
2223 */
2224VMMR3DECL(int) DBGFR3InterruptHardwareConfig(PUVM pUVM, uint8_t iInterrupt, bool fEnabled)
2225{
2226 /*
2227 * Convert to DBGFR3InterruptConfigEx call.
2228 */
2229 DBGFINTERRUPTCONFIG IntCfg = { iInterrupt, (uint8_t)fEnabled, DBGFINTERRUPTSTATE_DONT_TOUCH };
2230 return DBGFR3InterruptConfigEx(pUVM, &IntCfg, 1);
2231}
2232
2233
2234/**
2235 * Configures interception of a software interrupt.
2236 *
2237 * @returns VBox status code.
2238 * @param pUVM The user mode VM handle.
2239 * @param iInterrupt The interrupt number.
2240 * @param fEnabled Whether interception is enabled or not.
2241 * @sa DBGFR3InterruptHardwareConfig, DBGFR3InterruptConfigEx
2242 */
2243VMMR3DECL(int) DBGFR3InterruptSoftwareConfig(PUVM pUVM, uint8_t iInterrupt, bool fEnabled)
2244{
2245 /*
2246 * Convert to DBGFR3InterruptConfigEx call.
2247 */
2248 DBGFINTERRUPTCONFIG IntCfg = { iInterrupt, DBGFINTERRUPTSTATE_DONT_TOUCH, (uint8_t)fEnabled };
2249 return DBGFR3InterruptConfigEx(pUVM, &IntCfg, 1);
2250}
2251
2252
2253/**
2254 * Checks whether interception is enabled for a hardware interrupt.
2255 *
2256 * @returns true if enabled, false if not or invalid input.
2257 * @param pUVM The user mode VM handle.
2258 * @param iInterrupt The interrupt number.
2259 * @sa DBGFR3InterruptSoftwareIsEnabled, DBGF_IS_HARDWARE_INT_ENABLED,
2260 * DBGF_IS_SOFTWARE_INT_ENABLED
2261 */
2262VMMR3DECL(int) DBGFR3InterruptHardwareIsEnabled(PUVM pUVM, uint8_t iInterrupt)
2263{
2264 /*
2265 * Validate input.
2266 */
2267 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
2268 PVM pVM = pUVM->pVM;
2269 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
2270
2271 /*
2272 * Check it.
2273 */
2274 return ASMBitTest(&pVM->dbgf.s.bmHardIntBreakpoints, iInterrupt);
2275}
2276
2277
2278/**
2279 * Checks whether interception is enabled for a software interrupt.
2280 *
2281 * @returns true if enabled, false if not or invalid input.
2282 * @param pUVM The user mode VM handle.
2283 * @param iInterrupt The interrupt number.
2284 * @sa DBGFR3InterruptHardwareIsEnabled, DBGF_IS_SOFTWARE_INT_ENABLED,
2285 * DBGF_IS_HARDWARE_INT_ENABLED,
2286 */
2287VMMR3DECL(int) DBGFR3InterruptSoftwareIsEnabled(PUVM pUVM, uint8_t iInterrupt)
2288{
2289 /*
2290 * Validate input.
2291 */
2292 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
2293 PVM pVM = pUVM->pVM;
2294 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
2295
2296 /*
2297 * Check it.
2298 */
2299 return ASMBitTest(&pVM->dbgf.s.bmSoftIntBreakpoints, iInterrupt);
2300}
2301
2302
2303
2304/**
2305 * Call this to single step programmatically.
2306 *
2307 * You must pass down the return code to the EM loop! That's
2308 * where the actual single stepping take place (at least in the
2309 * current implementation).
2310 *
2311 * @returns VINF_EM_DBG_STEP
2312 *
2313 * @param pVCpu The cross context virtual CPU structure.
2314 *
2315 * @thread VCpu EMT
2316 * @internal
2317 */
2318VMMR3_INT_DECL(int) DBGFR3PrgStep(PVMCPU pVCpu)
2319{
2320 VMCPU_ASSERT_EMT(pVCpu);
2321
2322 pVCpu->dbgf.s.fSingleSteppingRaw = true;
2323 return VINF_EM_DBG_STEP;
2324}
2325
2326
2327/**
2328 * Inject an NMI into a running VM (only VCPU 0!)
2329 *
2330 * @returns VBox status code.
2331 * @param pUVM The user mode VM structure.
2332 * @param idCpu The ID of the CPU to inject the NMI on.
2333 */
2334VMMR3DECL(int) DBGFR3InjectNMI(PUVM pUVM, VMCPUID idCpu)
2335{
2336 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
2337 PVM pVM = pUVM->pVM;
2338 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
2339 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
2340
2341 /** @todo Implement generic NMI injection. */
2342 /** @todo NEM: NMI injection */
2343 if (!HMIsEnabled(pVM))
2344 return VERR_NOT_SUP_BY_NEM;
2345
2346 VMCPU_FF_SET(pVM->apCpusR3[idCpu], VMCPU_FF_INTERRUPT_NMI);
2347 return VINF_SUCCESS;
2348}
2349
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