VirtualBox

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

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

DBGF.cpp: Need to use priority flag or we won't catch the attetion of a lone EMT in the DBGFR3PowerOff code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 52.5 KB
Line 
1/* $Id: DBGF.cpp 59207 2015-12-22 09:39:20Z 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 AssertReturn(RTSemPongIsSpeaker(&pVM->dbgf.s.PingPong), VERR_SEM_OUT_OF_TURN);
1221
1222 /*
1223 * Send the ping back to the emulation thread telling it to run.
1224 */
1225 dbgfR3SetCmd(pVM, DBGFCMD_GO);
1226 int rc = RTSemPong(&pVM->dbgf.s.PingPong);
1227 AssertRC(rc);
1228
1229 return rc;
1230}
1231
1232
1233/**
1234 * Step Into.
1235 *
1236 * A single step event is generated from this command.
1237 * The current implementation is not reliable, so don't rely on the event coming.
1238 *
1239 * @returns VBox status code.
1240 * @param pUVM The user mode VM handle.
1241 * @param idCpu The ID of the CPU to single step on.
1242 */
1243VMMR3DECL(int) DBGFR3Step(PUVM pUVM, VMCPUID idCpu)
1244{
1245 /*
1246 * Check state.
1247 */
1248 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1249 PVM pVM = pUVM->pVM;
1250 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1251 AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
1252 AssertReturn(RTSemPongIsSpeaker(&pVM->dbgf.s.PingPong), VERR_SEM_OUT_OF_TURN);
1253 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
1254
1255 /*
1256 * Send the ping back to the emulation thread telling it to run.
1257 */
1258/** @todo SMP (idCpu) */
1259 dbgfR3SetCmd(pVM, DBGFCMD_SINGLE_STEP);
1260 int rc = RTSemPong(&pVM->dbgf.s.PingPong);
1261 AssertRC(rc);
1262 return rc;
1263}
1264
1265
1266
1267/**
1268 * dbgfR3EventConfigEx argument packet.
1269 */
1270typedef struct DBGFR3EVENTCONFIGEXARGS
1271{
1272 PCDBGFEVENTCONFIG paConfigs;
1273 size_t cConfigs;
1274 int rc;
1275} DBGFR3EVENTCONFIGEXARGS;
1276/** Pointer to a dbgfR3EventConfigEx argument packet. */
1277typedef DBGFR3EVENTCONFIGEXARGS *PDBGFR3EVENTCONFIGEXARGS;
1278
1279
1280/**
1281 * @callback_method_impl{FNVMMEMTRENDEZVOUS, Worker for DBGFR3EventConfigEx.}
1282 */
1283static DECLCALLBACK(VBOXSTRICTRC) dbgfR3EventConfigEx(PVM pVM, PVMCPU pVCpu, void *pvUser)
1284{
1285 if (pVCpu->idCpu == 0)
1286 {
1287 PDBGFR3EVENTCONFIGEXARGS pArgs = (PDBGFR3EVENTCONFIGEXARGS)pvUser;
1288 DBGFEVENTCONFIG volatile const *paConfigs = pArgs->paConfigs;
1289 size_t cConfigs = pArgs->cConfigs;
1290
1291 /*
1292 * Apply the changes.
1293 */
1294 unsigned cChanges = 0;
1295 for (uint32_t i = 0; i < cConfigs; i++)
1296 {
1297 DBGFEVENTTYPE enmType = paConfigs[i].enmType;
1298 AssertReturn(enmType >= DBGFEVENT_FIRST_SELECTABLE && enmType < DBGFEVENT_END, VERR_INVALID_PARAMETER);
1299 if (paConfigs[i].fEnabled)
1300 cChanges += ASMAtomicBitTestAndSet(&pVM->dbgf.s.bmSelectedEvents, enmType) == false;
1301 else
1302 cChanges += ASMAtomicBitTestAndClear(&pVM->dbgf.s.bmSelectedEvents, enmType) == true;
1303 }
1304
1305 /*
1306 * Inform HM about changes.
1307 */
1308 if (cChanges > 0 && HMIsEnabled(pVM))
1309 {
1310 HMR3NotifyDebugEventChanged(pVM);
1311 HMR3NotifyDebugEventChangedPerCpu(pVM, pVCpu);
1312 }
1313 }
1314 else if (HMIsEnabled(pVM))
1315 HMR3NotifyDebugEventChangedPerCpu(pVM, pVCpu);
1316
1317 return VINF_SUCCESS;
1318}
1319
1320
1321/**
1322 * Configures (enables/disables) multiple selectable debug events.
1323 *
1324 * @returns VBox status code.
1325 * @param pUVM The user mode VM handle.
1326 * @param paConfigs The event to configure and their new state.
1327 * @param cConfigs Number of entries in @a paConfigs.
1328 */
1329VMMR3DECL(int) DBGFR3EventConfigEx(PUVM pUVM, PCDBGFEVENTCONFIG paConfigs, size_t cConfigs)
1330{
1331 /*
1332 * Validate input.
1333 */
1334 size_t i = cConfigs;
1335 while (i-- > 0)
1336 {
1337 AssertReturn(paConfigs[i].enmType >= DBGFEVENT_FIRST_SELECTABLE, VERR_INVALID_PARAMETER);
1338 AssertReturn(paConfigs[i].enmType < DBGFEVENT_END, VERR_INVALID_PARAMETER);
1339 }
1340 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1341 PVM pVM = pUVM->pVM;
1342 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1343
1344 /*
1345 * Apply the changes in EMT(0) and rendezvous with the other CPUs so they
1346 * can sync their data and execution with new debug state.
1347 */
1348 DBGFR3EVENTCONFIGEXARGS Args = { paConfigs, cConfigs, VINF_SUCCESS };
1349 int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING | VMMEMTRENDEZVOUS_FLAGS_PRIORITY,
1350 dbgfR3EventConfigEx, &Args);
1351 if (RT_SUCCESS(rc))
1352 rc = Args.rc;
1353 return rc;
1354}
1355
1356
1357/**
1358 * Enables or disables a selectable debug event.
1359 *
1360 * @returns VBox status code.
1361 * @param pUVM The user mode VM handle.
1362 * @param enmEvent The selectable debug event.
1363 * @param fEnabled The new state.
1364 */
1365VMMR3DECL(int) DBGFR3EventConfig(PUVM pUVM, DBGFEVENTTYPE enmEvent, bool fEnabled)
1366{
1367 /*
1368 * Convert to an array call.
1369 */
1370 DBGFEVENTCONFIG EvtCfg = { enmEvent, fEnabled };
1371 return DBGFR3EventConfigEx(pUVM, &EvtCfg, 1);
1372}
1373
1374
1375/**
1376 * Checks if the given selectable event is enabled.
1377 *
1378 * @returns true if enabled, false if not or invalid input.
1379 * @param pUVM The user mode VM handle.
1380 * @param enmEvent The selectable debug event.
1381 * @sa DBGFR3EventQuery
1382 */
1383VMMR3DECL(bool) DBGFR3EventIsEnabled(PUVM pUVM, DBGFEVENTTYPE enmEvent)
1384{
1385 /*
1386 * Validate input.
1387 */
1388 AssertReturn( enmEvent >= DBGFEVENT_HALT_DONE
1389 && enmEvent < DBGFEVENT_END, false);
1390 Assert( enmEvent >= DBGFEVENT_FIRST_SELECTABLE
1391 || enmEvent == DBGFEVENT_BREAKPOINT
1392 || enmEvent == DBGFEVENT_BREAKPOINT_IO
1393 || enmEvent == DBGFEVENT_BREAKPOINT_MMIO);
1394
1395 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
1396 PVM pVM = pUVM->pVM;
1397 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
1398
1399 /*
1400 * Check the event status.
1401 */
1402 return ASMBitTest(&pVM->dbgf.s.bmSelectedEvents, enmEvent);
1403}
1404
1405
1406/**
1407 * Queries the status of a set of events.
1408 *
1409 * @returns VBox status code.
1410 * @param pUVM The user mode VM handle.
1411 * @param paConfigs The events to query and where to return the state.
1412 * @param cConfigs The number of elements in @a paConfigs.
1413 * @sa DBGFR3EventIsEnabled, DBGF_IS_EVENT_ENABLED
1414 */
1415VMMR3DECL(int) DBGFR3EventQuery(PUVM pUVM, PDBGFEVENTCONFIG paConfigs, size_t cConfigs)
1416{
1417 /*
1418 * Validate input.
1419 */
1420 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1421 PVM pVM = pUVM->pVM;
1422 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1423
1424 for (size_t i = 0; i < cConfigs; i++)
1425 {
1426 DBGFEVENTTYPE enmType = paConfigs[i].enmType;
1427 AssertReturn( enmType >= DBGFEVENT_HALT_DONE
1428 && enmType < DBGFEVENT_END, VERR_INVALID_PARAMETER);
1429 Assert( enmType >= DBGFEVENT_FIRST_SELECTABLE
1430 || enmType == DBGFEVENT_BREAKPOINT
1431 || enmType == DBGFEVENT_BREAKPOINT_IO
1432 || enmType == DBGFEVENT_BREAKPOINT_MMIO);
1433 paConfigs[i].fEnabled = ASMBitTest(&pVM->dbgf.s.bmSelectedEvents, paConfigs[i].enmType);
1434 }
1435
1436 return VINF_SUCCESS;
1437}
1438
1439
1440/**
1441 * dbgfR3InterruptConfigEx argument packet.
1442 */
1443typedef struct DBGFR3INTERRUPTCONFIGEXARGS
1444{
1445 PCDBGFINTERRUPTCONFIG paConfigs;
1446 size_t cConfigs;
1447 int rc;
1448} DBGFR3INTERRUPTCONFIGEXARGS;
1449/** Pointer to a dbgfR3InterruptConfigEx argument packet. */
1450typedef DBGFR3INTERRUPTCONFIGEXARGS *PDBGFR3INTERRUPTCONFIGEXARGS;
1451
1452/**
1453 * @callback_method_impl{FNVMMEMTRENDEZVOUS,
1454 * Worker for DBGFR3InterruptConfigEx.}
1455 */
1456static DECLCALLBACK(VBOXSTRICTRC) dbgfR3InterruptConfigEx(PVM pVM, PVMCPU pVCpu, void *pvUser)
1457{
1458 if (pVCpu->idCpu == 0)
1459 {
1460 PDBGFR3INTERRUPTCONFIGEXARGS pArgs = (PDBGFR3INTERRUPTCONFIGEXARGS)pvUser;
1461 PCDBGFINTERRUPTCONFIG paConfigs = pArgs->paConfigs;
1462 size_t cConfigs = pArgs->cConfigs;
1463
1464 /*
1465 * Apply the changes.
1466 */
1467 bool fChanged = false;
1468 bool fThis;
1469 for (uint32_t i = 0; i < cConfigs; i++)
1470 {
1471 /*
1472 * Hardware interrupts.
1473 */
1474 if (paConfigs[i].enmHardState == DBGFINTERRUPTSTATE_ENABLED)
1475 {
1476 fChanged |= fThis = ASMAtomicBitTestAndSet(&pVM->dbgf.s.bmHardIntBreakpoints, paConfigs[i].iInterrupt) == false;
1477 if (fThis)
1478 {
1479 Assert(pVM->dbgf.s.cHardIntBreakpoints < 256);
1480 pVM->dbgf.s.cHardIntBreakpoints++;
1481 }
1482 }
1483 else if (paConfigs[i].enmHardState == DBGFINTERRUPTSTATE_DISABLED)
1484 {
1485 fChanged |= fThis = ASMAtomicBitTestAndClear(&pVM->dbgf.s.bmHardIntBreakpoints, paConfigs[i].iInterrupt) == true;
1486 if (fThis)
1487 {
1488 Assert(pVM->dbgf.s.cHardIntBreakpoints > 0);
1489 pVM->dbgf.s.cHardIntBreakpoints--;
1490 }
1491 }
1492
1493 /*
1494 * Software interrupts.
1495 */
1496 if (paConfigs[i].enmHardState == DBGFINTERRUPTSTATE_ENABLED)
1497 {
1498 fChanged |= fThis = ASMAtomicBitTestAndSet(&pVM->dbgf.s.bmSoftIntBreakpoints, paConfigs[i].iInterrupt) == false;
1499 if (fThis)
1500 {
1501 Assert(pVM->dbgf.s.cSoftIntBreakpoints < 256);
1502 pVM->dbgf.s.cSoftIntBreakpoints++;
1503 }
1504 }
1505 else if (paConfigs[i].enmSoftState == DBGFINTERRUPTSTATE_DISABLED)
1506 {
1507 fChanged |= fThis = ASMAtomicBitTestAndClear(&pVM->dbgf.s.bmSoftIntBreakpoints, paConfigs[i].iInterrupt) == true;
1508 if (fThis)
1509 {
1510 Assert(pVM->dbgf.s.cSoftIntBreakpoints > 0);
1511 pVM->dbgf.s.cSoftIntBreakpoints--;
1512 }
1513 }
1514 }
1515
1516 /*
1517 * Update the event bitmap entries.
1518 */
1519 if (pVM->dbgf.s.cHardIntBreakpoints > 0)
1520 fChanged |= ASMAtomicBitTestAndSet(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_INTERRUPT_HARDWARE) == false;
1521 else
1522 fChanged |= ASMAtomicBitTestAndClear(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_INTERRUPT_HARDWARE) == true;
1523
1524 if (pVM->dbgf.s.cSoftIntBreakpoints > 0)
1525 fChanged |= ASMAtomicBitTestAndSet(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_INTERRUPT_SOFTWARE) == false;
1526 else
1527 fChanged |= ASMAtomicBitTestAndClear(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_INTERRUPT_SOFTWARE) == true;
1528
1529 /*
1530 * Inform HM about changes.
1531 */
1532 if (fChanged && HMIsEnabled(pVM))
1533 {
1534 HMR3NotifyDebugEventChanged(pVM);
1535 HMR3NotifyDebugEventChangedPerCpu(pVM, pVCpu);
1536 }
1537 }
1538 else if (HMIsEnabled(pVM))
1539 HMR3NotifyDebugEventChangedPerCpu(pVM, pVCpu);
1540
1541 return VINF_SUCCESS;
1542}
1543
1544
1545/**
1546 * Changes
1547 *
1548 * @returns VBox status code.
1549 * @param pUVM The user mode VM handle.
1550 * @param paConfigs The events to query and where to return the state.
1551 * @param cConfigs The number of elements in @a paConfigs.
1552 * @sa DBGFR3InterruptConfigHardware, DBGFR3InterruptConfigSoftware
1553 */
1554VMMR3DECL(int) DBGFR3InterruptConfigEx(PUVM pUVM, PCDBGFINTERRUPTCONFIG paConfigs, size_t cConfigs)
1555{
1556 /*
1557 * Validate input.
1558 */
1559 size_t i = cConfigs;
1560 while (i-- > 0)
1561 {
1562 AssertReturn(paConfigs[i].enmHardState <= DBGFINTERRUPTSTATE_DONT_TOUCH, VERR_INVALID_PARAMETER);
1563 AssertReturn(paConfigs[i].enmSoftState <= DBGFINTERRUPTSTATE_DONT_TOUCH, VERR_INVALID_PARAMETER);
1564 }
1565
1566 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1567 PVM pVM = pUVM->pVM;
1568 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1569
1570 /*
1571 * Apply the changes in EMT(0) and rendezvous with the other CPUs so they
1572 * can sync their data and execution with new debug state.
1573 */
1574 DBGFR3INTERRUPTCONFIGEXARGS Args = { paConfigs, cConfigs, VINF_SUCCESS };
1575 int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING | VMMEMTRENDEZVOUS_FLAGS_PRIORITY,
1576 dbgfR3InterruptConfigEx, &Args);
1577 if (RT_SUCCESS(rc))
1578 rc = Args.rc;
1579 return rc;
1580}
1581
1582
1583/**
1584 * Configures interception of a hardware interrupt.
1585 *
1586 * @returns VBox status code.
1587 * @param pUVM The user mode VM handle.
1588 * @param iInterrupt The interrupt number.
1589 * @param fEnabled Whether interception is enabled or not.
1590 * @sa DBGFR3InterruptSoftwareConfig, DBGFR3InterruptConfigEx
1591 */
1592VMMR3DECL(int) DBGFR3InterruptHardwareConfig(PUVM pUVM, uint8_t iInterrupt, bool fEnabled)
1593{
1594 /*
1595 * Convert to DBGFR3InterruptConfigEx call.
1596 */
1597 DBGFINTERRUPTCONFIG IntCfg = { iInterrupt, (uint8_t)fEnabled, DBGFINTERRUPTSTATE_DONT_TOUCH };
1598 return DBGFR3InterruptConfigEx(pUVM, &IntCfg, 1);
1599}
1600
1601
1602/**
1603 * Configures interception of a software interrupt.
1604 *
1605 * @returns VBox status code.
1606 * @param pUVM The user mode VM handle.
1607 * @param iInterrupt The interrupt number.
1608 * @param fEnabled Whether interception is enabled or not.
1609 * @sa DBGFR3InterruptHardwareConfig, DBGFR3InterruptConfigEx
1610 */
1611VMMR3DECL(int) DBGFR3InterruptSoftwareConfig(PUVM pUVM, uint8_t iInterrupt, bool fEnabled)
1612{
1613 /*
1614 * Convert to DBGFR3InterruptConfigEx call.
1615 */
1616 DBGFINTERRUPTCONFIG IntCfg = { iInterrupt, DBGFINTERRUPTSTATE_DONT_TOUCH, (uint8_t)fEnabled };
1617 return DBGFR3InterruptConfigEx(pUVM, &IntCfg, 1);
1618}
1619
1620
1621/**
1622 * Checks whether interception is enabled for a hardware interrupt.
1623 *
1624 * @returns true if enabled, false if not or invalid input.
1625 * @param pUVM The user mode VM handle.
1626 * @param iInterrupt The interrupt number.
1627 * @sa DBGFR3InterruptSoftwareIsEnabled, DBGF_IS_HARDWARE_INT_ENABLED,
1628 * DBGF_IS_SOFTWARE_INT_ENABLED
1629 */
1630VMMR3DECL(int) DBGFR3InterruptHardwareIsEnabled(PUVM pUVM, uint8_t iInterrupt)
1631{
1632 /*
1633 * Validate input.
1634 */
1635 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
1636 PVM pVM = pUVM->pVM;
1637 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
1638
1639 /*
1640 * Check it.
1641 */
1642 return ASMBitTest(&pVM->dbgf.s.bmHardIntBreakpoints, iInterrupt);
1643}
1644
1645
1646/**
1647 * Checks whether interception is enabled for a software interrupt.
1648 *
1649 * @returns true if enabled, false if not or invalid input.
1650 * @param pUVM The user mode VM handle.
1651 * @param iInterrupt The interrupt number.
1652 * @sa DBGFR3InterruptHardwareIsEnabled, DBGF_IS_SOFTWARE_INT_ENABLED,
1653 * DBGF_IS_HARDWARE_INT_ENABLED,
1654 */
1655VMMR3DECL(int) DBGFR3InterruptSoftwareIsEnabled(PUVM pUVM, uint8_t iInterrupt)
1656{
1657 /*
1658 * Validate input.
1659 */
1660 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
1661 PVM pVM = pUVM->pVM;
1662 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
1663
1664 /*
1665 * Check it.
1666 */
1667 return ASMBitTest(&pVM->dbgf.s.bmSoftIntBreakpoints, iInterrupt);
1668}
1669
1670
1671
1672/**
1673 * Call this to single step programmatically.
1674 *
1675 * You must pass down the return code to the EM loop! That's
1676 * where the actual single stepping take place (at least in the
1677 * current implementation).
1678 *
1679 * @returns VINF_EM_DBG_STEP
1680 *
1681 * @param pVCpu The cross context virtual CPU structure.
1682 *
1683 * @thread VCpu EMT
1684 * @internal
1685 */
1686VMMR3_INT_DECL(int) DBGFR3PrgStep(PVMCPU pVCpu)
1687{
1688 VMCPU_ASSERT_EMT(pVCpu);
1689
1690 pVCpu->dbgf.s.fSingleSteppingRaw = true;
1691 return VINF_EM_DBG_STEP;
1692}
1693
1694
1695/**
1696 * Inject an NMI into a running VM (only VCPU 0!)
1697 *
1698 * @returns VBox status code.
1699 * @param pUVM The user mode VM structure.
1700 * @param idCpu The ID of the CPU to inject the NMI on.
1701 */
1702VMMR3DECL(int) DBGFR3InjectNMI(PUVM pUVM, VMCPUID idCpu)
1703{
1704 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1705 PVM pVM = pUVM->pVM;
1706 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1707 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
1708
1709 /** @todo Implement generic NMI injection. */
1710 if (!HMIsEnabled(pVM))
1711 return VERR_NOT_SUP_IN_RAW_MODE;
1712
1713 VMCPU_FF_SET(&pVM->aCpus[idCpu], VMCPU_FF_INTERRUPT_NMI);
1714 return VINF_SUCCESS;
1715}
1716
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