VirtualBox

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

Last change on this file since 58938 was 58938, checked in by vboxsync, 9 years ago

HM,DBGF: Made DBGF notify HM about changes to VMM event and interrupt breakpoints. Made HM cache the basic info wrt ring-0 loop selection, opting for using a debug loop when debugging takes place to avoid cluttering slowing down the normal execution loop. The plan is to extend the single stepping loop and to put complicated dtrace probes into the same loop. Modified the VMX loop selection already.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 50.0 KB
Line 
1/* $Id: DBGF.cpp 58938 2015-12-01 14:17:45Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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#ifdef VBOX_WITH_REM
76# include <VBox/vmm/rem.h>
77#endif
78#include <VBox/vmm/em.h>
79#include <VBox/vmm/hm.h>
80#include "DBGFInternal.h"
81#include <VBox/vmm/vm.h>
82#include <VBox/vmm/uvm.h>
83#include <VBox/err.h>
84
85#include <VBox/log.h>
86#include <iprt/semaphore.h>
87#include <iprt/thread.h>
88#include <iprt/asm.h>
89#include <iprt/time.h>
90#include <iprt/assert.h>
91#include <iprt/stream.h>
92#include <iprt/env.h>
93
94
95/*********************************************************************************************************************************
96* Internal Functions *
97*********************************************************************************************************************************/
98static int dbgfR3VMMWait(PVM pVM);
99static int dbgfR3VMMCmd(PVM pVM, DBGFCMD enmCmd, PDBGFCMDDATA pCmdData, bool *pfResumeExecution);
100static DECLCALLBACK(int) dbgfR3Attach(PVM pVM);
101
102
103/**
104 * Sets the VMM Debug Command variable.
105 *
106 * @returns Previous command.
107 * @param pVM The cross context VM structure.
108 * @param enmCmd The command.
109 */
110DECLINLINE(DBGFCMD) dbgfR3SetCmd(PVM pVM, DBGFCMD enmCmd)
111{
112 DBGFCMD rc;
113 if (enmCmd == DBGFCMD_NO_COMMAND)
114 {
115 Log2(("DBGF: Setting command to %d (DBGFCMD_NO_COMMAND)\n", enmCmd));
116 rc = (DBGFCMD)ASMAtomicXchgU32((uint32_t volatile *)(void *)&pVM->dbgf.s.enmVMMCmd, enmCmd);
117 VM_FF_CLEAR(pVM, VM_FF_DBGF);
118 }
119 else
120 {
121 Log2(("DBGF: Setting command to %d\n", enmCmd));
122 AssertMsg(pVM->dbgf.s.enmVMMCmd == DBGFCMD_NO_COMMAND, ("enmCmd=%d enmVMMCmd=%d\n", enmCmd, pVM->dbgf.s.enmVMMCmd));
123 rc = (DBGFCMD)ASMAtomicXchgU32((uint32_t volatile *)(void *)&pVM->dbgf.s.enmVMMCmd, enmCmd);
124 VM_FF_SET(pVM, VM_FF_DBGF);
125 VMR3NotifyGlobalFFU(pVM->pUVM, 0 /* didn't notify REM */);
126 }
127 return rc;
128}
129
130
131/**
132 * Initializes the DBGF.
133 *
134 * @returns VBox status code.
135 * @param pVM The cross context VM structure.
136 */
137VMMR3_INT_DECL(int) DBGFR3Init(PVM pVM)
138{
139 PUVM pUVM = pVM->pUVM;
140 AssertCompile(sizeof(pUVM->dbgf.s) <= sizeof(pUVM->dbgf.padding));
141 AssertCompile(sizeof(pUVM->aCpus[0].dbgf.s) <= sizeof(pUVM->aCpus[0].dbgf.padding));
142
143 /*
144 * The usual sideways mountain climbing style of init:
145 */
146 int rc = dbgfR3InfoInit(pUVM); /* (First, initalizes the shared critical section.) */
147 if (RT_SUCCESS(rc))
148 {
149 rc = dbgfR3TraceInit(pVM);
150 if (RT_SUCCESS(rc))
151 {
152 rc = dbgfR3RegInit(pUVM);
153 if (RT_SUCCESS(rc))
154 {
155 rc = dbgfR3AsInit(pUVM);
156 if (RT_SUCCESS(rc))
157 {
158 rc = dbgfR3BpInit(pVM);
159 if (RT_SUCCESS(rc))
160 {
161 rc = dbgfR3OSInit(pUVM);
162 if (RT_SUCCESS(rc))
163 {
164 rc = dbgfR3PlugInInit(pUVM);
165 if (RT_SUCCESS(rc))
166 {
167 return VINF_SUCCESS;
168 }
169 dbgfR3OSTerm(pUVM);
170 }
171 }
172 dbgfR3AsTerm(pUVM);
173 }
174 dbgfR3RegTerm(pUVM);
175 }
176 dbgfR3TraceTerm(pVM);
177 }
178 dbgfR3InfoTerm(pUVM);
179 }
180 return rc;
181}
182
183
184/**
185 * Terminates and cleans up resources allocated by the DBGF.
186 *
187 * @returns VBox status code.
188 * @param pVM The cross context VM structure.
189 */
190VMMR3_INT_DECL(int) DBGFR3Term(PVM pVM)
191{
192 PUVM pUVM = pVM->pUVM;
193
194 dbgfR3PlugInTerm(pUVM);
195 dbgfR3OSTerm(pUVM);
196 dbgfR3AsTerm(pUVM);
197 dbgfR3RegTerm(pUVM);
198 dbgfR3TraceTerm(pVM);
199 dbgfR3InfoTerm(pUVM);
200
201 return VINF_SUCCESS;
202}
203
204
205/**
206 * Called when the VM is powered off to detach debuggers.
207 *
208 * @param pVM The cross context VM structure.
209 */
210VMMR3_INT_DECL(void) DBGFR3PowerOff(PVM pVM)
211{
212
213 /*
214 * Send a termination event to any attached debugger.
215 */
216 /* wait to become the speaker (we should already be that). */
217 if ( pVM->dbgf.s.fAttached
218 && RTSemPingShouldWait(&pVM->dbgf.s.PingPong))
219 RTSemPingWait(&pVM->dbgf.s.PingPong, 5000);
220
221 if (pVM->dbgf.s.fAttached)
222 {
223 /* Just mark it as detached if we're not in a position to send a power
224 off event. It should fail later on. */
225 if (!RTSemPingIsSpeaker(&pVM->dbgf.s.PingPong))
226 {
227 ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, false);
228 if (RTSemPingIsSpeaker(&pVM->dbgf.s.PingPong))
229 ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, true);
230 }
231
232 if (RTSemPingIsSpeaker(&pVM->dbgf.s.PingPong))
233 {
234 /* Try send the power off event. */
235 int rc;
236 DBGFCMD enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND);
237 if (enmCmd == DBGFCMD_DETACH_DEBUGGER)
238 /* the debugger beat us to initiating the detaching. */
239 rc = VINF_SUCCESS;
240 else
241 {
242 /* ignore the command (if any). */
243 enmCmd = DBGFCMD_NO_COMMAND;
244 pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_POWERING_OFF;
245 pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_OTHER;
246 rc = RTSemPing(&pVM->dbgf.s.PingPong);
247 }
248
249 /*
250 * Process commands and priority requests until we get a command
251 * indicating that the debugger has detached.
252 */
253 uint32_t cPollHack = 1;
254 PVMCPU pVCpu = VMMGetCpu(pVM);
255 while (RT_SUCCESS(rc))
256 {
257 if (enmCmd != DBGFCMD_NO_COMMAND)
258 {
259 /* process command */
260 bool fResumeExecution;
261 DBGFCMDDATA CmdData = pVM->dbgf.s.VMMCmdData;
262 rc = dbgfR3VMMCmd(pVM, enmCmd, &CmdData, &fResumeExecution);
263 if (enmCmd == DBGFCMD_DETACHED_DEBUGGER)
264 break;
265 enmCmd = DBGFCMD_NO_COMMAND;
266 }
267 else
268 {
269 /* Wait for new command, processing pending priority requests
270 first. The request processing is a bit crazy, but
271 unfortunately required by plugin unloading. */
272 if ( VM_FF_IS_PENDING(pVM, VM_FF_REQUEST)
273 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_REQUEST))
274 {
275 LogFlow(("DBGFR3PowerOff: Processes priority requests...\n"));
276 rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY, true /*fPriorityOnly*/);
277 if (rc == VINF_SUCCESS)
278 rc = VMR3ReqProcessU(pVM->pUVM, pVCpu->idCpu, true /*fPriorityOnly*/);
279 LogFlow(("DBGFR3PowerOff: VMR3ReqProcess -> %Rrc\n", rc));
280 cPollHack = 1;
281 }
282 else if (cPollHack < 120)
283 cPollHack++;
284
285 rc = RTSemPingWait(&pVM->dbgf.s.PingPong, cPollHack);
286 if (RT_SUCCESS(rc))
287 enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND);
288 else if (rc == VERR_TIMEOUT)
289 rc = VINF_SUCCESS;
290 }
291 }
292
293 /*
294 * Clear the FF so we won't get confused later on.
295 */
296 VM_FF_CLEAR(pVM, VM_FF_DBGF);
297 }
298 }
299}
300
301
302/**
303 * Applies relocations to data and code managed by this
304 * component. This function will be called at init and
305 * whenever the VMM need to relocate it self inside the GC.
306 *
307 * @param pVM The cross context VM structure.
308 * @param offDelta Relocation delta relative to old location.
309 */
310VMMR3_INT_DECL(void) DBGFR3Relocate(PVM pVM, RTGCINTPTR offDelta)
311{
312 dbgfR3TraceRelocate(pVM);
313 dbgfR3AsRelocate(pVM->pUVM, offDelta);
314}
315
316
317/**
318 * Waits a little while for a debuggger to attach.
319 *
320 * @returns True is a debugger have attached.
321 * @param pVM The cross context VM structure.
322 * @param enmEvent Event.
323 */
324bool dbgfR3WaitForAttach(PVM pVM, DBGFEVENTTYPE enmEvent)
325{
326 /*
327 * First a message.
328 */
329#ifndef RT_OS_L4
330
331# if !defined(DEBUG) || defined(DEBUG_sandervl) || defined(DEBUG_frank) || defined(IEM_VERIFICATION_MODE)
332 int cWait = 10;
333# else
334 int cWait = HMIsEnabled(pVM)
335 && ( enmEvent == DBGFEVENT_ASSERTION_HYPER
336 || enmEvent == DBGFEVENT_FATAL_ERROR)
337 && !RTEnvExist("VBOX_DBGF_WAIT_FOR_ATTACH")
338 ? 10
339 : 150;
340# endif
341 RTStrmPrintf(g_pStdErr, "DBGF: No debugger attached, waiting %d second%s for one to attach (event=%d)\n",
342 cWait / 10, cWait != 10 ? "s" : "", enmEvent);
343 RTStrmFlush(g_pStdErr);
344 while (cWait > 0)
345 {
346 RTThreadSleep(100);
347 if (pVM->dbgf.s.fAttached)
348 {
349 RTStrmPrintf(g_pStdErr, "Attached!\n");
350 RTStrmFlush(g_pStdErr);
351 return true;
352 }
353
354 /* next */
355 if (!(cWait % 10))
356 {
357 RTStrmPrintf(g_pStdErr, "%d.", cWait / 10);
358 RTStrmFlush(g_pStdErr);
359 }
360 cWait--;
361 }
362#endif
363
364 RTStrmPrintf(g_pStdErr, "Stopping the VM!\n");
365 RTStrmFlush(g_pStdErr);
366 return false;
367}
368
369
370/**
371 * Forced action callback.
372 * The VMM will call this from it's main loop when VM_FF_DBGF is set.
373 *
374 * The function checks and executes pending commands from the debugger.
375 *
376 * @returns VINF_SUCCESS normally.
377 * @returns VERR_DBGF_RAISE_FATAL_ERROR to pretend a fatal error happened.
378 * @param pVM The cross context VM structure.
379 */
380VMMR3_INT_DECL(int) DBGFR3VMMForcedAction(PVM pVM)
381{
382 int rc = VINF_SUCCESS;
383
384 if (VM_FF_TEST_AND_CLEAR(pVM, VM_FF_DBGF))
385 {
386 PVMCPU pVCpu = VMMGetCpu(pVM);
387
388 /*
389 * Command pending? Process it.
390 */
391 if (pVM->dbgf.s.enmVMMCmd != DBGFCMD_NO_COMMAND)
392 {
393 bool fResumeExecution;
394 DBGFCMDDATA CmdData = pVM->dbgf.s.VMMCmdData;
395 DBGFCMD enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND);
396 rc = dbgfR3VMMCmd(pVM, enmCmd, &CmdData, &fResumeExecution);
397 if (!fResumeExecution)
398 rc = dbgfR3VMMWait(pVM);
399 }
400 }
401 return rc;
402}
403
404
405/**
406 * Flag whether the event implies that we're stopped in the hypervisor code
407 * and have to block certain operations.
408 *
409 * @param pVM The cross context VM structure.
410 * @param enmEvent The event.
411 */
412static void dbgfR3EventSetStoppedInHyperFlag(PVM pVM, DBGFEVENTTYPE enmEvent)
413{
414 switch (enmEvent)
415 {
416 case DBGFEVENT_STEPPED_HYPER:
417 case DBGFEVENT_ASSERTION_HYPER:
418 case DBGFEVENT_BREAKPOINT_HYPER:
419 pVM->dbgf.s.fStoppedInHyper = true;
420 break;
421 default:
422 pVM->dbgf.s.fStoppedInHyper = false;
423 break;
424 }
425}
426
427
428/**
429 * Try to determine the event context.
430 *
431 * @returns debug event context.
432 * @param pVM The cross context VM structure.
433 */
434static DBGFEVENTCTX dbgfR3FigureEventCtx(PVM pVM)
435{
436 /** @todo SMP support! */
437 PVMCPU pVCpu = &pVM->aCpus[0];
438
439 switch (EMGetState(pVCpu))
440 {
441 case EMSTATE_RAW:
442 case EMSTATE_DEBUG_GUEST_RAW:
443 return DBGFEVENTCTX_RAW;
444
445 case EMSTATE_REM:
446 case EMSTATE_DEBUG_GUEST_REM:
447 return DBGFEVENTCTX_REM;
448
449 case EMSTATE_DEBUG_HYPER:
450 case EMSTATE_GURU_MEDITATION:
451 return DBGFEVENTCTX_HYPER;
452
453 default:
454 return DBGFEVENTCTX_OTHER;
455 }
456}
457
458/**
459 * The common event prologue code.
460 * It will set the 'stopped-in-hyper' flag, make sure someone is attached,
461 * and perhaps process any high priority pending actions (none yet).
462 *
463 * @returns VBox status code.
464 * @param pVM The cross context VM structure.
465 * @param enmEvent The event to be sent.
466 */
467static int dbgfR3EventPrologue(PVM pVM, DBGFEVENTTYPE enmEvent)
468{
469 /** @todo SMP */
470 PVMCPU pVCpu = VMMGetCpu(pVM);
471
472 /*
473 * Check if a debugger is attached.
474 */
475 if ( !pVM->dbgf.s.fAttached
476 && !dbgfR3WaitForAttach(pVM, enmEvent))
477 {
478 Log(("DBGFR3VMMEventSrc: enmEvent=%d - debugger not attached\n", enmEvent));
479 return VERR_DBGF_NOT_ATTACHED;
480 }
481
482 /*
483 * Sync back the state from the REM.
484 */
485 dbgfR3EventSetStoppedInHyperFlag(pVM, enmEvent);
486#ifdef VBOX_WITH_REM
487 if (!pVM->dbgf.s.fStoppedInHyper)
488 REMR3StateUpdate(pVM, pVCpu);
489#endif
490
491 /*
492 * Look thru pending commands and finish those which make sense now.
493 */
494 /** @todo Process/purge pending commands. */
495 //int rc = DBGFR3VMMForcedAction(pVM);
496 return VINF_SUCCESS;
497}
498
499
500/**
501 * Sends the event in the event buffer.
502 *
503 * @returns VBox status code.
504 * @param pVM The cross context VM structure.
505 */
506static int dbgfR3SendEvent(PVM pVM)
507{
508 int rc = RTSemPing(&pVM->dbgf.s.PingPong);
509 if (RT_SUCCESS(rc))
510 rc = dbgfR3VMMWait(pVM);
511
512 pVM->dbgf.s.fStoppedInHyper = false;
513 /** @todo sync VMM -> REM after exitting the debugger. everything may change while in the debugger! */
514 return rc;
515}
516
517
518/**
519 * Send a generic debugger event which takes no data.
520 *
521 * @returns VBox status code.
522 * @param pVM The cross context VM structure.
523 * @param enmEvent The event to send.
524 * @internal
525 */
526VMMR3DECL(int) DBGFR3Event(PVM pVM, DBGFEVENTTYPE enmEvent)
527{
528 int rc = dbgfR3EventPrologue(pVM, enmEvent);
529 if (RT_FAILURE(rc))
530 return rc;
531
532 /*
533 * Send the event and process the reply communication.
534 */
535 pVM->dbgf.s.DbgEvent.enmType = enmEvent;
536 pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM);
537 return dbgfR3SendEvent(pVM);
538}
539
540
541/**
542 * Send a debugger event which takes the full source file location.
543 *
544 * @returns VBox status code.
545 * @param pVM The cross context VM structure.
546 * @param enmEvent The event to send.
547 * @param pszFile Source file.
548 * @param uLine Line number in source file.
549 * @param pszFunction Function name.
550 * @param pszFormat Message which accompanies the event.
551 * @param ... Message arguments.
552 * @internal
553 */
554VMMR3DECL(int) DBGFR3EventSrc(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, const char *pszFunction, const char *pszFormat, ...)
555{
556 va_list args;
557 va_start(args, pszFormat);
558 int rc = DBGFR3EventSrcV(pVM, enmEvent, pszFile, uLine, pszFunction, pszFormat, args);
559 va_end(args);
560 return rc;
561}
562
563
564/**
565 * Send a debugger event which takes the full source file location.
566 *
567 * @returns VBox status code.
568 * @param pVM The cross context VM structure.
569 * @param enmEvent The event to send.
570 * @param pszFile Source file.
571 * @param uLine Line number in source file.
572 * @param pszFunction Function name.
573 * @param pszFormat Message which accompanies the event.
574 * @param args Message arguments.
575 * @internal
576 */
577VMMR3DECL(int) DBGFR3EventSrcV(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, const char *pszFunction, const char *pszFormat, va_list args)
578{
579 int rc = dbgfR3EventPrologue(pVM, enmEvent);
580 if (RT_FAILURE(rc))
581 return rc;
582
583 /*
584 * Format the message.
585 */
586 char *pszMessage = NULL;
587 char szMessage[8192];
588 if (pszFormat && *pszFormat)
589 {
590 pszMessage = &szMessage[0];
591 RTStrPrintfV(szMessage, sizeof(szMessage), pszFormat, args);
592 }
593
594 /*
595 * Send the event and process the reply communication.
596 */
597 pVM->dbgf.s.DbgEvent.enmType = enmEvent;
598 pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM);
599 pVM->dbgf.s.DbgEvent.u.Src.pszFile = pszFile;
600 pVM->dbgf.s.DbgEvent.u.Src.uLine = uLine;
601 pVM->dbgf.s.DbgEvent.u.Src.pszFunction = pszFunction;
602 pVM->dbgf.s.DbgEvent.u.Src.pszMessage = pszMessage;
603 return dbgfR3SendEvent(pVM);
604}
605
606
607/**
608 * Send a debugger event which takes the two assertion messages.
609 *
610 * @returns VBox status code.
611 * @param pVM The cross context VM structure.
612 * @param enmEvent The event to send.
613 * @param pszMsg1 First assertion message.
614 * @param pszMsg2 Second assertion message.
615 */
616VMMR3_INT_DECL(int) DBGFR3EventAssertion(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszMsg1, const char *pszMsg2)
617{
618 int rc = dbgfR3EventPrologue(pVM, enmEvent);
619 if (RT_FAILURE(rc))
620 return rc;
621
622 /*
623 * Send the event and process the reply communication.
624 */
625 pVM->dbgf.s.DbgEvent.enmType = enmEvent;
626 pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM);
627 pVM->dbgf.s.DbgEvent.u.Assert.pszMsg1 = pszMsg1;
628 pVM->dbgf.s.DbgEvent.u.Assert.pszMsg2 = pszMsg2;
629 return dbgfR3SendEvent(pVM);
630}
631
632
633/**
634 * Breakpoint was hit somewhere.
635 * Figure out which breakpoint it is and notify the debugger.
636 *
637 * @returns VBox status code.
638 * @param pVM The cross context VM structure.
639 * @param enmEvent DBGFEVENT_BREAKPOINT_HYPER or DBGFEVENT_BREAKPOINT.
640 */
641VMMR3_INT_DECL(int) DBGFR3EventBreakpoint(PVM pVM, DBGFEVENTTYPE enmEvent)
642{
643 int rc = dbgfR3EventPrologue(pVM, enmEvent);
644 if (RT_FAILURE(rc))
645 return rc;
646
647 /*
648 * Send the event and process the reply communication.
649 */
650 /** @todo SMP */
651 PVMCPU pVCpu = VMMGetCpu0(pVM);
652
653 pVM->dbgf.s.DbgEvent.enmType = enmEvent;
654 RTUINT iBp = pVM->dbgf.s.DbgEvent.u.Bp.iBp = pVCpu->dbgf.s.iActiveBp;
655 pVCpu->dbgf.s.iActiveBp = ~0U;
656 if (iBp != ~0U)
657 pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_RAW;
658 else
659 {
660 /* REM breakpoints has be been searched for. */
661#if 0 /** @todo get flat PC api! */
662 uint32_t eip = CPUMGetGuestEIP(pVM);
663#else
664 /* @todo SMP support!! */
665 PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(VMMGetCpu(pVM));
666 RTGCPTR eip = pCtx->rip + pCtx->cs.u64Base;
667#endif
668 for (size_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
669 if ( pVM->dbgf.s.aBreakpoints[i].enmType == DBGFBPTYPE_REM
670 && pVM->dbgf.s.aBreakpoints[i].u.Rem.GCPtr == eip)
671 {
672 pVM->dbgf.s.DbgEvent.u.Bp.iBp = pVM->dbgf.s.aBreakpoints[i].iBp;
673 break;
674 }
675 AssertMsg(pVM->dbgf.s.DbgEvent.u.Bp.iBp != ~0U, ("eip=%08x\n", eip));
676 pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_REM;
677 }
678 return dbgfR3SendEvent(pVM);
679}
680
681
682/**
683 * Waits for the debugger to respond.
684 *
685 * @returns VBox status code. (clearify)
686 * @param pVM The cross context VM structure.
687 */
688static int dbgfR3VMMWait(PVM pVM)
689{
690 PVMCPU pVCpu = VMMGetCpu(pVM);
691
692 LogFlow(("dbgfR3VMMWait:\n"));
693 int rcRet = VINF_SUCCESS;
694
695 /*
696 * Waits for the debugger to reply (i.e. issue an command).
697 */
698 for (;;)
699 {
700 /*
701 * Wait.
702 */
703 uint32_t cPollHack = 1; /** @todo this interface is horrible now that we're using lots of VMR3ReqCall stuff all over DBGF. */
704 for (;;)
705 {
706 int rc;
707 if ( !VM_FF_IS_PENDING(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_REQUEST)
708 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_REQUEST))
709 {
710 rc = RTSemPingWait(&pVM->dbgf.s.PingPong, cPollHack);
711 if (RT_SUCCESS(rc))
712 break;
713 if (rc != VERR_TIMEOUT)
714 {
715 LogFlow(("dbgfR3VMMWait: returns %Rrc\n", rc));
716 return rc;
717 }
718 }
719
720 if (VM_FF_IS_PENDING(pVM, VM_FF_EMT_RENDEZVOUS))
721 {
722 rc = VMMR3EmtRendezvousFF(pVM, pVCpu);
723 cPollHack = 1;
724 }
725 else if ( VM_FF_IS_PENDING(pVM, VM_FF_REQUEST)
726 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_REQUEST))
727 {
728 LogFlow(("dbgfR3VMMWait: Processes requests...\n"));
729 rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY, false /*fPriorityOnly*/);
730 if (rc == VINF_SUCCESS)
731 rc = VMR3ReqProcessU(pVM->pUVM, pVCpu->idCpu, false /*fPriorityOnly*/);
732 LogFlow(("dbgfR3VMMWait: VMR3ReqProcess -> %Rrc rcRet=%Rrc\n", rc, rcRet));
733 cPollHack = 1;
734 }
735 else
736 {
737 rc = VINF_SUCCESS;
738 if (cPollHack < 120)
739 cPollHack++;
740 }
741
742 if (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST)
743 {
744 switch (rc)
745 {
746 case VINF_EM_DBG_BREAKPOINT:
747 case VINF_EM_DBG_STEPPED:
748 case VINF_EM_DBG_STEP:
749 case VINF_EM_DBG_STOP:
750 AssertMsgFailed(("rc=%Rrc\n", rc));
751 break;
752
753 /* return straight away */
754 case VINF_EM_TERMINATE:
755 case VINF_EM_OFF:
756 LogFlow(("dbgfR3VMMWait: returns %Rrc\n", rc));
757 return rc;
758
759 /* remember return code. */
760 default:
761 AssertReleaseMsgFailed(("rc=%Rrc is not in the switch!\n", rc));
762 case VINF_EM_RESET:
763 case VINF_EM_SUSPEND:
764 case VINF_EM_HALT:
765 case VINF_EM_RESUME:
766 case VINF_EM_RESCHEDULE:
767 case VINF_EM_RESCHEDULE_REM:
768 case VINF_EM_RESCHEDULE_RAW:
769 if (rc < rcRet || rcRet == VINF_SUCCESS)
770 rcRet = rc;
771 break;
772 }
773 }
774 else if (RT_FAILURE(rc))
775 {
776 LogFlow(("dbgfR3VMMWait: returns %Rrc\n", rc));
777 return rc;
778 }
779 }
780
781 /*
782 * Process the command.
783 */
784 bool fResumeExecution;
785 DBGFCMDDATA CmdData = pVM->dbgf.s.VMMCmdData;
786 DBGFCMD enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND);
787 int rc = dbgfR3VMMCmd(pVM, enmCmd, &CmdData, &fResumeExecution);
788 if (fResumeExecution)
789 {
790 if (RT_FAILURE(rc))
791 rcRet = rc;
792 else if ( rc >= VINF_EM_FIRST
793 && rc <= VINF_EM_LAST
794 && (rc < rcRet || rcRet == VINF_SUCCESS))
795 rcRet = rc;
796 LogFlow(("dbgfR3VMMWait: returns %Rrc\n", rcRet));
797 return rcRet;
798 }
799 }
800}
801
802
803/**
804 * Executes command from debugger.
805 * The caller is responsible for waiting or resuming execution based on the
806 * value returned in the *pfResumeExecution indicator.
807 *
808 * @returns VBox status code. (clearify!)
809 * @param pVM The cross context VM structure.
810 * @param enmCmd The command in question.
811 * @param pCmdData Pointer to the command data.
812 * @param pfResumeExecution Where to store the resume execution / continue waiting indicator.
813 */
814static int dbgfR3VMMCmd(PVM pVM, DBGFCMD enmCmd, PDBGFCMDDATA pCmdData, bool *pfResumeExecution)
815{
816 bool fSendEvent;
817 bool fResume;
818 int rc = VINF_SUCCESS;
819
820 NOREF(pCmdData); /* for later */
821
822 switch (enmCmd)
823 {
824 /*
825 * Halt is answered by an event say that we've halted.
826 */
827 case DBGFCMD_HALT:
828 {
829 pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_HALT_DONE;
830 pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM);
831 fSendEvent = true;
832 fResume = false;
833 break;
834 }
835
836
837 /*
838 * Resume is not answered we'll just resume execution.
839 */
840 case DBGFCMD_GO:
841 {
842 /** @todo SMP */
843 PVMCPU pVCpu = VMMGetCpu0(pVM);
844 pVCpu->dbgf.s.fSingleSteppingRaw = false;
845 fSendEvent = false;
846 fResume = true;
847 break;
848 }
849
850 /** @todo implement (and define) the rest of the commands. */
851
852 /*
853 * Disable breakpoints and stuff.
854 * Send an everythings cool event to the debugger thread and resume execution.
855 */
856 case DBGFCMD_DETACH_DEBUGGER:
857 {
858 ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, false);
859 pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_DETACH_DONE;
860 pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_OTHER;
861 fSendEvent = true;
862 fResume = true;
863 break;
864 }
865
866 /*
867 * The debugger has detached successfully.
868 * There is no reply to this event.
869 */
870 case DBGFCMD_DETACHED_DEBUGGER:
871 {
872 fSendEvent = false;
873 fResume = true;
874 break;
875 }
876
877 /*
878 * Single step, with trace into.
879 */
880 case DBGFCMD_SINGLE_STEP:
881 {
882 Log2(("Single step\n"));
883 rc = VINF_EM_DBG_STEP;
884 /** @todo SMP */
885 PVMCPU pVCpu = VMMGetCpu0(pVM);
886 pVCpu->dbgf.s.fSingleSteppingRaw = true;
887 fSendEvent = false;
888 fResume = true;
889 break;
890 }
891
892 /*
893 * Default is to send an invalid command event.
894 */
895 default:
896 {
897 pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_INVALID_COMMAND;
898 pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM);
899 fSendEvent = true;
900 fResume = false;
901 break;
902 }
903 }
904
905 /*
906 * Send pending event.
907 */
908 if (fSendEvent)
909 {
910 Log2(("DBGF: Emulation thread: sending event %d\n", pVM->dbgf.s.DbgEvent.enmType));
911 int rc2 = RTSemPing(&pVM->dbgf.s.PingPong);
912 if (RT_FAILURE(rc2))
913 {
914 AssertRC(rc2);
915 *pfResumeExecution = true;
916 return rc2;
917 }
918 }
919
920 /*
921 * Return.
922 */
923 *pfResumeExecution = fResume;
924 return rc;
925}
926
927
928/**
929 * Attaches a debugger to the specified VM.
930 *
931 * Only one debugger at a time.
932 *
933 * @returns VBox status code.
934 * @param pUVM The user mode VM handle.
935 */
936VMMR3DECL(int) DBGFR3Attach(PUVM pUVM)
937{
938 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
939 PVM pVM = pUVM->pVM;
940 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
941
942 /*
943 * Call the VM, use EMT for serialization.
944 */
945 /** @todo SMP */
946 return VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)dbgfR3Attach, 1, pVM);
947}
948
949
950/**
951 * EMT worker for DBGFR3Attach.
952 *
953 * @returns VBox status code.
954 * @param pVM The cross context VM structure.
955 */
956static DECLCALLBACK(int) dbgfR3Attach(PVM pVM)
957{
958 if (pVM->dbgf.s.fAttached)
959 {
960 Log(("dbgR3Attach: Debugger already attached\n"));
961 return VERR_DBGF_ALREADY_ATTACHED;
962 }
963
964 /*
965 * Create the Ping-Pong structure.
966 */
967 int rc = RTSemPingPongInit(&pVM->dbgf.s.PingPong);
968 AssertRCReturn(rc, rc);
969
970 /*
971 * Set the attached flag.
972 */
973 ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, true);
974 return VINF_SUCCESS;
975}
976
977
978/**
979 * Detaches a debugger from the specified VM.
980 *
981 * Caller must be attached to the VM.
982 *
983 * @returns VBox status code.
984 * @param pUVM The user mode VM handle.
985 */
986VMMR3DECL(int) DBGFR3Detach(PUVM pUVM)
987{
988 LogFlow(("DBGFR3Detach:\n"));
989 int rc;
990
991 /*
992 * Validate input. The UVM handle shall be valid, the VM handle might be
993 * in the processes of being destroyed already, so deal quietly with that.
994 */
995 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
996 PVM pVM = pUVM->pVM;
997 if (!VM_IS_VALID_EXT(pVM))
998 return VERR_INVALID_VM_HANDLE;
999
1000 /*
1001 * Check if attached.
1002 */
1003 if (!pVM->dbgf.s.fAttached)
1004 return VERR_DBGF_NOT_ATTACHED;
1005
1006 /*
1007 * Try send the detach command.
1008 * Keep in mind that we might be racing EMT, so, be extra careful.
1009 */
1010 DBGFCMD enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_DETACH_DEBUGGER);
1011 if (RTSemPongIsSpeaker(&pVM->dbgf.s.PingPong))
1012 {
1013 rc = RTSemPong(&pVM->dbgf.s.PingPong);
1014 AssertMsgRCReturn(rc, ("Failed to signal emulation thread. rc=%Rrc\n", rc), rc);
1015 LogRel(("DBGFR3Detach: enmCmd=%d (pong -> ping)\n", enmCmd));
1016 }
1017
1018 /*
1019 * Wait for the OK event.
1020 */
1021 rc = RTSemPongWait(&pVM->dbgf.s.PingPong, RT_INDEFINITE_WAIT);
1022 AssertLogRelMsgRCReturn(rc, ("Wait on detach command failed, rc=%Rrc\n", rc), rc);
1023
1024 /*
1025 * Send the notification command indicating that we're really done.
1026 */
1027 enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_DETACHED_DEBUGGER);
1028 rc = RTSemPong(&pVM->dbgf.s.PingPong);
1029 AssertMsgRCReturn(rc, ("Failed to signal emulation thread. rc=%Rrc\n", rc), rc);
1030
1031 LogFlowFunc(("returns VINF_SUCCESS\n"));
1032 return VINF_SUCCESS;
1033}
1034
1035
1036/**
1037 * Wait for a debug event.
1038 *
1039 * @returns VBox status code. Will not return VBOX_INTERRUPTED.
1040 * @param pUVM The user mode VM handle.
1041 * @param cMillies Number of millis to wait.
1042 * @param ppEvent Where to store the event pointer.
1043 */
1044VMMR3DECL(int) DBGFR3EventWait(PUVM pUVM, RTMSINTERVAL cMillies, PCDBGFEVENT *ppEvent)
1045{
1046 /*
1047 * Check state.
1048 */
1049 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1050 PVM pVM = pUVM->pVM;
1051 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1052 AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
1053 *ppEvent = NULL;
1054
1055 /*
1056 * Wait.
1057 */
1058 int rc = RTSemPongWait(&pVM->dbgf.s.PingPong, cMillies);
1059 if (RT_SUCCESS(rc))
1060 {
1061 *ppEvent = &pVM->dbgf.s.DbgEvent;
1062 Log2(("DBGF: Debugger thread: receiving event %d\n", (*ppEvent)->enmType));
1063 return VINF_SUCCESS;
1064 }
1065
1066 return rc;
1067}
1068
1069
1070/**
1071 * Halts VM execution.
1072 *
1073 * After calling this the VM isn't actually halted till an DBGFEVENT_HALT_DONE
1074 * arrives. Until that time it's not possible to issue any new commands.
1075 *
1076 * @returns VBox status code.
1077 * @param pUVM The user mode VM handle.
1078 */
1079VMMR3DECL(int) DBGFR3Halt(PUVM pUVM)
1080{
1081 /*
1082 * Check state.
1083 */
1084 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1085 PVM pVM = pUVM->pVM;
1086 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1087 AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
1088 RTPINGPONGSPEAKER enmSpeaker = pVM->dbgf.s.PingPong.enmSpeaker;
1089 if ( enmSpeaker == RTPINGPONGSPEAKER_PONG
1090 || enmSpeaker == RTPINGPONGSPEAKER_PONG_SIGNALED)
1091 return VWRN_DBGF_ALREADY_HALTED;
1092
1093 /*
1094 * Send command.
1095 */
1096 dbgfR3SetCmd(pVM, DBGFCMD_HALT);
1097
1098 return VINF_SUCCESS;
1099}
1100
1101
1102/**
1103 * Checks if the VM is halted by the debugger.
1104 *
1105 * @returns True if halted.
1106 * @returns False if not halted.
1107 * @param pUVM The user mode VM handle.
1108 */
1109VMMR3DECL(bool) DBGFR3IsHalted(PUVM pUVM)
1110{
1111 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
1112 PVM pVM = pUVM->pVM;
1113 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
1114 AssertReturn(pVM->dbgf.s.fAttached, false);
1115
1116 RTPINGPONGSPEAKER enmSpeaker = pVM->dbgf.s.PingPong.enmSpeaker;
1117 return enmSpeaker == RTPINGPONGSPEAKER_PONG_SIGNALED
1118 || enmSpeaker == RTPINGPONGSPEAKER_PONG;
1119}
1120
1121
1122/**
1123 * Checks if the debugger can wait for events or not.
1124 *
1125 * This function is only used by lazy, multiplexing debuggers. :-)
1126 *
1127 * @returns VBox status code.
1128 * @retval VINF_SUCCESS if waitable.
1129 * @retval VERR_SEM_OUT_OF_TURN if not waitable.
1130 * @retval VERR_INVALID_VM_HANDLE if the VM is being (/ has been) destroyed
1131 * (not asserted) or if the handle is invalid (asserted).
1132 * @retval VERR_DBGF_NOT_ATTACHED if not attached.
1133 *
1134 * @param pUVM The user mode VM handle.
1135 */
1136VMMR3DECL(int) DBGFR3QueryWaitable(PUVM pUVM)
1137{
1138 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1139
1140 /* Note! There is a slight race here, unfortunately. */
1141 PVM pVM = pUVM->pVM;
1142 if (!RT_VALID_PTR(pVM))
1143 return VERR_INVALID_VM_HANDLE;
1144 if (pVM->enmVMState >= VMSTATE_DESTROYING)
1145 return VERR_INVALID_VM_HANDLE;
1146 if (!pVM->dbgf.s.fAttached)
1147 return VERR_DBGF_NOT_ATTACHED;
1148
1149 if (!RTSemPongShouldWait(&pVM->dbgf.s.PingPong))
1150 return VERR_SEM_OUT_OF_TURN;
1151
1152 return VINF_SUCCESS;
1153}
1154
1155
1156/**
1157 * Resumes VM execution.
1158 *
1159 * There is no receipt event on this command.
1160 *
1161 * @returns VBox status code.
1162 * @param pUVM The user mode VM handle.
1163 */
1164VMMR3DECL(int) DBGFR3Resume(PUVM pUVM)
1165{
1166 /*
1167 * Check state.
1168 */
1169 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1170 PVM pVM = pUVM->pVM;
1171 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1172 AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
1173 AssertReturn(RTSemPongIsSpeaker(&pVM->dbgf.s.PingPong), VERR_SEM_OUT_OF_TURN);
1174
1175 /*
1176 * Send the ping back to the emulation thread telling it to run.
1177 */
1178 dbgfR3SetCmd(pVM, DBGFCMD_GO);
1179 int rc = RTSemPong(&pVM->dbgf.s.PingPong);
1180 AssertRC(rc);
1181
1182 return rc;
1183}
1184
1185
1186/**
1187 * Step Into.
1188 *
1189 * A single step event is generated from this command.
1190 * The current implementation is not reliable, so don't rely on the event coming.
1191 *
1192 * @returns VBox status code.
1193 * @param pUVM The user mode VM handle.
1194 * @param idCpu The ID of the CPU to single step on.
1195 */
1196VMMR3DECL(int) DBGFR3Step(PUVM pUVM, VMCPUID idCpu)
1197{
1198 /*
1199 * Check state.
1200 */
1201 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1202 PVM pVM = pUVM->pVM;
1203 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1204 AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
1205 AssertReturn(RTSemPongIsSpeaker(&pVM->dbgf.s.PingPong), VERR_SEM_OUT_OF_TURN);
1206 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
1207
1208 /*
1209 * Send the ping back to the emulation thread telling it to run.
1210 */
1211/** @todo SMP (idCpu) */
1212 dbgfR3SetCmd(pVM, DBGFCMD_SINGLE_STEP);
1213 int rc = RTSemPong(&pVM->dbgf.s.PingPong);
1214 AssertRC(rc);
1215 return rc;
1216}
1217
1218
1219/**
1220 * @callback_method_impl{FNVMMEMTRENDEZVOUS}
1221 */
1222static DECLCALLBACK(VBOXSTRICTRC) dbgfR3EventConfigNotifyAllCpus(PVM pVM, PVMCPU pVCpu, void *pvUser)
1223{
1224 if (pvUser /*fIsHmEnabled*/)
1225 HMR3NotifyDebugEventChangedPerCpu(pVM, pVCpu);
1226 return VINF_SUCCESS;
1227}
1228
1229
1230/**
1231 * Worker for DBGFR3EventConfigEx.
1232 *
1233 * @returns VBox status code. Will not return VBOX_INTERRUPTED.
1234 * @param pUVM The user mode VM handle.
1235 * @param paConfigs The event to configure and their new state.
1236 * @param cConfigs Number of entries in @a paConfigs.
1237 */
1238static DECLCALLBACK(int) dbgfR3EventConfigEx(PUVM pUVM, DBGFEVENTCONFIG volatile const *paConfigs, size_t cConfigs)
1239{
1240 PVM pVM = pUVM->pVM;
1241 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1242
1243 /*
1244 * Apply the changes.
1245 */
1246 unsigned cChanges = 0;
1247 for (uint32_t i = 0; i < cConfigs; i++)
1248 {
1249 DBGFEVENTTYPE enmType = paConfigs[i].enmType;
1250 AssertReturn(enmType >= DBGFEVENT_FIRST_SELECTABLE && enmType < DBGFEVENT_END, VERR_INVALID_PARAMETER);
1251 if (paConfigs[i].fEnabled)
1252 cChanges += ASMAtomicBitTestAndSet(&pVM->dbgf.s.bmSelectedEvents, enmType) == false;
1253 else
1254 cChanges += ASMAtomicBitTestAndClear(&pVM->dbgf.s.bmSelectedEvents, enmType) == true;
1255 }
1256
1257 /*
1258 * Inform HM about changes. In an SMP setup, interrupt execution on the
1259 * other CPUs so their execution loop can be reselected.
1260 */
1261 int rc = VINF_SUCCESS;
1262 if (cChanges > 0)
1263 {
1264 bool const fIsHmEnabled = HMIsEnabled(pVM);
1265 if (fIsHmEnabled)
1266 HMR3NotifyDebugEventChanged(pVM);
1267 if (pVM->cCpus > 1 || fIsHmEnabled)
1268 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3EventConfigNotifyAllCpus,
1269 (void *)(uintptr_t)fIsHmEnabled);
1270 }
1271 return rc;
1272}
1273
1274
1275/**
1276 * Configures (enables/disables) multiple selectable debug events.
1277 *
1278 * @returns VBox status code.
1279 * @param pUVM The user mode VM handle.
1280 * @param paConfigs The event to configure and their new state.
1281 * @param cConfigs Number of entries in @a paConfigs.
1282 */
1283VMMR3DECL(int) DBGFR3EventConfigEx(PUVM pUVM, PCDBGFEVENTCONFIG paConfigs, size_t cConfigs)
1284{
1285 /*
1286 * Validate input.
1287 */
1288 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1289 size_t i = cConfigs;
1290 while (i-- > 0)
1291 {
1292 AssertReturn(paConfigs[i].enmType >= DBGFEVENT_FIRST_SELECTABLE, VERR_INVALID_PARAMETER);
1293 AssertReturn(paConfigs[i].enmType < DBGFEVENT_END, VERR_INVALID_PARAMETER);
1294 }
1295
1296 /*
1297 * Apply the changes in EMT(0).
1298 */
1299 return VMR3ReqPriorityCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3EventConfigEx, 3, pUVM, paConfigs, cConfigs);
1300}
1301
1302
1303/**
1304 * Enables or disables a selectable debug event.
1305 *
1306 * @returns VBox status code.
1307 * @param pUVM The user mode VM handle.
1308 * @param enmEvent The selectable debug event.
1309 * @param fEnabled The new state.
1310 */
1311VMMR3DECL(int) DBGFR3EventConfig(PUVM pUVM, DBGFEVENTTYPE enmEvent, bool fEnabled)
1312{
1313 /*
1314 * Convert to an array call.
1315 */
1316 DBGFEVENTCONFIG EvtCfg = { enmEvent, fEnabled };
1317 return DBGFR3EventConfigEx(pUVM, &EvtCfg, 1);
1318}
1319
1320
1321/**
1322 * Checks if the given selectable event is enabled.
1323 *
1324 * @returns true if enabled, false if not or invalid input.
1325 * @param pUVM The user mode VM handle.
1326 * @param enmEvent The selectable debug event.
1327 * @sa DBGFR3EventQuery
1328 */
1329VMMR3DECL(bool) DBGFR3EventIsEnabled(PUVM pUVM, DBGFEVENTTYPE enmEvent)
1330{
1331 /*
1332 * Validate input.
1333 */
1334 AssertReturn( enmEvent >= DBGFEVENT_HALT_DONE
1335 && enmEvent < DBGFEVENT_END, false);
1336 Assert( enmEvent >= DBGFEVENT_FIRST_SELECTABLE
1337 || enmEvent == DBGFEVENT_BREAKPOINT
1338 || enmEvent == DBGFEVENT_BREAKPOINT_IO
1339 || enmEvent == DBGFEVENT_BREAKPOINT_MMIO);
1340
1341 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
1342 PVM pVM = pUVM->pVM;
1343 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
1344
1345 /*
1346 * Check the event status.
1347 */
1348 return ASMBitTest(&pVM->dbgf.s.bmSelectedEvents, enmEvent);
1349}
1350
1351
1352/**
1353 * Queries the status of a set of events.
1354 *
1355 * @returns VBox status code.
1356 * @param pUVM The user mode VM handle.
1357 * @param paConfigs The events to query and where to return the state.
1358 * @param cConfigs The number of elements in @a paConfigs.
1359 * @sa DBGFR3EventIsEnabled, DBGF_IS_EVENT_ENABLED
1360 */
1361VMMR3DECL(int) DBGFR3EventQuery(PUVM pUVM, PDBGFEVENTCONFIG paConfigs, size_t cConfigs)
1362{
1363 /*
1364 * Validate input.
1365 */
1366 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
1367 PVM pVM = pUVM->pVM;
1368 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
1369
1370 for (size_t i = 0; i < cConfigs; i++)
1371 {
1372 DBGFEVENTTYPE enmType = paConfigs[i].enmType;
1373 AssertReturn( enmType >= DBGFEVENT_HALT_DONE
1374 && enmType < DBGFEVENT_END, VERR_INVALID_PARAMETER);
1375 Assert( enmType >= DBGFEVENT_FIRST_SELECTABLE
1376 || enmType == DBGFEVENT_BREAKPOINT
1377 || enmType == DBGFEVENT_BREAKPOINT_IO
1378 || enmType == DBGFEVENT_BREAKPOINT_MMIO);
1379 paConfigs[i].fEnabled = ASMBitTest(&pVM->dbgf.s.bmSelectedEvents, paConfigs[i].enmType);
1380 }
1381
1382 return VINF_SUCCESS;
1383}
1384
1385
1386/**
1387 * Worker for DBGFR3InterruptConfigEx.
1388 *
1389 * @returns VBox status code. Will not return VBOX_INTERRUPTED.
1390 * @param pUVM The user mode VM handle.
1391 * @param paConfigs The event to configure and their new state.
1392 * @param cConfigs Number of entries in @a paConfigs.
1393 */
1394static DECLCALLBACK(int) dbgfR3InterruptConfigEx(PUVM pUVM, PCDBGFINTERRUPTCONFIG paConfigs, size_t cConfigs)
1395{
1396 PVM pVM = pUVM->pVM;
1397 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1398
1399 /*
1400 * Apply the changes.
1401 */
1402 bool fChanged = false;
1403 bool fThis;
1404 for (uint32_t i = 0; i < cConfigs; i++)
1405 {
1406 /*
1407 * Hardware interrupts.
1408 */
1409 if (paConfigs[i].enmHardState == DBGFINTERRUPTSTATE_ENABLED)
1410 {
1411 fChanged |= fThis = ASMAtomicBitTestAndSet(&pVM->dbgf.s.bmHardIntBreakpoints, paConfigs[i].iInterrupt) == false;
1412 if (fThis)
1413 {
1414 Assert(pVM->dbgf.s.cHardIntBreakpoints < 256);
1415 pVM->dbgf.s.cHardIntBreakpoints++;
1416 }
1417 }
1418 else if (paConfigs[i].enmHardState == DBGFINTERRUPTSTATE_DISABLED)
1419 {
1420 fChanged |= fThis = ASMAtomicBitTestAndClear(&pVM->dbgf.s.bmHardIntBreakpoints, paConfigs[i].iInterrupt) == true;
1421 if (fThis)
1422 {
1423 Assert(pVM->dbgf.s.cHardIntBreakpoints > 0);
1424 pVM->dbgf.s.cHardIntBreakpoints--;
1425 }
1426 }
1427
1428 /*
1429 * Software interrupts.
1430 */
1431 if (paConfigs[i].enmHardState == DBGFINTERRUPTSTATE_ENABLED)
1432 {
1433 fChanged |= fThis = ASMAtomicBitTestAndSet(&pVM->dbgf.s.bmSoftIntBreakpoints, paConfigs[i].iInterrupt) == false;
1434 if (fThis)
1435 {
1436 Assert(pVM->dbgf.s.cSoftIntBreakpoints < 256);
1437 pVM->dbgf.s.cSoftIntBreakpoints++;
1438 }
1439 }
1440 else if (paConfigs[i].enmSoftState == DBGFINTERRUPTSTATE_DISABLED)
1441 {
1442 fChanged |= fThis = ASMAtomicBitTestAndClear(&pVM->dbgf.s.bmSoftIntBreakpoints, paConfigs[i].iInterrupt) == true;
1443 if (fThis)
1444 {
1445 Assert(pVM->dbgf.s.cSoftIntBreakpoints > 0);
1446 pVM->dbgf.s.cSoftIntBreakpoints--;
1447 }
1448 }
1449 }
1450
1451 /*
1452 * Update the event bitmap entries.
1453 */
1454 if (pVM->dbgf.s.cHardIntBreakpoints > 0)
1455 fChanged |= ASMAtomicBitTestAndSet(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_INTERRUPT_HARDWARE) == false;
1456 else
1457 fChanged |= ASMAtomicBitTestAndClear(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_INTERRUPT_HARDWARE) == true;
1458
1459 if (pVM->dbgf.s.cSoftIntBreakpoints > 0)
1460 fChanged |= ASMAtomicBitTestAndSet(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_INTERRUPT_SOFTWARE) == false;
1461 else
1462 fChanged |= ASMAtomicBitTestAndClear(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_INTERRUPT_SOFTWARE) == true;
1463
1464
1465 /*
1466 * Inform HM about changes. In an SMP setup, interrupt execution on the
1467 * other CPUs so their execution loop can be reselected.
1468 */
1469 int rc = VINF_SUCCESS;
1470 if (fChanged)
1471 {
1472 bool const fIsHmEnabled = HMIsEnabled(pVM);
1473 if (fIsHmEnabled)
1474 HMR3NotifyDebugEventChanged(pVM);
1475 if (pVM->cCpus > 1 || fIsHmEnabled)
1476 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3EventConfigNotifyAllCpus,
1477 (void *)(uintptr_t)fIsHmEnabled);
1478 }
1479 return rc;
1480}
1481
1482
1483/**
1484 * Changes
1485 *
1486 * @returns VBox status code.
1487 * @param pUVM The user mode VM handle.
1488 * @param paConfigs The events to query and where to return the state.
1489 * @param cConfigs The number of elements in @a paConfigs.
1490 * @sa DBGFR3InterruptConfigHardware, DBGFR3InterruptConfigSoftware
1491 */
1492VMMR3DECL(int) DBGFR3InterruptConfigEx(PUVM pUVM, PCDBGFINTERRUPTCONFIG paConfigs, size_t cConfigs)
1493{
1494 /*
1495 * Validate input.
1496 */
1497 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1498 size_t i = cConfigs;
1499 while (i-- > 0)
1500 {
1501 AssertReturn(paConfigs[i].enmHardState <= DBGFINTERRUPTSTATE_DONT_TOUCH, VERR_INVALID_PARAMETER);
1502 AssertReturn(paConfigs[i].enmSoftState <= DBGFINTERRUPTSTATE_DONT_TOUCH, VERR_INVALID_PARAMETER);
1503 }
1504
1505 /*
1506 * Apply the changes in EMT(0).
1507 */
1508 return VMR3ReqPriorityCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3InterruptConfigEx, 3, pUVM, paConfigs, cConfigs);
1509}
1510
1511
1512/**
1513 * Configures interception of a hardware interrupt.
1514 *
1515 * @returns VBox status code.
1516 * @param pUVM The user mode VM handle.
1517 * @param iInterrupt The interrupt number.
1518 * @param fEnabled Whether interception is enabled or not.
1519 * @sa DBGFR3InterruptSoftwareConfig, DBGFR3InterruptConfigEx
1520 */
1521VMMR3DECL(int) DBGFR3InterruptHardwareConfig(PUVM pUVM, uint8_t iInterrupt, bool fEnabled)
1522{
1523 /*
1524 * Convert to DBGFR3InterruptConfigEx call.
1525 */
1526 DBGFINTERRUPTCONFIG IntCfg = { iInterrupt, (uint8_t)fEnabled, DBGFINTERRUPTSTATE_DONT_TOUCH };
1527 return DBGFR3InterruptConfigEx(pUVM, &IntCfg, 1);
1528}
1529
1530
1531/**
1532 * Configures interception of a software interrupt.
1533 *
1534 * @returns VBox status code.
1535 * @param pUVM The user mode VM handle.
1536 * @param iInterrupt The interrupt number.
1537 * @param fEnabled Whether interception is enabled or not.
1538 * @sa DBGFR3InterruptHardwareConfig, DBGFR3InterruptConfigEx
1539 */
1540VMMR3DECL(int) DBGFR3InterruptSoftwareConfig(PUVM pUVM, uint8_t iInterrupt, bool fEnabled)
1541{
1542 /*
1543 * Convert to DBGFR3InterruptConfigEx call.
1544 */
1545 DBGFINTERRUPTCONFIG IntCfg = { iInterrupt, DBGFINTERRUPTSTATE_DONT_TOUCH, (uint8_t)fEnabled };
1546 return DBGFR3InterruptConfigEx(pUVM, &IntCfg, 1);
1547}
1548
1549
1550/**
1551 * Checks whether interception is enabled for a hardware interrupt.
1552 *
1553 * @returns true if enabled, false if not or invalid input.
1554 * @param pUVM The user mode VM handle.
1555 * @param iInterrupt The interrupt number.
1556 * @sa DBGFR3InterruptSoftwareIsEnabled, DBGF_IS_HARDWARE_INT_ENABLED,
1557 * DBGF_IS_SOFTWARE_INT_ENABLED
1558 */
1559VMMR3DECL(int) DBGFR3InterruptHardwareIsEnabled(PUVM pUVM, uint8_t iInterrupt)
1560{
1561 /*
1562 * Validate input.
1563 */
1564 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
1565 PVM pVM = pUVM->pVM;
1566 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
1567
1568 /*
1569 * Check it.
1570 */
1571 return ASMBitTest(&pVM->dbgf.s.bmHardIntBreakpoints, iInterrupt);
1572}
1573
1574
1575/**
1576 * Checks whether interception is enabled for a software interrupt.
1577 *
1578 * @returns true if enabled, false if not or invalid input.
1579 * @param pUVM The user mode VM handle.
1580 * @param iInterrupt The interrupt number.
1581 * @sa DBGFR3InterruptHardwareIsEnabled, DBGF_IS_SOFTWARE_INT_ENABLED,
1582 * DBGF_IS_HARDWARE_INT_ENABLED,
1583 */
1584VMMR3DECL(int) DBGFR3InterruptSoftwareIsEnabled(PUVM pUVM, uint8_t iInterrupt)
1585{
1586 /*
1587 * Validate input.
1588 */
1589 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
1590 PVM pVM = pUVM->pVM;
1591 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
1592
1593 /*
1594 * Check it.
1595 */
1596 return ASMBitTest(&pVM->dbgf.s.bmSoftIntBreakpoints, iInterrupt);
1597}
1598
1599
1600
1601/**
1602 * Call this to single step programmatically.
1603 *
1604 * You must pass down the return code to the EM loop! That's
1605 * where the actual single stepping take place (at least in the
1606 * current implementation).
1607 *
1608 * @returns VINF_EM_DBG_STEP
1609 *
1610 * @param pVCpu The cross context virtual CPU structure.
1611 *
1612 * @thread VCpu EMT
1613 * @internal
1614 */
1615VMMR3_INT_DECL(int) DBGFR3PrgStep(PVMCPU pVCpu)
1616{
1617 VMCPU_ASSERT_EMT(pVCpu);
1618
1619 pVCpu->dbgf.s.fSingleSteppingRaw = true;
1620 return VINF_EM_DBG_STEP;
1621}
1622
1623
1624/**
1625 * Inject an NMI into a running VM (only VCPU 0!)
1626 *
1627 * @returns VBox status code.
1628 * @param pUVM The user mode VM structure.
1629 * @param idCpu The ID of the CPU to inject the NMI on.
1630 */
1631VMMR3DECL(int) DBGFR3InjectNMI(PUVM pUVM, VMCPUID idCpu)
1632{
1633 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1634 PVM pVM = pUVM->pVM;
1635 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1636 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
1637
1638 /** @todo Implement generic NMI injection. */
1639 if (!HMIsEnabled(pVM))
1640 return VERR_NOT_SUP_IN_RAW_MODE;
1641
1642 VMCPU_FF_SET(&pVM->aCpus[idCpu], VMCPU_FF_INTERRUPT_NMI);
1643 return VINF_SUCCESS;
1644}
1645
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