VirtualBox

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

Last change on this file since 44399 was 44399, checked in by vboxsync, 12 years ago

DBGF,DBGC,++: PVM -> PUVM. Some refactoring and cleanup as well.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 33.6 KB
Line 
1/* $Id: DBGF.cpp 44399 2013-01-27 21:12:53Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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 Pointer to the VM.
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 Pointer to the VM.
136 */
137VMMR3_INT_DECL(int) DBGFR3Init(PVM pVM)
138{
139 PUVM pUVM = pVM->pUVM;
140 int rc = dbgfR3InfoInit(pUVM);
141 if (RT_SUCCESS(rc))
142 rc = dbgfR3TraceInit(pVM);
143 if (RT_SUCCESS(rc))
144 rc = dbgfR3RegInit(pUVM);
145 if (RT_SUCCESS(rc))
146 rc = dbgfR3AsInit(pUVM);
147 if (RT_SUCCESS(rc))
148 rc = dbgfR3SymInit(pVM);
149 if (RT_SUCCESS(rc))
150 rc = dbgfR3BpInit(pVM);
151 return rc;
152}
153
154
155/**
156 * Terminates and cleans up resources allocated by the DBGF.
157 *
158 * @returns VBox status code.
159 * @param pVM Pointer to the VM.
160 */
161VMMR3_INT_DECL(int) DBGFR3Term(PVM pVM)
162{
163 PUVM pUVM = pVM->pUVM;
164 int rc;
165
166 /*
167 * Send a termination event to any attached debugger.
168 */
169 /* wait to become the speaker (we should already be that). */
170 if ( pVM->dbgf.s.fAttached
171 && RTSemPingShouldWait(&pVM->dbgf.s.PingPong))
172 RTSemPingWait(&pVM->dbgf.s.PingPong, 5000);
173
174 /* now, send the event if we're the speaker. */
175 if ( pVM->dbgf.s.fAttached
176 && RTSemPingIsSpeaker(&pVM->dbgf.s.PingPong))
177 {
178 DBGFCMD enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND);
179 if (enmCmd == DBGFCMD_DETACH_DEBUGGER)
180 /* the debugger beat us to initiating the detaching. */
181 rc = VINF_SUCCESS;
182 else
183 {
184 /* ignore the command (if any). */
185 enmCmd = DBGFCMD_NO_COMMAND;
186 pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_TERMINATING;
187 pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_OTHER;
188 rc = RTSemPing(&pVM->dbgf.s.PingPong);
189 }
190
191 /*
192 * Process commands until we get a detached command.
193 */
194 while (RT_SUCCESS(rc) && enmCmd != DBGFCMD_DETACHED_DEBUGGER)
195 {
196 if (enmCmd != DBGFCMD_NO_COMMAND)
197 {
198 /* process command */
199 bool fResumeExecution;
200 DBGFCMDDATA CmdData = pVM->dbgf.s.VMMCmdData;
201 rc = dbgfR3VMMCmd(pVM, enmCmd, &CmdData, &fResumeExecution);
202 enmCmd = DBGFCMD_NO_COMMAND;
203 }
204 else
205 {
206 /* wait for new command. */
207 rc = RTSemPingWait(&pVM->dbgf.s.PingPong, RT_INDEFINITE_WAIT);
208 if (RT_SUCCESS(rc))
209 enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND);
210 }
211 }
212 }
213
214 /*
215 * Terminate the other bits.
216 */
217 dbgfR3OSTerm(pUVM);
218 dbgfR3AsTerm(pUVM);
219 dbgfR3RegTerm(pUVM);
220 dbgfR3TraceTerm(pVM);
221 dbgfR3InfoTerm(pUVM);
222 return VINF_SUCCESS;
223}
224
225
226/**
227 * Applies relocations to data and code managed by this
228 * component. This function will be called at init and
229 * whenever the VMM need to relocate it self inside the GC.
230 *
231 * @param pVM Pointer to the VM.
232 * @param offDelta Relocation delta relative to old location.
233 */
234VMMR3_INT_DECL(void) DBGFR3Relocate(PVM pVM, RTGCINTPTR offDelta)
235{
236 dbgfR3TraceRelocate(pVM);
237 dbgfR3AsRelocate(pVM->pUVM, offDelta);
238}
239
240
241/**
242 * Waits a little while for a debuggger to attach.
243 *
244 * @returns True is a debugger have attached.
245 * @param pVM Pointer to the VM.
246 * @param enmEvent Event.
247 */
248bool dbgfR3WaitForAttach(PVM pVM, DBGFEVENTTYPE enmEvent)
249{
250 /*
251 * First a message.
252 */
253#ifndef RT_OS_L4
254
255# if !defined(DEBUG) || defined(DEBUG_sandervl) || defined(DEBUG_frank) || defined(IEM_VERIFICATION_MODE)
256 int cWait = 10;
257# else
258 int cWait = HMIsEnabled(pVM)
259 && ( enmEvent == DBGFEVENT_ASSERTION_HYPER
260 || enmEvent == DBGFEVENT_FATAL_ERROR)
261 && !RTEnvExist("VBOX_DBGF_WAIT_FOR_ATTACH")
262 ? 10
263 : 150;
264# endif
265 RTStrmPrintf(g_pStdErr, "DBGF: No debugger attached, waiting %d second%s for one to attach (event=%d)\n",
266 cWait / 10, cWait != 10 ? "s" : "", enmEvent);
267 RTStrmFlush(g_pStdErr);
268 while (cWait > 0)
269 {
270 RTThreadSleep(100);
271 if (pVM->dbgf.s.fAttached)
272 {
273 RTStrmPrintf(g_pStdErr, "Attached!\n");
274 RTStrmFlush(g_pStdErr);
275 return true;
276 }
277
278 /* next */
279 if (!(cWait % 10))
280 {
281 RTStrmPrintf(g_pStdErr, "%d.", cWait / 10);
282 RTStrmFlush(g_pStdErr);
283 }
284 cWait--;
285 }
286#endif
287
288 RTStrmPrintf(g_pStdErr, "Stopping the VM!\n");
289 RTStrmFlush(g_pStdErr);
290 return false;
291}
292
293
294/**
295 * Forced action callback.
296 * The VMM will call this from it's main loop when VM_FF_DBGF is set.
297 *
298 * The function checks and executes pending commands from the debugger.
299 *
300 * @returns VINF_SUCCESS normally.
301 * @returns VERR_DBGF_RAISE_FATAL_ERROR to pretend a fatal error happened.
302 * @param pVM Pointer to the VM.
303 */
304VMMR3_INT_DECL(int) DBGFR3VMMForcedAction(PVM pVM)
305{
306 int rc = VINF_SUCCESS;
307
308 if (VM_FF_TESTANDCLEAR(pVM, VM_FF_DBGF))
309 {
310 PVMCPU pVCpu = VMMGetCpu(pVM);
311
312 /*
313 * Commands?
314 */
315 if (pVM->dbgf.s.enmVMMCmd != DBGFCMD_NO_COMMAND)
316 {
317 /** @todo stupid GDT/LDT sync hack. go away! */
318 SELMR3UpdateFromCPUM(pVM, pVCpu);
319
320 /*
321 * Process the command.
322 */
323 bool fResumeExecution;
324 DBGFCMDDATA CmdData = pVM->dbgf.s.VMMCmdData;
325 DBGFCMD enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND);
326 rc = dbgfR3VMMCmd(pVM, enmCmd, &CmdData, &fResumeExecution);
327 if (!fResumeExecution)
328 rc = dbgfR3VMMWait(pVM);
329 }
330 }
331 return rc;
332}
333
334
335/**
336 * Flag whether the event implies that we're stopped in the hypervisor code
337 * and have to block certain operations.
338 *
339 * @param pVM Pointer to the VM.
340 * @param enmEvent The event.
341 */
342static void dbgfR3EventSetStoppedInHyperFlag(PVM pVM, DBGFEVENTTYPE enmEvent)
343{
344 switch (enmEvent)
345 {
346 case DBGFEVENT_STEPPED_HYPER:
347 case DBGFEVENT_ASSERTION_HYPER:
348 case DBGFEVENT_BREAKPOINT_HYPER:
349 pVM->dbgf.s.fStoppedInHyper = true;
350 break;
351 default:
352 pVM->dbgf.s.fStoppedInHyper = false;
353 break;
354 }
355}
356
357
358/**
359 * Try to determine the event context.
360 *
361 * @returns debug event context.
362 * @param pVM Pointer to the VM.
363 */
364static DBGFEVENTCTX dbgfR3FigureEventCtx(PVM pVM)
365{
366 /** @todo SMP support! */
367 PVMCPU pVCpu = &pVM->aCpus[0];
368
369 switch (EMGetState(pVCpu))
370 {
371 case EMSTATE_RAW:
372 case EMSTATE_DEBUG_GUEST_RAW:
373 return DBGFEVENTCTX_RAW;
374
375 case EMSTATE_REM:
376 case EMSTATE_DEBUG_GUEST_REM:
377 return DBGFEVENTCTX_REM;
378
379 case EMSTATE_DEBUG_HYPER:
380 case EMSTATE_GURU_MEDITATION:
381 return DBGFEVENTCTX_HYPER;
382
383 default:
384 return DBGFEVENTCTX_OTHER;
385 }
386}
387
388/**
389 * The common event prologue code.
390 * It will set the 'stopped-in-hyper' flag, make sure someone is attached,
391 * and perhaps process any high priority pending actions (none yet).
392 *
393 * @returns VBox status.
394 * @param pVM Pointer to the VM.
395 * @param enmEvent The event to be sent.
396 */
397static int dbgfR3EventPrologue(PVM pVM, DBGFEVENTTYPE enmEvent)
398{
399 /** @todo SMP */
400 PVMCPU pVCpu = VMMGetCpu(pVM);
401
402 /*
403 * Check if a debugger is attached.
404 */
405 if ( !pVM->dbgf.s.fAttached
406 && !dbgfR3WaitForAttach(pVM, enmEvent))
407 {
408 Log(("DBGFR3VMMEventSrc: enmEvent=%d - debugger not attached\n", enmEvent));
409 return VERR_DBGF_NOT_ATTACHED;
410 }
411
412 /*
413 * Sync back the state from the REM.
414 */
415 dbgfR3EventSetStoppedInHyperFlag(pVM, enmEvent);
416#ifdef VBOX_WITH_REM
417 if (!pVM->dbgf.s.fStoppedInHyper)
418 REMR3StateUpdate(pVM, pVCpu);
419#endif
420
421 /*
422 * Look thru pending commands and finish those which make sense now.
423 */
424 /** @todo Process/purge pending commands. */
425 //int rc = DBGFR3VMMForcedAction(pVM);
426 return VINF_SUCCESS;
427}
428
429
430/**
431 * Sends the event in the event buffer.
432 *
433 * @returns VBox status code.
434 * @param pVM Pointer to the VM.
435 */
436static int dbgfR3SendEvent(PVM pVM)
437{
438 int rc = RTSemPing(&pVM->dbgf.s.PingPong);
439 if (RT_SUCCESS(rc))
440 rc = dbgfR3VMMWait(pVM);
441
442 pVM->dbgf.s.fStoppedInHyper = false;
443 /** @todo sync VMM -> REM after exitting the debugger. everything may change while in the debugger! */
444 return rc;
445}
446
447
448/**
449 * Send a generic debugger event which takes no data.
450 *
451 * @returns VBox status.
452 * @param pVM Pointer to the VM.
453 * @param enmEvent The event to send.
454 * @internal
455 */
456VMMR3DECL(int) DBGFR3Event(PVM pVM, DBGFEVENTTYPE enmEvent)
457{
458 int rc = dbgfR3EventPrologue(pVM, enmEvent);
459 if (RT_FAILURE(rc))
460 return rc;
461
462 /*
463 * Send the event and process the reply communication.
464 */
465 pVM->dbgf.s.DbgEvent.enmType = enmEvent;
466 pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM);
467 return dbgfR3SendEvent(pVM);
468}
469
470
471/**
472 * Send a debugger event which takes the full source file location.
473 *
474 * @returns VBox status.
475 * @param pVM Pointer to the VM.
476 * @param enmEvent The event to send.
477 * @param pszFile Source file.
478 * @param uLine Line number in source file.
479 * @param pszFunction Function name.
480 * @param pszFormat Message which accompanies the event.
481 * @param ... Message arguments.
482 * @internal
483 */
484VMMR3DECL(int) DBGFR3EventSrc(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, const char *pszFunction, const char *pszFormat, ...)
485{
486 va_list args;
487 va_start(args, pszFormat);
488 int rc = DBGFR3EventSrcV(pVM, enmEvent, pszFile, uLine, pszFunction, pszFormat, args);
489 va_end(args);
490 return rc;
491}
492
493
494/**
495 * Send a debugger event which takes the full source file location.
496 *
497 * @returns VBox status.
498 * @param pVM Pointer to the VM.
499 * @param enmEvent The event to send.
500 * @param pszFile Source file.
501 * @param uLine Line number in source file.
502 * @param pszFunction Function name.
503 * @param pszFormat Message which accompanies the event.
504 * @param args Message arguments.
505 * @internal
506 */
507VMMR3DECL(int) DBGFR3EventSrcV(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, const char *pszFunction, const char *pszFormat, va_list args)
508{
509 int rc = dbgfR3EventPrologue(pVM, enmEvent);
510 if (RT_FAILURE(rc))
511 return rc;
512
513 /*
514 * Format the message.
515 */
516 char *pszMessage = NULL;
517 char szMessage[8192];
518 if (pszFormat && *pszFormat)
519 {
520 pszMessage = &szMessage[0];
521 RTStrPrintfV(szMessage, sizeof(szMessage), pszFormat, args);
522 }
523
524 /*
525 * Send the event and process the reply communication.
526 */
527 pVM->dbgf.s.DbgEvent.enmType = enmEvent;
528 pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM);
529 pVM->dbgf.s.DbgEvent.u.Src.pszFile = pszFile;
530 pVM->dbgf.s.DbgEvent.u.Src.uLine = uLine;
531 pVM->dbgf.s.DbgEvent.u.Src.pszFunction = pszFunction;
532 pVM->dbgf.s.DbgEvent.u.Src.pszMessage = pszMessage;
533 return dbgfR3SendEvent(pVM);
534}
535
536
537/**
538 * Send a debugger event which takes the two assertion messages.
539 *
540 * @returns VBox status.
541 * @param pVM Pointer to the VM.
542 * @param enmEvent The event to send.
543 * @param pszMsg1 First assertion message.
544 * @param pszMsg2 Second assertion message.
545 */
546VMMR3_INT_DECL(int) DBGFR3EventAssertion(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszMsg1, const char *pszMsg2)
547{
548 int rc = dbgfR3EventPrologue(pVM, enmEvent);
549 if (RT_FAILURE(rc))
550 return rc;
551
552 /*
553 * Send the event and process the reply communication.
554 */
555 pVM->dbgf.s.DbgEvent.enmType = enmEvent;
556 pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM);
557 pVM->dbgf.s.DbgEvent.u.Assert.pszMsg1 = pszMsg1;
558 pVM->dbgf.s.DbgEvent.u.Assert.pszMsg2 = pszMsg2;
559 return dbgfR3SendEvent(pVM);
560}
561
562
563/**
564 * Breakpoint was hit somewhere.
565 * Figure out which breakpoint it is and notify the debugger.
566 *
567 * @returns VBox status.
568 * @param pVM Pointer to the VM.
569 * @param enmEvent DBGFEVENT_BREAKPOINT_HYPER or DBGFEVENT_BREAKPOINT.
570 */
571VMMR3_INT_DECL(int) DBGFR3EventBreakpoint(PVM pVM, DBGFEVENTTYPE enmEvent)
572{
573 int rc = dbgfR3EventPrologue(pVM, enmEvent);
574 if (RT_FAILURE(rc))
575 return rc;
576
577 /*
578 * Send the event and process the reply communication.
579 */
580 /** @todo SMP */
581 PVMCPU pVCpu = VMMGetCpu0(pVM);
582
583 pVM->dbgf.s.DbgEvent.enmType = enmEvent;
584 RTUINT iBp = pVM->dbgf.s.DbgEvent.u.Bp.iBp = pVCpu->dbgf.s.iActiveBp;
585 pVCpu->dbgf.s.iActiveBp = ~0U;
586 if (iBp != ~0U)
587 pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_RAW;
588 else
589 {
590 /* REM breakpoints has be been searched for. */
591#if 0 /** @todo get flat PC api! */
592 uint32_t eip = CPUMGetGuestEIP(pVM);
593#else
594 /* @todo SMP support!! */
595 PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(VMMGetCpu(pVM));
596 RTGCPTR eip = pCtx->rip + pCtx->cs.u64Base;
597#endif
598 for (size_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++)
599 if ( pVM->dbgf.s.aBreakpoints[i].enmType == DBGFBPTYPE_REM
600 && pVM->dbgf.s.aBreakpoints[i].GCPtr == eip)
601 {
602 pVM->dbgf.s.DbgEvent.u.Bp.iBp = pVM->dbgf.s.aBreakpoints[i].iBp;
603 break;
604 }
605 AssertMsg(pVM->dbgf.s.DbgEvent.u.Bp.iBp != ~0U, ("eip=%08x\n", eip));
606 pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_REM;
607 }
608 return dbgfR3SendEvent(pVM);
609}
610
611
612/**
613 * Waits for the debugger to respond.
614 *
615 * @returns VBox status. (clearify)
616 * @param pVM Pointer to the VM.
617 */
618static int dbgfR3VMMWait(PVM pVM)
619{
620 PVMCPU pVCpu = VMMGetCpu(pVM);
621
622 LogFlow(("dbgfR3VMMWait:\n"));
623
624 /** @todo stupid GDT/LDT sync hack. go away! */
625 SELMR3UpdateFromCPUM(pVM, pVCpu);
626 int rcRet = VINF_SUCCESS;
627
628 /*
629 * Waits for the debugger to reply (i.e. issue an command).
630 */
631 for (;;)
632 {
633 /*
634 * Wait.
635 */
636 uint32_t cPollHack = 1; /** @todo this interface is horrible now that we're using lots of VMR3ReqCall stuff all over DBGF. */
637 for (;;)
638 {
639 int rc;
640 if ( !VM_FF_ISPENDING(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_REQUEST)
641 && !VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_REQUEST))
642 {
643 rc = RTSemPingWait(&pVM->dbgf.s.PingPong, cPollHack);
644 if (RT_SUCCESS(rc))
645 break;
646 if (rc != VERR_TIMEOUT)
647 {
648 LogFlow(("dbgfR3VMMWait: returns %Rrc\n", rc));
649 return rc;
650 }
651 }
652
653 if (VM_FF_ISPENDING(pVM, VM_FF_EMT_RENDEZVOUS))
654 {
655 rc = VMMR3EmtRendezvousFF(pVM, pVCpu);
656 cPollHack = 1;
657 }
658 else if ( VM_FF_ISPENDING(pVM, VM_FF_REQUEST)
659 || VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_REQUEST))
660 {
661 LogFlow(("dbgfR3VMMWait: Processes requests...\n"));
662 rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY, false /*fPriorityOnly*/);
663 if (rc == VINF_SUCCESS)
664 rc = VMR3ReqProcessU(pVM->pUVM, pVCpu->idCpu, false /*fPriorityOnly*/);
665 LogFlow(("dbgfR3VMMWait: VMR3ReqProcess -> %Rrc rcRet=%Rrc\n", rc, rcRet));
666 cPollHack = 1;
667 }
668 else
669 {
670 rc = VINF_SUCCESS;
671 if (cPollHack < 120)
672 cPollHack++;
673 }
674
675 if (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST)
676 {
677 switch (rc)
678 {
679 case VINF_EM_DBG_BREAKPOINT:
680 case VINF_EM_DBG_STEPPED:
681 case VINF_EM_DBG_STEP:
682 case VINF_EM_DBG_STOP:
683 AssertMsgFailed(("rc=%Rrc\n", rc));
684 break;
685
686 /* return straight away */
687 case VINF_EM_TERMINATE:
688 case VINF_EM_OFF:
689 LogFlow(("dbgfR3VMMWait: returns %Rrc\n", rc));
690 return rc;
691
692 /* remember return code. */
693 default:
694 AssertReleaseMsgFailed(("rc=%Rrc is not in the switch!\n", rc));
695 case VINF_EM_RESET:
696 case VINF_EM_SUSPEND:
697 case VINF_EM_HALT:
698 case VINF_EM_RESUME:
699 case VINF_EM_RESCHEDULE:
700 case VINF_EM_RESCHEDULE_REM:
701 case VINF_EM_RESCHEDULE_RAW:
702 if (rc < rcRet || rcRet == VINF_SUCCESS)
703 rcRet = rc;
704 break;
705 }
706 }
707 else if (RT_FAILURE(rc))
708 {
709 LogFlow(("dbgfR3VMMWait: returns %Rrc\n", rc));
710 return rc;
711 }
712 }
713
714 /*
715 * Process the command.
716 */
717 bool fResumeExecution;
718 DBGFCMDDATA CmdData = pVM->dbgf.s.VMMCmdData;
719 DBGFCMD enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND);
720 int rc = dbgfR3VMMCmd(pVM, enmCmd, &CmdData, &fResumeExecution);
721 if (fResumeExecution)
722 {
723 if (RT_FAILURE(rc))
724 rcRet = rc;
725 else if ( rc >= VINF_EM_FIRST
726 && rc <= VINF_EM_LAST
727 && (rc < rcRet || rcRet == VINF_SUCCESS))
728 rcRet = rc;
729 LogFlow(("dbgfR3VMMWait: returns %Rrc\n", rcRet));
730 return rcRet;
731 }
732 }
733}
734
735
736/**
737 * Executes command from debugger.
738 * The caller is responsible for waiting or resuming execution based on the
739 * value returned in the *pfResumeExecution indicator.
740 *
741 * @returns VBox status. (clearify!)
742 * @param pVM Pointer to the VM.
743 * @param enmCmd The command in question.
744 * @param pCmdData Pointer to the command data.
745 * @param pfResumeExecution Where to store the resume execution / continue waiting indicator.
746 */
747static int dbgfR3VMMCmd(PVM pVM, DBGFCMD enmCmd, PDBGFCMDDATA pCmdData, bool *pfResumeExecution)
748{
749 bool fSendEvent;
750 bool fResume;
751 int rc = VINF_SUCCESS;
752
753 NOREF(pCmdData); /* for later */
754
755 switch (enmCmd)
756 {
757 /*
758 * Halt is answered by an event say that we've halted.
759 */
760 case DBGFCMD_HALT:
761 {
762 pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_HALT_DONE;
763 pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM);
764 fSendEvent = true;
765 fResume = false;
766 break;
767 }
768
769
770 /*
771 * Resume is not answered we'll just resume execution.
772 */
773 case DBGFCMD_GO:
774 {
775 fSendEvent = false;
776 fResume = true;
777 break;
778 }
779
780 /** @todo implement (and define) the rest of the commands. */
781
782 /*
783 * Disable breakpoints and stuff.
784 * Send an everythings cool event to the debugger thread and resume execution.
785 */
786 case DBGFCMD_DETACH_DEBUGGER:
787 {
788 ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, false);
789 pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_DETACH_DONE;
790 pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_OTHER;
791 fSendEvent = true;
792 fResume = true;
793 break;
794 }
795
796 /*
797 * The debugger has detached successfully.
798 * There is no reply to this event.
799 */
800 case DBGFCMD_DETACHED_DEBUGGER:
801 {
802 fSendEvent = false;
803 fResume = true;
804 break;
805 }
806
807 /*
808 * Single step, with trace into.
809 */
810 case DBGFCMD_SINGLE_STEP:
811 {
812 Log2(("Single step\n"));
813 rc = VINF_EM_DBG_STEP;
814 /** @todo SMP */
815 PVMCPU pVCpu = VMMGetCpu0(pVM);
816 pVCpu->dbgf.s.fSingleSteppingRaw = true;
817 fSendEvent = false;
818 fResume = true;
819 break;
820 }
821
822 /*
823 * Default is to send an invalid command event.
824 */
825 default:
826 {
827 pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_INVALID_COMMAND;
828 pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM);
829 fSendEvent = true;
830 fResume = false;
831 break;
832 }
833 }
834
835 /*
836 * Send pending event.
837 */
838 if (fSendEvent)
839 {
840 Log2(("DBGF: Emulation thread: sending event %d\n", pVM->dbgf.s.DbgEvent.enmType));
841 int rc2 = RTSemPing(&pVM->dbgf.s.PingPong);
842 if (RT_FAILURE(rc2))
843 {
844 AssertRC(rc2);
845 *pfResumeExecution = true;
846 return rc2;
847 }
848 }
849
850 /*
851 * Return.
852 */
853 *pfResumeExecution = fResume;
854 return rc;
855}
856
857
858/**
859 * Attaches a debugger to the specified VM.
860 *
861 * Only one debugger at a time.
862 *
863 * @returns VBox status code.
864 * @param pUVM The user mode VM handle.
865 */
866VMMR3DECL(int) DBGFR3Attach(PUVM pUVM)
867{
868 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
869 PVM pVM = pUVM->pVM;
870 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
871
872 /*
873 * Call the VM, use EMT for serialization.
874 */
875 /** @todo SMP */
876 return VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)dbgfR3Attach, 1, pVM);
877}
878
879
880/**
881 * EMT worker for DBGFR3Attach.
882 *
883 * @returns VBox status code.
884 * @param pVM Pointer to the VM.
885 */
886static DECLCALLBACK(int) dbgfR3Attach(PVM pVM)
887{
888 if (pVM->dbgf.s.fAttached)
889 {
890 Log(("dbgR3Attach: Debugger already attached\n"));
891 return VERR_DBGF_ALREADY_ATTACHED;
892 }
893
894 /*
895 * Create the Ping-Pong structure.
896 */
897 int rc = RTSemPingPongInit(&pVM->dbgf.s.PingPong);
898 AssertRCReturn(rc, rc);
899
900 /*
901 * Set the attached flag.
902 */
903 ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, true);
904 return VINF_SUCCESS;
905}
906
907
908/**
909 * Detaches a debugger from the specified VM.
910 *
911 * Caller must be attached to the VM.
912 *
913 * @returns VBox status code.
914 * @param pUVM The user mode VM handle.
915 */
916VMMR3DECL(int) DBGFR3Detach(PUVM pUVM)
917{
918 LogFlow(("DBGFR3Detach:\n"));
919 int rc;
920
921 /*
922 * Check if attached.
923 */
924 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
925 PVM pVM = pUVM->pVM;
926 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
927 AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
928
929 /*
930 * Try send the detach command.
931 * Keep in mind that we might be racing EMT, so, be extra careful.
932 */
933 DBGFCMD enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_DETACH_DEBUGGER);
934 if (RTSemPongIsSpeaker(&pVM->dbgf.s.PingPong))
935 {
936 rc = RTSemPong(&pVM->dbgf.s.PingPong);
937 AssertMsgRCReturn(rc, ("Failed to signal emulation thread. rc=%Rrc\n", rc), rc);
938 LogRel(("DBGFR3Detach: enmCmd=%d (pong -> ping)\n", enmCmd));
939 }
940
941 /*
942 * Wait for the OK event.
943 */
944 rc = RTSemPongWait(&pVM->dbgf.s.PingPong, RT_INDEFINITE_WAIT);
945 AssertLogRelMsgRCReturn(rc, ("Wait on detach command failed, rc=%Rrc\n", rc), rc);
946
947 /*
948 * Send the notification command indicating that we're really done.
949 */
950 enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_DETACHED_DEBUGGER);
951 rc = RTSemPong(&pVM->dbgf.s.PingPong);
952 AssertMsgRCReturn(rc, ("Failed to signal emulation thread. rc=%Rrc\n", rc), rc);
953
954 LogFlowFunc(("returns VINF_SUCCESS\n"));
955 return VINF_SUCCESS;
956}
957
958
959/**
960 * Wait for a debug event.
961 *
962 * @returns VBox status. Will not return VBOX_INTERRUPTED.
963 * @param pUVM The user mode VM handle.
964 * @param cMillies Number of millis to wait.
965 * @param ppEvent Where to store the event pointer.
966 */
967VMMR3DECL(int) DBGFR3EventWait(PUVM pUVM, RTMSINTERVAL cMillies, PCDBGFEVENT *ppEvent)
968{
969 /*
970 * Check state.
971 */
972 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
973 PVM pVM = pUVM->pVM;
974 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
975 AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
976 *ppEvent = NULL;
977
978 /*
979 * Wait.
980 */
981 int rc = RTSemPongWait(&pVM->dbgf.s.PingPong, cMillies);
982 if (RT_SUCCESS(rc))
983 {
984 *ppEvent = &pVM->dbgf.s.DbgEvent;
985 Log2(("DBGF: Debugger thread: receiving event %d\n", (*ppEvent)->enmType));
986 return VINF_SUCCESS;
987 }
988
989 return rc;
990}
991
992
993/**
994 * Halts VM execution.
995 *
996 * After calling this the VM isn't actually halted till an DBGFEVENT_HALT_DONE
997 * arrives. Until that time it's not possible to issue any new commands.
998 *
999 * @returns VBox status.
1000 * @param pUVM The user mode VM handle.
1001 */
1002VMMR3DECL(int) DBGFR3Halt(PUVM pUVM)
1003{
1004 /*
1005 * Check state.
1006 */
1007 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
1008 PVM pVM = pUVM->pVM;
1009 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
1010 AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
1011 RTPINGPONGSPEAKER enmSpeaker = pVM->dbgf.s.PingPong.enmSpeaker;
1012 if ( enmSpeaker == RTPINGPONGSPEAKER_PONG
1013 || enmSpeaker == RTPINGPONGSPEAKER_PONG_SIGNALED)
1014 return VWRN_DBGF_ALREADY_HALTED;
1015
1016 /*
1017 * Send command.
1018 */
1019 dbgfR3SetCmd(pVM, DBGFCMD_HALT);
1020
1021 return VINF_SUCCESS;
1022}
1023
1024
1025/**
1026 * Checks if the VM is halted by the debugger.
1027 *
1028 * @returns True if halted.
1029 * @returns False if not halted.
1030 * @param pUVM The user mode VM handle.
1031 */
1032VMMR3DECL(bool) DBGFR3IsHalted(PUVM pUVM)
1033{
1034 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
1035 PVM pVM = pUVM->pVM;
1036 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
1037 AssertReturn(pVM->dbgf.s.fAttached, false);
1038
1039 RTPINGPONGSPEAKER enmSpeaker = pVM->dbgf.s.PingPong.enmSpeaker;
1040 return enmSpeaker == RTPINGPONGSPEAKER_PONG_SIGNALED
1041 || enmSpeaker == RTPINGPONGSPEAKER_PONG;
1042}
1043
1044
1045/**
1046 * Checks if the debugger can wait for events or not.
1047 *
1048 * This function is only used by lazy, multiplexing debuggers. :-)
1049 *
1050 * @returns True if waitable.
1051 * @returns False if not waitable.
1052 * @param pUVM The user mode VM handle.
1053 */
1054VMMR3DECL(bool) DBGFR3CanWait(PUVM pUVM)
1055{
1056 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1057 PVM pVM = pUVM->pVM;
1058 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1059 AssertReturn(pVM->dbgf.s.fAttached, false);
1060
1061 return RTSemPongShouldWait(&pVM->dbgf.s.PingPong);
1062}
1063
1064
1065/**
1066 * Resumes VM execution.
1067 *
1068 * There is no receipt event on this command.
1069 *
1070 * @returns VBox status.
1071 * @param pUVM The user mode VM handle.
1072 */
1073VMMR3DECL(int) DBGFR3Resume(PUVM pUVM)
1074{
1075 /*
1076 * Check state.
1077 */
1078 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1079 PVM pVM = pUVM->pVM;
1080 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1081 AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
1082 AssertReturn(RTSemPongIsSpeaker(&pVM->dbgf.s.PingPong), VERR_SEM_OUT_OF_TURN);
1083
1084 /*
1085 * Send the ping back to the emulation thread telling it to run.
1086 */
1087 dbgfR3SetCmd(pVM, DBGFCMD_GO);
1088 int rc = RTSemPong(&pVM->dbgf.s.PingPong);
1089 AssertRC(rc);
1090
1091 return rc;
1092}
1093
1094
1095/**
1096 * Step Into.
1097 *
1098 * A single step event is generated from this command.
1099 * The current implementation is not reliable, so don't rely on the event coming.
1100 *
1101 * @returns VBox status.
1102 * @param pUVM The user mode VM handle.
1103 * @param idCpu The ID of the CPU to single step on.
1104 */
1105VMMR3DECL(int) DBGFR3Step(PUVM pUVM, VMCPUID idCpu)
1106{
1107 /*
1108 * Check state.
1109 */
1110 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1111 PVM pVM = pUVM->pVM;
1112 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1113 AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED);
1114 AssertReturn(RTSemPongIsSpeaker(&pVM->dbgf.s.PingPong), VERR_SEM_OUT_OF_TURN);
1115 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
1116
1117 /*
1118 * Send the ping back to the emulation thread telling it to run.
1119 */
1120/** @todo SMP (idCpu) */
1121 dbgfR3SetCmd(pVM, DBGFCMD_SINGLE_STEP);
1122 int rc = RTSemPong(&pVM->dbgf.s.PingPong);
1123 AssertRC(rc);
1124 return rc;
1125}
1126
1127
1128/**
1129 * Call this to single step programmatically.
1130 *
1131 * You must pass down the return code to the EM loop! That's
1132 * where the actual single stepping take place (at least in the
1133 * current implementation).
1134 *
1135 * @returns VINF_EM_DBG_STEP
1136 *
1137 * @param pVCpu Pointer to the VMCPU.
1138 *
1139 * @thread VCpu EMT
1140 * @internal
1141 */
1142VMMR3_INT_DECL(int) DBGFR3PrgStep(PVMCPU pVCpu)
1143{
1144 VMCPU_ASSERT_EMT(pVCpu);
1145
1146 pVCpu->dbgf.s.fSingleSteppingRaw = true;
1147 return VINF_EM_DBG_STEP;
1148}
1149
1150
1151/**
1152 * Inject an NMI into a running VM (only VCPU 0!)
1153 *
1154 * @returns VBox status code.
1155 * @param pVM Pointer to the VM.
1156 */
1157VMMR3DECL(int) DBGFR3InjectNMI(PUVM pUVM, VMCPUID idCpu)
1158{
1159 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1160 PVM pVM = pUVM->pVM;
1161 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1162 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
1163
1164 /** @todo Implement generic NMI injection. */
1165 if (!HMIsEnabled(pVM))
1166 return VERR_NOT_SUP_IN_RAW_MODE;
1167
1168 VMCPU_FF_SET(&pVM->aCpus[idCpu], VMCPU_FF_INTERRUPT_NMI);
1169 return VINF_SUCCESS;
1170}
1171
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