VirtualBox

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

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

DBGF: Added bsod_msr event, stubbed bsod_efi event. Since we cannot return VINF_EM_DBG_EVENT from an MSR handler, VMCPU_FF_DBGF was introduced as an alternative.

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