VirtualBox

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

Last change on this file since 23911 was 23145, checked in by vboxsync, 15 years ago

VMM: Extended VMMR3EmtRendezvous with TYPE_ASCENDING, TYPE_DESCENDING and STOP_ON_ERROR for use with VM state changes. The return type of the callback was changed so that the callback can feed scheduling info to EM.

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