VirtualBox

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

最後變更 在這個檔案從81150是 81150,由 vboxsync 提交於 5 年 前

VMM,/Makefile.kmk: Kicked out more recompiler related code. bugref:9576

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette