VirtualBox

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

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

dbgf.cpp: turned annoying assertion into non-asserting check.

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