VirtualBox

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

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

VMM/r3: Refactored VMCPU enumeration in preparation that aCpus will be replaced with a pointer array. Removed two raw-mode offset members from the CPUM and CPUMCPU sub-structures. bugref:9217 bugref:9517

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