VirtualBox

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

Last change on this file since 12837 was 12832, checked in by vboxsync, 16 years ago

DBGF: spaces.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 30.0 KB
Line 
1/* $Id: DBGF.cpp 12832 2008-09-30 13:51:53Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/** @page pg_dbgf DBGF - The Debugger Facility
24 *
25 * The purpose of the DBGF is to provide an interface for debuggers to
26 * manipulate the VMM without having to mess up the source code for each of
27 * them. The DBGF is always built in and will always work when a debugger
28 * attaches to the VM. The DBGF provides the basic debugger features, such as
29 * halting execution, handling breakpoints, single step execution, instruction
30 * disassembly, info querying, OS specific diggers, symbol and module
31 * management.
32 *
33 * The interface is working in a manner similar to the win32, linux and os2
34 * debugger interfaces. It interface has an asynchronous nature. This comes from
35 * the fact that the VMM and the Debugger are running in different threads. They
36 * are refered to as the "emulation thread" and the "debugger thread", or as the
37 * "ping thread" and the "pong thread, respectivly. (The last set of names comes
38 * from the use of the Ping-Pong synchronization construct from the RTSem API.)
39 *
40 *
41 *
42 * @section sec_dbgf_scenario Usage Scenario
43 *
44 * The debugger starts by attaching to the VM. For pratical reasons we limit the
45 * number of concurrently attached debuggers to 1 per VM. The action of
46 * attaching to the VM causes the VM to check and generate debug events.
47 *
48 * The debugger then will wait/poll for debug events and issue commands.
49 *
50 * The waiting and polling is done by the DBGFEventWait() function. It will wait
51 * for the emulation thread to send a ping, thus indicating that there is an
52 * event waiting to be processed.
53 *
54 * An event can be a respons to an command issued previously, the hitting of a
55 * breakpoint, or running into a bad/fatal VMM condition. The debugger now have
56 * the ping and must respond to the event at hand - the VMM is waiting. This
57 * usually means that the user of the debugger must do something, but it doesn't
58 * have to. The debugger is free to call any DBGF function (nearly at least)
59 * while processing the event.
60 *
61 * Typically the user will issue a request for the execution to be resumed, so
62 * the debugger calls DBGFResume() and goes back to waiting/polling for events.
63 *
64 * When the user eventually terminates the debugging session or selects another
65 * VM, the debugger detaches from the VM. This means that breakpoints are
66 * disabled and that the emulation thread no longer polls for debugger commands.
67 *
68 */
69
70
71/*******************************************************************************
72* Header Files *
73*******************************************************************************/
74#define LOG_GROUP LOG_GROUP_DBGF
75#include <VBox/dbgf.h>
76#include <VBox/selm.h>
77#include <VBox/rem.h>
78#include <VBox/em.h>
79#include "DBGFInternal.h"
80#include <VBox/vm.h>
81#include <VBox/err.h>
82
83#include <VBox/log.h>
84#include <iprt/semaphore.h>
85#include <iprt/thread.h>
86#include <iprt/asm.h>
87#include <iprt/time.h>
88#include <iprt/assert.h>
89#include <iprt/stream.h>
90
91
92/*******************************************************************************
93* Internal Functions *
94*******************************************************************************/
95static int dbgfR3VMMWait(PVM pVM);
96static int dbgfR3VMMCmd(PVM pVM, DBGFCMD enmCmd, PDBGFCMDDATA pCmdData, bool *pfResumeExecution);
97
98
99/**
100 * Sets the VMM Debug Command variable.
101 *
102 * @returns Previous command.
103 * @param pVM VM Handle.
104 * @param enmCmd The command.
105 */
106DECLINLINE(DBGFCMD) dbgfR3SetCmd(PVM pVM, DBGFCMD enmCmd)
107{
108 DBGFCMD rc;
109 if (enmCmd == DBGFCMD_NO_COMMAND)
110 {
111 Log2(("DBGF: Setting command to %d (DBGFCMD_NO_COMMAND)\n", enmCmd));
112 rc = (DBGFCMD)ASMAtomicXchgU32((uint32_t volatile *)(void *)&pVM->dbgf.s.enmVMMCmd, enmCmd);
113 VM_FF_CLEAR(pVM, VM_FF_DBGF);
114 }
115 else
116 {
117 Log2(("DBGF: Setting command to %d\n", enmCmd));
118 AssertMsg(pVM->dbgf.s.enmVMMCmd == DBGFCMD_NO_COMMAND, ("enmCmd=%d enmVMMCmd=%d\n", enmCmd, pVM->dbgf.s.enmVMMCmd));
119 rc = (DBGFCMD)ASMAtomicXchgU32((uint32_t volatile *)(void *)&pVM->dbgf.s.enmVMMCmd, enmCmd);
120 VM_FF_SET(pVM, VM_FF_DBGF);
121 VMR3NotifyFF(pVM, false /* didn't notify REM */);
122 }
123 return rc;
124}
125
126
127/**
128 * Initializes the DBGF.
129 *
130 * @returns VBox status code.
131 * @param pVM VM handle.
132 */
133DBGFR3DECL(int) DBGFR3Init(PVM pVM)
134{
135 int rc = dbgfR3InfoInit(pVM);
136 if (VBOX_SUCCESS(rc))
137 rc = dbgfR3SymInit(pVM);
138 if (VBOX_SUCCESS(rc))
139 rc = dbgfR3BpInit(pVM);
140 return rc;
141}
142
143
144/**
145 * Termiantes and cleans up resources allocated by the DBGF.
146 *
147 * @returns VBox status code.
148 * @param pVM VM Handle.
149 */
150DBGFR3DECL(int) DBGFR3Term(PVM pVM)
151{
152 int rc;
153
154 /*
155 * Send a termination event to any attached debuggers.
156 */
157 /* wait for any pending events or whatever */
158 if ( pVM->dbgf.s.fAttached
159 && pVM->dbgf.s.PingPong.enmSpeaker == RTPINGPONGSPEAKER_PONG)
160 {
161 RTThreadSleep(32); /* Don't want that assertion if we can help it. */
162 while ( pVM->dbgf.s.fAttached
163 && pVM->dbgf.s.PingPong.enmSpeaker == RTPINGPONGSPEAKER_PONG)
164 if (RTSemPingWait(&pVM->dbgf.s.PingPong, 5000) != VERR_TIMEOUT)
165 break;
166 }
167
168 /* now, send the event */
169 if ( pVM->dbgf.s.fAttached
170 && pVM->dbgf.s.PingPong.enmSpeaker != RTPINGPONGSPEAKER_PONG)
171 {
172 pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_TERMINATING;
173 pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_OTHER;
174 rc = RTSemPing(&pVM->dbgf.s.PingPong);
175 if (VBOX_SUCCESS(rc))
176 {
177 /*
178 * Waits for the debugger to detach.
179 */
180 while (pVM->dbgf.s.fAttached)
181 {
182 /*
183 * Wait.
184 */
185 rc = RTSemPingWait(&pVM->dbgf.s.PingPong, 1000);
186
187 /*
188 * Process the command.
189 */
190 DBGFCMDDATA CmdData = pVM->dbgf.s.VMMCmdData;
191 DBGFCMD enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND);
192 if (enmCmd != DBGFCMD_NO_COMMAND)
193 {
194 bool fResumeExecution = false;
195 rc = dbgfR3VMMCmd(pVM, enmCmd, &CmdData, &fResumeExecution);
196 if (enmCmd == DBGFCMD_DETACH_DEBUGGER)
197 break;
198 }
199 else if (VBOX_FAILURE(rc))
200 break;
201 }
202 }
203 }
204
205 /*
206 * Terminate the other bits.
207 */
208 dbgfR3OSTerm(pVM);
209 dbgfR3InfoTerm(pVM);
210 return VINF_SUCCESS;
211}
212
213
214/**
215 * Applies relocations to data and code managed by this
216 * component. This function will be called at init and
217 * whenever the VMM need to relocate it self inside the GC.
218 *
219 * @param pVM VM handle.
220 * @param offDelta Relocation delta relative to old location.
221 */
222DBGFR3DECL(void) DBGFR3Relocate(PVM pVM, RTGCINTPTR offDelta)
223{
224}
225
226
227/**
228 * Waits a little while for a debuggger to attach.
229 *
230 * @returns True is a debugger have attached.
231 * @param pVM VM handle.
232 * @param enmEvent Event.
233 */
234bool dbgfR3WaitForAttach(PVM pVM, DBGFEVENTTYPE enmEvent)
235{
236 /*
237 * First a message.
238 */
239#ifndef RT_OS_L4
240
241# if !defined(DEBUG) || defined(DEBUG_sandervl) || defined(DEBUG_frank)
242 int cWait = 10;
243# else
244 int cWait = 150;
245# endif
246 RTStrmPrintf(g_pStdErr, "DBGF: No debugger attached, waiting %d second%s for one to attach (event=%d)\n",
247 cWait / 10, cWait != 10 ? "s" : "", enmEvent);
248 RTStrmFlush(g_pStdErr);
249 while (cWait > 0)
250 {
251 RTThreadSleep(100);
252 if (pVM->dbgf.s.fAttached)
253 {
254 RTStrmPrintf(g_pStdErr, "Attached!\n");
255 RTStrmFlush(g_pStdErr);
256 return true;
257 }
258
259 /* next */
260 if (!(cWait % 10))
261 {
262 RTStrmPrintf(g_pStdErr, "%d.", cWait / 10);
263 RTStrmFlush(g_pStdErr);
264 }
265 cWait--;
266 }
267#endif
268
269 RTStrmPrintf(g_pStdErr, "Stopping the VM!\n");
270 RTStrmFlush(g_pStdErr);
271 return false;
272}
273
274
275/**
276 * Forced action callback.
277 * The VMM will call this from it's main loop when VM_FF_DBGF is set.
278 *
279 * The function checks and executes pending commands from the debugger.
280 *
281 * @returns VINF_SUCCESS normally.
282 * @returns VERR_DBGF_RAISE_FATAL_ERROR to pretend a fatal error happend.
283 * @param pVM VM Handle.
284 */
285DBGFR3DECL(int) DBGFR3VMMForcedAction(PVM pVM)
286{
287 /*
288 * Clear the FF DBGF request flag.
289 */
290 Assert(pVM->fForcedActions & VM_FF_DBGF);
291 VM_FF_CLEAR(pVM, VM_FF_DBGF);
292
293 /*
294 * Commands?
295 */
296 int rc = VINF_SUCCESS;
297 if (pVM->dbgf.s.enmVMMCmd != DBGFCMD_NO_COMMAND)
298 {
299 /** @todo stupid GDT/LDT sync hack. go away! */
300 SELMR3UpdateFromCPUM(pVM);
301
302 /*
303 * Process the command.
304 */
305 bool fResumeExecution;
306 DBGFCMDDATA CmdData = pVM->dbgf.s.VMMCmdData;
307 DBGFCMD enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND);
308 rc = dbgfR3VMMCmd(pVM, enmCmd, &CmdData, &fResumeExecution);
309 if (!fResumeExecution)
310 rc = dbgfR3VMMWait(pVM);
311 }
312 return rc;
313}
314
315
316/**
317 * Flag whether the event implies that we're stopped in the hypervisor code
318 * and have to block certain operations.
319 *
320 * @param pVM The VM handle.
321 * @param enmEvent The event.
322 */
323static void dbgfR3EventSetStoppedInHyperFlag(PVM pVM, DBGFEVENTTYPE enmEvent)
324{
325 switch (enmEvent)
326 {
327 case DBGFEVENT_STEPPED_HYPER:
328 case DBGFEVENT_ASSERTION_HYPER:
329 case DBGFEVENT_BREAKPOINT_HYPER:
330 pVM->dbgf.s.fStoppedInHyper = true;
331 break;
332 default:
333 pVM->dbgf.s.fStoppedInHyper = false;
334 break;
335 }
336}
337
338
339/**
340 * Try determin the event context.
341 *
342 * @returns debug event context.
343 * @param pVM The VM handle.
344 */
345static DBGFEVENTCTX dbgfR3FigureEventCtx(PVM pVM)
346{
347 switch (EMGetState(pVM))
348 {
349 case EMSTATE_RAW:
350 case EMSTATE_DEBUG_GUEST_RAW:
351 return DBGFEVENTCTX_RAW;
352
353 case EMSTATE_REM:
354 case EMSTATE_DEBUG_GUEST_REM:
355 return DBGFEVENTCTX_REM;
356
357 case EMSTATE_DEBUG_HYPER:
358 case EMSTATE_GURU_MEDITATION:
359 return DBGFEVENTCTX_HYPER;
360
361 default:
362 return DBGFEVENTCTX_OTHER;
363 }
364}
365
366/**
367 * The common event prologue code.
368 * It will set the 'stopped-in-hyper' flag, make sure someone's attach,
369 * and perhaps process any high priority pending actions (none yet).
370 *
371 * @returns VBox status.
372 * @param pVM The VM handle.
373 * @param enmEvent The event to be sent.
374 */
375static int dbgfR3EventPrologue(PVM pVM, DBGFEVENTTYPE enmEvent)
376{
377 /*
378 * Check if a debugger is attached.
379 */
380 if ( !pVM->dbgf.s.fAttached
381 && !dbgfR3WaitForAttach(pVM, enmEvent))
382 {
383 Log(("DBGFR3VMMEventSrc: enmEvent=%d - debugger not attached\n", enmEvent));
384 return VERR_DBGF_NOT_ATTACHED;
385 }
386
387 /*
388 * Sync back the state from the REM.
389 */
390 dbgfR3EventSetStoppedInHyperFlag(pVM, enmEvent);
391 if (!pVM->dbgf.s.fStoppedInHyper)
392 REMR3StateUpdate(pVM);
393
394 /*
395 * Look thru pending commands and finish those which make sense now.
396 */
397 /** @todo Process/purge pending commands. */
398 //int rc = DBGFR3VMMForcedAction(pVM);
399 return VINF_SUCCESS;
400}
401
402
403/**
404 * Sends the event in the event buffer.
405 *
406 * @returns VBox status code.
407 * @param pVM The VM handle.
408 */
409static int dbgfR3SendEvent(PVM pVM)
410{
411 int rc = RTSemPing(&pVM->dbgf.s.PingPong);
412 if (VBOX_SUCCESS(rc))
413 rc = dbgfR3VMMWait(pVM);
414
415 pVM->dbgf.s.fStoppedInHyper = false;
416 /** @todo sync VMM -> REM after exitting the debugger. everything may change while in the debugger! */
417 return rc;
418}
419
420
421/**
422 * Send a generic debugger event which takes no data.
423 *
424 * @returns VBox status.
425 * @param pVM The VM handle.
426 * @param enmEvent The event to send.
427 */
428DBGFR3DECL(int) DBGFR3Event(PVM pVM, DBGFEVENTTYPE enmEvent)
429{
430 int rc = dbgfR3EventPrologue(pVM, enmEvent);
431 if (VBOX_FAILURE(rc))
432 return rc;
433
434 /*
435 * Send the event and process the reply communication.
436 */
437 pVM->dbgf.s.DbgEvent.enmType = enmEvent;
438 pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM);
439 return dbgfR3SendEvent(pVM);
440}
441
442
443/**
444 * Send a debugger event which takes the full source file location.
445 *
446 * @returns VBox status.
447 * @param pVM The VM handle.
448 * @param enmEvent The event to send.
449 * @param pszFile Source file.
450 * @param uLine Line number in source file.
451 * @param pszFunction Function name.
452 * @param pszFormat Message which accompanies the event.
453 * @param ... Message arguments.
454 */
455DBGFR3DECL(int) DBGFR3EventSrc(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, const char *pszFunction, const char *pszFormat, ...)
456{
457 va_list args;
458 va_start(args, pszFormat);
459 int rc = DBGFR3EventSrcV(pVM, enmEvent, pszFile, uLine, pszFunction, pszFormat, args);
460 va_end(args);
461 return rc;
462}
463
464
465/**
466 * Send a debugger event which takes the full source file location.
467 *
468 * @returns VBox status.
469 * @param pVM The VM handle.
470 * @param enmEvent The event to send.
471 * @param pszFile Source file.
472 * @param uLine Line number in source file.
473 * @param pszFunction Function name.
474 * @param pszFormat Message which accompanies the event.
475 * @param args Message arguments.
476 */
477DBGFR3DECL(int) DBGFR3EventSrcV(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, const char *pszFunction, const char *pszFormat, va_list args)
478{
479 int rc = dbgfR3EventPrologue(pVM, enmEvent);
480 if (VBOX_FAILURE(rc))
481 return rc;
482
483 /*
484 * Format the message.
485 */
486 char *pszMessage = NULL;
487 char szMessage[8192];
488 if (pszFormat && *pszFormat)
489 {
490 pszMessage = &szMessage[0];
491 RTStrPrintfV(szMessage, sizeof(szMessage), pszFormat, args);
492 }
493
494 /*
495 * Send the event and process the reply communication.
496 */
497 pVM->dbgf.s.DbgEvent.enmType = enmEvent;
498 pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM);
499 pVM->dbgf.s.DbgEvent.u.Src.pszFile = pszFile;
500 pVM->dbgf.s.DbgEvent.u.Src.uLine = uLine;
501 pVM->dbgf.s.DbgEvent.u.Src.pszFunction = pszFunction;
502 pVM->dbgf.s.DbgEvent.u.Src.pszMessage = pszMessage;
503 return dbgfR3SendEvent(pVM);
504}
505
506
507/**
508 * Send a debugger event which takes the two assertion messages.
509 *
510 * @returns VBox status.
511 * @param pVM The VM handle.
512 * @param enmEvent The event to send.
513 * @param pszMsg1 First assertion message.
514 * @param pszMsg2 Second assertion message.
515 */
516DBGFR3DECL(int) DBGFR3EventAssertion(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszMsg1, const char *pszMsg2)
517{
518 int rc = dbgfR3EventPrologue(pVM, enmEvent);
519 if (VBOX_FAILURE(rc))
520 return rc;
521
522 /*
523 * Send the event and process the reply communication.
524 */
525 pVM->dbgf.s.DbgEvent.enmType = enmEvent;
526 pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM);
527 pVM->dbgf.s.DbgEvent.u.Assert.pszMsg1 = pszMsg1;
528 pVM->dbgf.s.DbgEvent.u.Assert.pszMsg2 = pszMsg2;
529 return dbgfR3SendEvent(pVM);
530}
531
532
533/**
534 * Breakpoint was hit somewhere.
535 * Figure out which breakpoint it is and notify the debugger.
536 *
537 * @returns VBox status.
538 * @param pVM The VM handle.
539 * @param enmEvent DBGFEVENT_BREAKPOINT_HYPER or DBGFEVENT_BREAKPOINT.
540 */
541DBGFR3DECL(int) DBGFR3EventBreakpoint(PVM pVM, DBGFEVENTTYPE enmEvent)
542{
543 int rc = dbgfR3EventPrologue(pVM, enmEvent);
544 if (VBOX_FAILURE(rc))
545 return rc;
546
547 /*
548 * Send the event and process the reply communication.
549 */
550 pVM->dbgf.s.DbgEvent.enmType = enmEvent;
551 RTUINT iBp = pVM->dbgf.s.DbgEvent.u.Bp.iBp = pVM->dbgf.s.iActiveBp;
552 pVM->dbgf.s.iActiveBp = ~0U;
553 if (iBp != ~0U)
554 pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_RAW;
555 else
556 {
557 /* REM breakpoints has be been searched for. */
558#if 0 /** @todo get flat PC api! */
559 uint32_t eip = CPUMGetGuestEIP(pVM);
560#else
561 PCPUMCTX pCtx;
562 CPUMQueryGuestCtxPtr(pVM, &pCtx);
563 RTGCPTR eip = pCtx->rip + pCtx->csHid.u64Base;
564#endif
565 for (iBp = 0; iBp < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); iBp++)
566 if ( pVM->dbgf.s.aBreakpoints[iBp].enmType == DBGFBPTYPE_REM
567 && pVM->dbgf.s.aBreakpoints[iBp].GCPtr == eip)
568 {
569 pVM->dbgf.s.DbgEvent.u.Bp.iBp = iBp;
570 break;
571 }
572 AssertMsg(pVM->dbgf.s.DbgEvent.u.Bp.iBp != ~0U, ("eip=%08x\n", eip));
573 pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_REM;
574 }
575 return dbgfR3SendEvent(pVM);
576}
577
578
579/**
580 * Waits for the debugger to respond.
581 *
582 * @returns VBox status. (clearify)
583 * @param pVM VM handle.
584 */
585static int dbgfR3VMMWait(PVM pVM)
586{
587 LogFlow(("dbgfR3VMMWait:\n"));
588
589 /** @todo stupid GDT/LDT sync hack. go away! */
590 SELMR3UpdateFromCPUM(pVM);
591 int rcRet = VINF_SUCCESS;
592
593 /*
594 * Waits for the debugger to reply (i.e. issue an command).
595 */
596 for (;;)
597 {
598 /*
599 * Wait.
600 */
601 for (;;)
602 {
603 int rc = RTSemPingWait(&pVM->dbgf.s.PingPong, 250);
604 if (VBOX_SUCCESS(rc))
605 break;
606 if (rc != VERR_TIMEOUT)
607 {
608 LogFlow(("dbgfR3VMMWait: returns %Vrc\n", rc));
609 return rc;
610 }
611
612 if (VM_FF_ISSET(pVM, VM_FF_REQUEST))
613 {
614 LogFlow(("dbgfR3VMMWait: Processes requests...\n"));
615 rc = VMR3ReqProcessU(pVM->pUVM);
616 LogFlow(("dbgfR3VMMWait: VMR3ReqProcess -> %Vrc rcRet=%Vrc\n", rc, rcRet));
617 if (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST)
618 {
619 switch (rc)
620 {
621 case VINF_EM_DBG_BREAKPOINT:
622 case VINF_EM_DBG_STEPPED:
623 case VINF_EM_DBG_STEP:
624 case VINF_EM_DBG_STOP:
625 AssertMsgFailed(("rc=%Vrc\n", rc));
626 break;
627
628 /* return straight away */
629 case VINF_EM_TERMINATE:
630 case VINF_EM_OFF:
631 LogFlow(("dbgfR3VMMWait: returns %Vrc\n", rc));
632 return rc;
633
634 /* remember return code. */
635 default:
636 AssertReleaseMsgFailed(("rc=%Vrc is not in the switch!\n", rc));
637 case VINF_EM_RESET:
638 case VINF_EM_SUSPEND:
639 case VINF_EM_HALT:
640 case VINF_EM_RESUME:
641 case VINF_EM_RESCHEDULE:
642 case VINF_EM_RESCHEDULE_REM:
643 case VINF_EM_RESCHEDULE_RAW:
644 if (rc < rcRet || rcRet == VINF_SUCCESS)
645 rcRet = rc;
646 break;
647 }
648 }
649 else if (VBOX_FAILURE(rc))
650 {
651 LogFlow(("dbgfR3VMMWait: returns %Vrc\n", rc));
652 return rc;
653 }
654 }
655 }
656
657 /*
658 * Process the command.
659 */
660 bool fResumeExecution;
661 DBGFCMDDATA CmdData = pVM->dbgf.s.VMMCmdData;
662 DBGFCMD enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND);
663 int rc = dbgfR3VMMCmd(pVM, enmCmd, &CmdData, &fResumeExecution);
664 if (fResumeExecution)
665 {
666 if (VBOX_FAILURE(rc))
667 rcRet = rc;
668 else if ( rc >= VINF_EM_FIRST
669 && rc <= VINF_EM_LAST
670 && (rc < rcRet || rcRet == VINF_SUCCESS))
671 rcRet = rc;
672 LogFlow(("dbgfR3VMMWait: returns %Vrc\n", rcRet));
673 return rcRet;
674 }
675 }
676}
677
678
679/**
680 * Executes command from debugger.
681 * The caller is responsible for waiting or resuming execution based on the
682 * value returned in the *pfResumeExecution indicator.
683 *
684 * @returns VBox status. (clearify!)
685 * @param pVM VM Handle.
686 * @param enmCmd The command in question.
687 * @param pCmdData Pointer to the command data.
688 * @param pfResumeExecution Where to store the resume execution / continue waiting indicator.
689 */
690static int dbgfR3VMMCmd(PVM pVM, DBGFCMD enmCmd, PDBGFCMDDATA pCmdData, bool *pfResumeExecution)
691{
692 bool fSendEvent;
693 bool fResume;
694 int rc = VINF_SUCCESS;
695
696 switch (enmCmd)
697 {
698 /*
699 * Halt is answered by an event say that we've halted.
700 */
701 case DBGFCMD_HALT:
702 {
703 pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_HALT_DONE;
704 pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM);
705 fSendEvent = true;
706 fResume = false;
707 break;
708 }
709
710
711 /*
712 * Resume is not answered we'll just resume execution.
713 */
714 case DBGFCMD_GO:
715 {
716 fSendEvent = false;
717 fResume = true;
718 break;
719 }
720
721 /** @todo implement (and define) the rest of the commands. */
722
723 /*
724 * Disable breakpoints and stuff.
725 * Send an everythings cool event to the debugger thread and resume execution.
726 */
727 case DBGFCMD_DETACH_DEBUGGER:
728 {
729 pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_DETACH_DONE;
730 pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_OTHER;
731 VM_FF_CLEAR(pVM, VM_FF_DBGF);
732 pVM->dbgf.s.fAttached = false;
733 fSendEvent = true;
734 fResume = true;
735 break;
736 }
737
738 /*
739 * Single step, with trace into.
740 */
741 case DBGFCMD_SINGLE_STEP:
742 {
743 Log2(("Single step\n"));
744 rc = VINF_EM_DBG_STEP;
745 pVM->dbgf.s.fSingleSteppingRaw = true;
746 fSendEvent = false;
747 fResume = true;
748 break;
749 }
750
751 /*
752 * Default is to send an invalid command event.
753 */
754 default:
755 {
756 pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_INVALID_COMMAND;
757 pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM);
758 fSendEvent = true;
759 fResume = false;
760 break;
761 }
762 }
763
764 /*
765 * Send pending event.
766 */
767 if (fSendEvent)
768 {
769 Log2(("DBGF: Emulation thread: sending event %d\n", pVM->dbgf.s.DbgEvent.enmType));
770 int rc2 = RTSemPing(&pVM->dbgf.s.PingPong);
771 if (VBOX_FAILURE(rc2))
772 {
773 AssertRC(rc2);
774 *pfResumeExecution = true;
775 return rc2;
776 }
777 }
778
779 /*
780 * Return.
781 */
782 *pfResumeExecution = fResume;
783 return rc;
784}
785
786
787
788
789/**
790 * Attaches a debugger to the specified VM.
791 *
792 * Only one debugger at a time.
793 *
794 * @returns VBox status code.
795 * @param pVM VM Handle.
796 */
797DBGFR3DECL(int) DBGFR3Attach(PVM pVM)
798{
799 /*
800 * Check if already attached.
801 */
802 if (pVM->dbgf.s.fAttached)
803 {
804 AssertMsgFailed(("Already attached\n"));
805 return VERR_DBGF_ALREADY_ATTACHED;
806 }
807
808 /*
809 * Create the Ping-Pong structure.
810 */
811 int rc = RTSemPingPongInit(&pVM->dbgf.s.PingPong);
812 if (rc)
813 return rc;
814
815 /*
816 * Set the attached flag.
817 */
818 pVM->dbgf.s.fAttached = true;
819 return VINF_SUCCESS;
820}
821
822
823/**
824 * Detaches a debugger from the specified VM.
825 *
826 * Caller must be attached to the VM.
827 *
828 * @returns VBox status code.
829 * @param pVM VM Handle.
830 */
831DBGFR3DECL(int) DBGFR3Detach(PVM pVM)
832{
833 LogFlowFunc(("\n"));
834
835 /*
836 * Check if attached.
837 */
838 if (!pVM->dbgf.s.fAttached)
839 {
840 AssertMsgFailed(("Not attached to VM!\n"));
841 return VERR_DBGF_NOT_ATTACHED;
842 }
843
844 /*
845 * Send detach command.
846 */
847 DBGFCMD enmCmd;
848 if (pVM->dbgf.s.PingPong.enmSpeaker == RTPINGPONGSPEAKER_PONG)
849 {
850 enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_DETACH_DEBUGGER);
851 int rc = RTSemPong(&pVM->dbgf.s.PingPong);
852 if (VBOX_FAILURE(rc))
853 {
854 AssertMsgFailed(("Failed to signal emulation thread. rc=%d\n", rc));
855 return rc;
856 }
857 LogFunc(("enmCmd=%d (pong -> ping)\n", enmCmd));
858 }
859 else
860 {
861 enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_DETACH_DEBUGGER);
862 LogFunc(("enmCmd=%d (ping)\n", enmCmd));
863 }
864
865 /*
866 * Wait for the ok event.
867 */
868 PCDBGFEVENT pEvent;
869 int rc = DBGFR3EventWait(pVM, RT_INDEFINITE_WAIT, &pEvent);
870 if (VBOX_FAILURE(rc))
871 {
872 AssertMsgFailed(("Wait on detach command failed, rc=%d\n", rc));
873 return rc;
874 }
875
876 /*
877 * Destroy the ping-pong construct and return.
878 */
879 ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, false);
880 RTThreadSleep(10);
881 rc = RTSemPingPongDestroy(&pVM->dbgf.s.PingPong);
882 AssertRC(rc);
883
884 LogFlowFunc(("returns VINF_SUCCESS\n"));
885 return VINF_SUCCESS;
886}
887
888
889
890/**
891 * Wait for a debug event.
892 *
893 * @returns VBox status. Will not return VBOX_INTERRUPTED.
894 * @param pVM VM handle.
895 * @param cMillies Number of millies to wait.
896 * @param ppEvent Where to store the event pointer.
897 */
898DBGFR3DECL(int) DBGFR3EventWait(PVM pVM, unsigned cMillies, PCDBGFEVENT *ppEvent)
899{
900 /*
901 * Check state.
902 */
903 if (!pVM->dbgf.s.fAttached)
904 {
905 AssertMsgFailed(("Not attached to VM!\n"));
906 return VERR_DBGF_NOT_ATTACHED;
907 }
908 *ppEvent = NULL;
909
910 /*
911 * Wait.
912 */
913 int rc = RTSemPongWait(&pVM->dbgf.s.PingPong, cMillies);
914 if (VBOX_SUCCESS(rc))
915 {
916 *ppEvent = &pVM->dbgf.s.DbgEvent;
917 Log2(("DBGF: Debugger thread: receiving event %d\n", (*ppEvent)->enmType));
918 return VINF_SUCCESS;
919 }
920
921 return rc;
922}
923
924
925/**
926 * Halts VM execution.
927 *
928 * After calling this the VM isn't actually halted till an DBGFEVENT_HALT_DONE
929 * arrives. Until that time it's not possible to issue any new commands.
930 *
931 * @returns VBox status.
932 * @param pVM VM handle.
933 */
934DBGFR3DECL(int) DBGFR3Halt(PVM pVM)
935{
936 /*
937 * Check state.
938 */
939 if (!pVM->dbgf.s.fAttached)
940 {
941 AssertMsgFailed(("Not attached to VM!\n"));
942 return VERR_DBGF_NOT_ATTACHED;
943 }
944 if ( pVM->dbgf.s.PingPong.enmSpeaker == RTPINGPONGSPEAKER_PONG
945 || pVM->dbgf.s.PingPong.enmSpeaker == RTPINGPONGSPEAKER_PONG_SIGNALED)
946 return VWRN_DBGF_ALREADY_HALTED;
947
948 /*
949 * Send command.
950 */
951 dbgfR3SetCmd(pVM, DBGFCMD_HALT);
952
953 return VINF_SUCCESS;
954}
955
956
957/**
958 * Checks if the VM is halted by the debugger.
959 *
960 * @returns True if halted.
961 * @returns False if not halted.
962 * @param pVM VM handle.
963 */
964DBGFR3DECL(bool) DBGFR3IsHalted(PVM pVM)
965{
966 AssertMsg(pVM->dbgf.s.fAttached, ("Not attached to VM!\n"));
967
968 RTPINGPONGSPEAKER enmSpeaker = pVM->dbgf.s.PingPong.enmSpeaker;
969 return pVM->dbgf.s.fAttached
970 && ( enmSpeaker == RTPINGPONGSPEAKER_PONG_SIGNALED
971 || enmSpeaker == RTPINGPONGSPEAKER_PONG);
972}
973
974
975/**
976 * Checks if the the debugger can wait for events or not.
977 *
978 * This function is only used by lazy, multiplexing debuggers. :-)
979 *
980 * @returns True if waitable.
981 * @returns False if not waitable.
982 * @param pVM VM handle.
983 */
984DBGFR3DECL(bool) DBGFR3CanWait(PVM pVM)
985{
986 AssertMsg(pVM->dbgf.s.fAttached, ("Not attached to VM!\n"));
987
988 RTPINGPONGSPEAKER enmSpeaker = pVM->dbgf.s.PingPong.enmSpeaker;
989 return pVM->dbgf.s.fAttached
990 && ( enmSpeaker == RTPINGPONGSPEAKER_PING
991 || enmSpeaker == RTPINGPONGSPEAKER_PING_SIGNALED
992 || enmSpeaker == RTPINGPONGSPEAKER_PONG_SIGNALED);
993}
994
995
996/**
997 * Resumes VM execution.
998 *
999 * There is no receipt event on this command.
1000 *
1001 * @returns VBox status.
1002 * @param pVM VM handle.
1003 */
1004DBGFR3DECL(int) DBGFR3Resume(PVM pVM)
1005{
1006 /*
1007 * Check state.
1008 */
1009 if (!pVM->dbgf.s.fAttached)
1010 {
1011 AssertMsgFailed(("Not attached to VM!\n"));
1012 return VERR_DBGF_NOT_ATTACHED;
1013 }
1014 if (pVM->dbgf.s.PingPong.enmSpeaker != RTPINGPONGSPEAKER_PONG)
1015 {
1016 AssertMsgFailed(("Speaking out of turn!\n"));
1017 return VERR_SEM_OUT_OF_TURN;
1018 }
1019
1020 /*
1021 * Send the ping back to the emulation thread telling it to run.
1022 */
1023 dbgfR3SetCmd(pVM, DBGFCMD_GO);
1024 int rc = RTSemPong(&pVM->dbgf.s.PingPong);
1025 AssertRC(rc);
1026
1027 return rc;
1028}
1029
1030
1031/**
1032 * Step Into.
1033 *
1034 * A single step event is generated from this command.
1035 * The current implementation is not reliable, so don't rely on the event comming.
1036 *
1037 * @returns VBox status.
1038 * @param pVM VM handle.
1039 */
1040DBGFR3DECL(int) DBGFR3Step(PVM pVM)
1041{
1042 /*
1043 * Check state.
1044 */
1045 if (!pVM->dbgf.s.fAttached)
1046 {
1047 AssertMsgFailed(("Not attached to VM!\n"));
1048 return VERR_DBGF_NOT_ATTACHED;
1049 }
1050 if (pVM->dbgf.s.PingPong.enmSpeaker != RTPINGPONGSPEAKER_PONG)
1051 {
1052 AssertMsgFailed(("Speaking out of turn!\n"));
1053 return VERR_SEM_OUT_OF_TURN;
1054 }
1055
1056 /*
1057 * Send the ping back to the emulation thread telling it to run.
1058 */
1059 dbgfR3SetCmd(pVM, DBGFCMD_SINGLE_STEP);
1060 int rc = RTSemPong(&pVM->dbgf.s.PingPong);
1061 AssertRC(rc);
1062 return rc;
1063}
1064
1065
1066/**
1067 * Call this to single step rawmode or recompiled mode.
1068 *
1069 * You must pass down the return code to the EM loop! That's
1070 * where the actual single stepping take place (at least in the
1071 * current implementation).
1072 *
1073 * @returns VINF_EM_DBG_STEP
1074 * @thread EMT
1075 */
1076DBGFR3DECL(int) DBGFR3PrgStep(PVM pVM)
1077{
1078 VM_ASSERT_EMT(pVM);
1079
1080 pVM->dbgf.s.fSingleSteppingRaw = true;
1081 return VINF_EM_DBG_STEP;
1082}
1083
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