VirtualBox

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

Last change on this file since 19167 was 19141, checked in by vboxsync, 16 years ago

Action flags breakup.
Fixed PGM saved state loading of 2.2.2 images.
Reduced hacks in PATM state loading (fixups).

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