VirtualBox

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

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

VMM/DBGF: First commit of new tracing facility, bugref:9210

The new DBGF tracing facility allows efficient capturing of events to a compact binary
trace log for later analysis. It is primarily intended for recording device/guest
interactions for now but can be extended easily for other types of events later on.
It supports capturing events happening in both R0 and R3 by using a shared ring buffer
to post events to. The events are processed by a dedicated I/O thread which writes
new events into the binary trace log file.

This is only the core VMM/DBGF part providing the API, the integration with PDM
comes in a separate commit.

Disabled by default for now because it is still work in progress,
enable with VBOX_WITH_DBGF_TRACING.

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