VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGConsole.cpp@ 35628

Last change on this file since 35628 was 35628, checked in by vboxsync, 14 years ago

Debugger Console: Clean up, split the command evaluation code out of DBGConsole.cpp and into DBGCEval.cpp.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.1 KB
Line 
1/* $Id: DBGConsole.cpp 35628 2011-01-19 14:58:26Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console.
4 */
5
6/*
7 * Copyright (C) 2006-2011 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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_dbgc DBGC - The Debug Console
20 *
21 * The debugger console is an early attempt to make some interactive
22 * debugging facilities for the VirtualBox VMM. It was initially only
23 * accessible thru a telnet session on debug builds. Later it was hastily
24 * built into the VBoxDbg module with a very simple Qt wrapper around it.
25 *
26 * The debugger is optional and presently not built into release builds
27 * of VirtualBox. It is therefore necessary to enclose code related to it
28 * in \#ifdef VBOX_WITH_DEBUGGER blocks. This is mandatory for components
29 * that register extenral commands.
30 *
31 *
32 * @section sec_dbgc_op Operation (intentions)
33 *
34 * The console will process commands in a manner similar to the OS/2 and
35 * windows kernel debuggers. This means ';' is a command separator and
36 * that when possible we'll use the same command names as these two uses.
37 *
38 *
39 * @subsection sec_dbg_op_numbers Numbers
40 *
41 * Numbers are hexadecimal unless specified with a prefix indicating
42 * elsewise. Prefixes:
43 * - '0x' - hexadecimal.
44 * - '0i' - decimal
45 * - '0t' - octal.
46 * - '0y' - binary.
47 *
48 * Some of the prefixes are a bit uncommon, the reason for this that
49 * the typical binary prefix '0b' can also be a hexadecimal value since
50 * no prefix or suffix is required for such values. Ditto for '0d' and
51 * '0' for decimal and octal.
52 *
53 *
54 * @subsection sec_dbg_op_address Addressing modes
55 *
56 * - Default is flat. For compatibility '%' also means flat.
57 * - Segmented addresses are specified selector:offset.
58 * - Physical addresses are specified using '%%'.
59 * - The default target for the addressing is the guest context, the '#'
60 * will override this and set it to the host.
61 * Note that several operations won't work on host addresses.
62 *
63 * The '%', '%%' and '#' prefixes is implemented as unary operators, while ':'
64 * is a binary operator. Operator precedence takes care of evaluation order.
65 *
66 *
67 * @subsection sec_dbg_op_evalution Evaluation
68 *
69 * Most unary and binary C operators are supported, check the help text for
70 * details. However, some of these are not yet implemented because this is
71 * tiresome and annoying work. So, if something is missing and you need it
72 * you implement it or complain to bird. (Ditto for missing functions.)
73 *
74 * Simple variable support is provided thru the 'set' and 'unset' commands and
75 * the unary '$' operator.
76 *
77 * The unary '@' operator will indicate function calls. Commands and functions
78 * are the same thing, except that functions has a return type.
79 *
80 *
81 * @subsection sec_dbg_op_registers Registers
82 *
83 * Registers are addressed using their name. Some registers which have several fields
84 * (like gdtr) will have separate names indicating the different fields. The default
85 * register set is the guest one. To access the hypervisor register one have to
86 * prefix the register names with '.'.
87 *
88 * The registers are implemented as built-in symbols. For making gdb guys more at
89 * home it is possible to access them with the '$' operator, i.e. as a variable.
90 *
91 *
92 * @subsection sec_dbg_op_commands Commands and Functions
93 *
94 * Commands and functions are the same thing, except that functions may return a
95 * value. So, functions may be used as commands. The command/function handlers
96 * can detect whether they are invoked as a command or function by checking whether
97 * there is a return variable or not.
98 *
99 * The command/function names are all lowercase, case sensitive, and starting
100 * with a letter. Operator characters are not permitted in the names of course.
101 * Space is allowed, but must be flagged so the parser can check for multiple
102 * spaces and tabs. (This feature is for 'dump xyz' and for emulating the
103 * gdb 'info abc'.)
104 *
105 * The '.' prefix indicates the set of external commands. External commands are
106 * command registered by VMM components.
107 *
108 *
109 * @section sec_dbgc_logging Logging
110 *
111 * The idea is to be able to pass thru debug and release logs to the console
112 * if the user so wishes. This feature requires some kind of hook into the
113 * logger instance and while this was sketched it hasn't yet been implemented
114 * (dbgcProcessLog and DBGC::fLog).
115 *
116 *
117 *
118 * @section sec_dbgc_linking Linking and API
119 *
120 * The DBGC code is linked into the VBoxVMM module. (At present it is also
121 * linked into VBoxDbg, but this is obviously very wrong.)
122 *
123 * A COM object will be created for the DBGC so it can be operated remotely
124 * without using TCP. VBoxDbg is the intended audience for this usage. Some
125 * questions about callbacks (for output) and security (you may wish to
126 * restrict users from debugging a VM) needs to be answered first though.
127 */
128
129
130/*******************************************************************************
131* Header Files *
132*******************************************************************************/
133#define LOG_GROUP LOG_GROUP_DBGC
134#include <VBox/dbg.h>
135#include <VBox/vmm/dbgf.h>
136#include <VBox/err.h>
137#include <VBox/log.h>
138
139#include <iprt/asm.h>
140#include <iprt/assert.h>
141#include <iprt/mem.h>
142#include <iprt/string.h>
143
144#include "DBGCInternal.h"
145#include "DBGPlugIns.h"
146
147
148/*******************************************************************************
149* Internal Functions *
150*******************************************************************************/
151static int dbgcProcessLog(PDBGC pDbgc);
152
153
154/**
155 * Resolves a symbol (or tries to do so at least).
156 *
157 * @returns 0 on success.
158 * @returns VBox status on failure.
159 * @param pDbgc The debug console instance.
160 * @param pszSymbol The symbol name.
161 * @param enmType The result type. Specifying DBGCVAR_TYPE_GC_FAR may
162 * cause failure, avoid it.
163 * @param pResult Where to store the result.
164 */
165int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)
166{
167 int rc;
168
169 /*
170 * Builtin?
171 */
172 PCDBGCSYM pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol);
173 if (pSymDesc)
174 {
175 if (!pSymDesc->pfnGet)
176 return VERR_PARSE_WRITEONLY_SYMBOL;
177 return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult);
178 }
179
180 /*
181 * A typical register? (Guest only)
182 */
183 static const char s_szSixLetterRegisters[] =
184 "rflags;eflags;"
185 ;
186 static const char s_szThreeLetterRegisters[] =
187 "eax;rax;" "r10;" "r8d;r8w;r8b;" "cr0;" "dr0;"
188 "ebx;rbx;" "r11;" "r9d;r9w;r8b;" "dr1;"
189 "ecx;rcx;" "r12;" "cr2;" "dr2;"
190 "edx;rdx;" "r13;" "cr3;" "dr3;"
191 "edi;rdi;dil;" "r14;" "cr4;" "dr4;"
192 "esi;rsi;sil;" "r15;" "cr8;"
193 "ebp;rbp;"
194 "esp;rsp;" "dr6;"
195 "rip;eip;" "dr7;"
196 "efl;"
197 ;
198 static const char s_szTwoLetterRegisters[] =
199 "ax;al;ah;" "r8;"
200 "bx;bl;bh;" "r9;"
201 "cx;cl;ch;" "cs;"
202 "dx;dl;dh;" "ds;"
203 "di;" "es;"
204 "si;" "fs;"
205 "bp;" "gs;"
206 "sp;" "ss;"
207 "ip;"
208 ;
209 size_t const cchSymbol = strlen(pszSymbol);
210 if ( (cchSymbol == 2 && strstr(s_szTwoLetterRegisters, pszSymbol))
211 || (cchSymbol == 3 && strstr(s_szThreeLetterRegisters, pszSymbol))
212 || (cchSymbol == 6 && strstr(s_szSixLetterRegisters, pszSymbol)))
213 {
214 if (!strchr(pszSymbol, ';'))
215 {
216 DBGCVAR Var;
217 DBGCVAR_INIT_STRING(&Var, pszSymbol);
218 rc = dbgcOpRegister(pDbgc, &Var, pResult);
219 if (RT_SUCCESS(rc))
220 return DBGCCmdHlpConvert(&pDbgc->CmdHlp, &Var, enmType, false /*fConvSyms*/, pResult);
221 }
222 }
223
224 /*
225 * Ask PDM.
226 */
227 /** @todo resolve symbols using PDM. */
228
229 /*
230 * Ask the debug info manager.
231 */
232 RTDBGSYMBOL Symbol;
233 rc = DBGFR3AsSymbolByName(pDbgc->pVM, pDbgc->hDbgAs, pszSymbol, &Symbol, NULL);
234 if (RT_SUCCESS(rc))
235 {
236 /*
237 * Default return is a flat gc address.
238 */
239 DBGCVAR_INIT_GC_FLAT(pResult, Symbol.Value);
240 if (Symbol.cb)
241 DBGCVAR_SET_RANGE(pResult, DBGCVAR_RANGE_BYTES, Symbol.cb);
242
243 switch (enmType)
244 {
245 /* nothing to do. */
246 case DBGCVAR_TYPE_GC_FLAT:
247 case DBGCVAR_TYPE_ANY:
248 return VINF_SUCCESS;
249
250 /* impossible at the moment. */
251 case DBGCVAR_TYPE_GC_FAR:
252 return VERR_PARSE_CONVERSION_FAILED;
253
254 /* simply make it numeric. */
255 case DBGCVAR_TYPE_NUMBER:
256 pResult->enmType = DBGCVAR_TYPE_NUMBER;
257 pResult->u.u64Number = Symbol.Value;
258 return VINF_SUCCESS;
259
260 /* cast it. */
261 case DBGCVAR_TYPE_GC_PHYS:
262 case DBGCVAR_TYPE_HC_FLAT:
263 case DBGCVAR_TYPE_HC_PHYS:
264 return DBGCCmdHlpConvert(&pDbgc->CmdHlp, pResult, enmType, false /*fConvSyms*/, pResult);
265
266 default:
267 AssertMsgFailed(("Internal error enmType=%d\n", enmType));
268 return VERR_INVALID_PARAMETER;
269 }
270 }
271
272 return VERR_PARSE_NOT_IMPLEMENTED;
273}
274
275
276/**
277 * Process all commands currently in the buffer.
278 *
279 * @returns VBox status code. Any error indicates the termination of the console session.
280 * @param pDbgc Debugger console instance data.
281 * @param fNoExecute Indicates that no commands should actually be executed.
282 */
283static int dbgcProcessCommands(PDBGC pDbgc, bool fNoExecute)
284{
285 /** @todo Replace this with a sh/ksh/csh/rexx like toplevel language that
286 * allows doing function, loops, if, cases, and such. */
287 int rc = 0;
288 while (pDbgc->cInputLines)
289 {
290 /*
291 * Empty the log buffer if we're hooking the log.
292 */
293 if (pDbgc->fLog)
294 {
295 rc = dbgcProcessLog(pDbgc);
296 if (RT_FAILURE(rc))
297 break;
298 }
299
300 if (pDbgc->iRead == pDbgc->iWrite)
301 {
302 AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));
303 pDbgc->cInputLines = 0;
304 return 0;
305 }
306
307 /*
308 * Copy the command to the parse buffer.
309 */
310 char ch;
311 char *psz = &pDbgc->achInput[pDbgc->iRead];
312 char *pszTrg = &pDbgc->achScratch[0];
313 while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )
314 {
315 if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])
316 psz = &pDbgc->achInput[0];
317
318 if (psz == &pDbgc->achInput[pDbgc->iWrite])
319 {
320 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));
321 pDbgc->cInputLines = 0;
322 return 0;
323 }
324
325 pszTrg++;
326 }
327 *pszTrg = '\0';
328
329 /*
330 * Advance the buffer.
331 */
332 pDbgc->iRead = psz - &pDbgc->achInput[0];
333 if (ch == '\n')
334 pDbgc->cInputLines--;
335
336 /*
337 * Parse and execute this command.
338 */
339 pDbgc->pszScratch = psz;
340 pDbgc->iArg = 0;
341 rc = dbgcEvalCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1, fNoExecute);
342 if (rc)
343 break;
344 }
345
346 return rc;
347}
348
349
350/**
351 * Handle input buffer overflow.
352 *
353 * Will read any available input looking for a '\n' to reset the buffer on.
354 *
355 * @returns VBox status.
356 * @param pDbgc Debugger console instance data.
357 */
358static int dbgcInputOverflow(PDBGC pDbgc)
359{
360 /*
361 * Assert overflow status and reset the input buffer.
362 */
363 if (!pDbgc->fInputOverflow)
364 {
365 pDbgc->fInputOverflow = true;
366 pDbgc->iRead = pDbgc->iWrite = 0;
367 pDbgc->cInputLines = 0;
368 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");
369 }
370
371 /*
372 * Eat input till no more or there is a '\n'.
373 * When finding a '\n' we'll continue normal processing.
374 */
375 while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
376 {
377 size_t cbRead;
378 int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);
379 if (RT_FAILURE(rc))
380 return rc;
381 char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);
382 if (psz)
383 {
384 pDbgc->fInputOverflow = false;
385 pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;
386 pDbgc->iWrite = (unsigned)cbRead;
387 pDbgc->cInputLines = 0;
388 break;
389 }
390 }
391
392 return 0;
393}
394
395
396/**
397 * Read input and do some preprocessing.
398 *
399 * @returns VBox status.
400 * In addition to the iWrite and achInput, cInputLines is maintained.
401 * In case of an input overflow the fInputOverflow flag will be set.
402 * @param pDbgc Debugger console instance data.
403 */
404static int dbgcInputRead(PDBGC pDbgc)
405{
406 /*
407 * We have ready input.
408 * Read it till we don't have any or we have a full input buffer.
409 */
410 int rc = 0;
411 do
412 {
413 /*
414 * More available buffer space?
415 */
416 size_t cbLeft;
417 if (pDbgc->iWrite > pDbgc->iRead)
418 cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);
419 else
420 cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;
421 if (!cbLeft)
422 {
423 /* overflow? */
424 if (!pDbgc->cInputLines)
425 rc = dbgcInputOverflow(pDbgc);
426 break;
427 }
428
429 /*
430 * Read one char and interpret it.
431 */
432 char achRead[128];
433 size_t cbRead;
434 rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);
435 if (RT_FAILURE(rc))
436 return rc;
437 char *psz = &achRead[0];
438 while (cbRead-- > 0)
439 {
440 char ch = *psz++;
441 switch (ch)
442 {
443 /*
444 * Ignore.
445 */
446 case '\0':
447 case '\r':
448 case '\a':
449 break;
450
451 /*
452 * Backspace.
453 */
454 case '\b':
455 Log2(("DBGC: backspace\n"));
456 if (pDbgc->iRead != pDbgc->iWrite)
457 {
458 unsigned iWriteUndo = pDbgc->iWrite;
459 if (pDbgc->iWrite)
460 pDbgc->iWrite--;
461 else
462 pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;
463
464 if (pDbgc->achInput[pDbgc->iWrite] == '\n')
465 pDbgc->iWrite = iWriteUndo;
466 }
467 break;
468
469 /*
470 * Add char to buffer.
471 */
472 case '\t':
473 case '\n':
474 case ';':
475 switch (ch)
476 {
477 case '\t': ch = ' '; break;
478 case '\n': pDbgc->cInputLines++; break;
479 }
480 default:
481 Log2(("DBGC: ch=%02x\n", (unsigned char)ch));
482 pDbgc->achInput[pDbgc->iWrite] = ch;
483 if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))
484 pDbgc->iWrite = 0;
485 break;
486 }
487 }
488
489 /* Terminate it to make it easier to read in the debugger. */
490 pDbgc->achInput[pDbgc->iWrite] = '\0';
491 } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));
492
493 return rc;
494}
495
496
497/**
498 * Reads input, parses it and executes commands on '\n'.
499 *
500 * @returns VBox status.
501 * @param pDbgc Debugger console instance data.
502 * @param fNoExecute Indicates that no commands should actually be executed.
503 */
504int dbgcProcessInput(PDBGC pDbgc, bool fNoExecute)
505{
506 /*
507 * We know there's input ready, so let's read it first.
508 */
509 int rc = dbgcInputRead(pDbgc);
510 if (RT_FAILURE(rc))
511 return rc;
512
513 /*
514 * Now execute any ready commands.
515 */
516 if (pDbgc->cInputLines)
517 {
518 pDbgc->pBack->pfnSetReady(pDbgc->pBack, false);
519 pDbgc->fReady = false;
520 rc = dbgcProcessCommands(pDbgc, fNoExecute);
521 if (RT_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)
522 pDbgc->fReady = true;
523
524 if ( RT_SUCCESS(rc)
525 && pDbgc->iRead == pDbgc->iWrite
526 && pDbgc->fReady)
527 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
528
529 if ( RT_SUCCESS(rc)
530 && pDbgc->fReady)
531 pDbgc->pBack->pfnSetReady(pDbgc->pBack, true);
532 }
533 else
534 /* Received nonsense; just skip it. */
535 pDbgc->iRead = pDbgc->iWrite;
536
537 return rc;
538}
539
540
541/**
542 * Gets the event context identifier string.
543 * @returns Read only string.
544 * @param enmCtx The context.
545 */
546static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)
547{
548 switch (enmCtx)
549 {
550 case DBGFEVENTCTX_RAW: return "raw";
551 case DBGFEVENTCTX_REM: return "rem";
552 case DBGFEVENTCTX_HWACCL: return "hwaccl";
553 case DBGFEVENTCTX_HYPER: return "hyper";
554 case DBGFEVENTCTX_OTHER: return "other";
555
556 case DBGFEVENTCTX_INVALID: return "!Invalid Event Ctx!";
557 default:
558 AssertMsgFailed(("enmCtx=%d\n", enmCtx));
559 return "!Unknown Event Ctx!";
560 }
561}
562
563
564/**
565 * Processes debugger events.
566 *
567 * @returns VBox status.
568 * @param pDbgc DBGC Instance data.
569 * @param pEvent Pointer to event data.
570 */
571static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)
572{
573 /*
574 * Flush log first.
575 */
576 if (pDbgc->fLog)
577 {
578 int rc = dbgcProcessLog(pDbgc);
579 if (RT_FAILURE(rc))
580 return rc;
581 }
582
583 /*
584 * Process the event.
585 */
586 pDbgc->pszScratch = &pDbgc->achInput[0];
587 pDbgc->iArg = 0;
588 bool fPrintPrompt = true;
589 int rc = VINF_SUCCESS;
590 switch (pEvent->enmType)
591 {
592 /*
593 * The first part is events we have initiated with commands.
594 */
595 case DBGFEVENT_HALT_DONE:
596 {
597 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",
598 pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));
599 pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */
600 if (RT_SUCCESS(rc))
601 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
602 break;
603 }
604
605
606 /*
607 * The second part is events which can occur at any time.
608 */
609 case DBGFEVENT_FATAL_ERROR:
610 {
611 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
612 dbgcGetEventCtx(pEvent->enmCtx));
613 pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */
614 if (RT_SUCCESS(rc))
615 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
616 break;
617 }
618
619 case DBGFEVENT_BREAKPOINT:
620 case DBGFEVENT_BREAKPOINT_HYPER:
621 {
622 bool fRegCtxGuest = pDbgc->fRegCtxGuest;
623 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;
624
625 rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
626 switch (rc)
627 {
628 case VERR_DBGC_BP_NOT_FOUND:
629 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
630 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
631 break;
632
633 case VINF_DBGC_BP_NO_COMMAND:
634 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
635 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
636 break;
637
638 case VINF_BUFFER_OVERFLOW:
639 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
640 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
641 break;
642
643 default:
644 break;
645 }
646 if (RT_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))
647 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
648 else
649 pDbgc->fRegCtxGuest = fRegCtxGuest;
650 break;
651 }
652
653 case DBGFEVENT_STEPPED:
654 case DBGFEVENT_STEPPED_HYPER:
655 {
656 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;
657
658 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));
659 if (RT_SUCCESS(rc))
660 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
661 break;
662 }
663
664 case DBGFEVENT_ASSERTION_HYPER:
665 {
666 pDbgc->fRegCtxGuest = false;
667
668 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
669 "\ndbgf event: Hypervisor Assertion! (%s)\n"
670 "%s"
671 "%s"
672 "\n",
673 dbgcGetEventCtx(pEvent->enmCtx),
674 pEvent->u.Assert.pszMsg1,
675 pEvent->u.Assert.pszMsg2);
676 if (RT_SUCCESS(rc))
677 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
678 break;
679 }
680
681 case DBGFEVENT_DEV_STOP:
682 {
683 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
684 "\n"
685 "dbgf event: DBGFSTOP (%s)\n"
686 "File: %s\n"
687 "Line: %d\n"
688 "Function: %s\n",
689 dbgcGetEventCtx(pEvent->enmCtx),
690 pEvent->u.Src.pszFile,
691 pEvent->u.Src.uLine,
692 pEvent->u.Src.pszFunction);
693 if (RT_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)
694 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
695 "Message: %s\n",
696 pEvent->u.Src.pszMessage);
697 if (RT_SUCCESS(rc))
698 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
699 break;
700 }
701
702
703 case DBGFEVENT_INVALID_COMMAND:
704 {
705 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");
706 break;
707 }
708
709 case DBGFEVENT_TERMINATING:
710 {
711 pDbgc->fReady = false;
712 pDbgc->pBack->pfnSetReady(pDbgc->pBack, false);
713 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");
714 fPrintPrompt = false;
715 rc = VERR_GENERAL_FAILURE;
716 break;
717 }
718
719
720 default:
721 {
722 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
723 break;
724 }
725 }
726
727 /*
728 * Prompt, anyone?
729 */
730 if (fPrintPrompt && RT_SUCCESS(rc))
731 {
732 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
733 pDbgc->fReady = true;
734 if (RT_SUCCESS(rc))
735 pDbgc->pBack->pfnSetReady(pDbgc->pBack, true);
736 }
737
738 return rc;
739}
740
741
742/**
743 * Prints any log lines from the log buffer.
744 *
745 * The caller must not call function this unless pDbgc->fLog is set.
746 *
747 * @returns VBox status. (output related)
748 * @param pDbgc Debugger console instance data.
749 */
750static int dbgcProcessLog(PDBGC pDbgc)
751{
752 /** @todo */
753 NOREF(pDbgc);
754 return 0;
755}
756
757
758/**
759 * Run the debugger console.
760 *
761 * @returns VBox status.
762 * @param pDbgc Pointer to the debugger console instance data.
763 */
764int dbgcRun(PDBGC pDbgc)
765{
766 /*
767 * We're ready for commands now.
768 */
769 pDbgc->fReady = true;
770 pDbgc->pBack->pfnSetReady(pDbgc->pBack, true);
771
772 /*
773 * Main Debugger Loop.
774 *
775 * This loop will either block on waiting for input or on waiting on
776 * debug events. If we're forwarding the log we cannot wait for long
777 * before we must flush the log.
778 */
779 int rc = VINF_SUCCESS;
780 for (;;)
781 {
782 if ( pDbgc->pVM
783 && DBGFR3CanWait(pDbgc->pVM))
784 {
785 /*
786 * Wait for a debug event.
787 */
788 PCDBGFEVENT pEvent;
789 rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);
790 if (RT_SUCCESS(rc))
791 {
792 rc = dbgcProcessEvent(pDbgc, pEvent);
793 if (RT_FAILURE(rc))
794 break;
795 }
796 else if (rc != VERR_TIMEOUT)
797 break;
798
799 /*
800 * Check for input.
801 */
802 if (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
803 {
804 rc = dbgcProcessInput(pDbgc, false /* fNoExecute */);
805 if (RT_FAILURE(rc))
806 break;
807 }
808 }
809 else
810 {
811 /*
812 * Wait for input. If Logging is enabled we'll only wait very briefly.
813 */
814 if (pDbgc->pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))
815 {
816 rc = dbgcProcessInput(pDbgc, false /* fNoExecute */);
817 if (RT_FAILURE(rc))
818 break;
819 }
820 }
821
822 /*
823 * Forward log output.
824 */
825 if (pDbgc->fLog)
826 {
827 rc = dbgcProcessLog(pDbgc);
828 if (RT_FAILURE(rc))
829 break;
830 }
831 }
832
833 return rc;
834}
835
836
837/**
838 * Creates a a new instance.
839 *
840 * @returns VBox status code.
841 * @param ppDbgc Where to store the pointer to the instance data.
842 * @param pBack Pointer to the backend.
843 * @param fFlags The flags.
844 */
845int dbgcCreate(PDBGC *ppDbgc, PDBGCBACK pBack, unsigned fFlags)
846{
847 /*
848 * Validate input.
849 */
850 AssertPtrReturn(pBack, VERR_INVALID_POINTER);
851 AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);
852
853 /*
854 * Allocate and initialize.
855 */
856 PDBGC pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));
857 if (!pDbgc)
858 return VERR_NO_MEMORY;
859
860 dbgcInitCmdHlp(pDbgc);
861 pDbgc->pBack = pBack;
862 pDbgc->pVM = NULL;
863 pDbgc->idCpu = NIL_VMCPUID;
864 pDbgc->hDbgAs = DBGF_AS_GLOBAL;
865 pDbgc->pszEmulation = "CodeView/WinDbg";
866 pDbgc->paEmulationCmds = &g_aCmdsCodeView[0];
867 pDbgc->cEmulationCmds = g_cCmdsCodeView;
868 //pDbgc->fLog = false;
869 pDbgc->fRegCtxGuest = true;
870 pDbgc->fRegTerse = true;
871 //pDbgc->cPagingHierarchyDumps = 0;
872 //pDbgc->DisasmPos = {0};
873 //pDbgc->SourcePos = {0};
874 //pDbgc->DumpPos = {0};
875 pDbgc->pLastPos = &pDbgc->DisasmPos;
876 //pDbgc->cbDumpElement = 0;
877 //pDbgc->cVars = 0;
878 //pDbgc->paVars = NULL;
879 //pDbgc->pPlugInHead = NULL;
880 //pDbgc->pFirstBp = NULL;
881 //pDbgc->abSearch = {0};
882 //pDbgc->cbSearch = 0;
883 pDbgc->cbSearchUnit = 1;
884 pDbgc->cMaxSearchHits = 1;
885 //pDbgc->SearchAddr = {0};
886 //pDbgc->cbSearchRange = 0;
887
888 //pDbgc->uInputZero = 0;
889 //pDbgc->iRead = 0;
890 //pDbgc->iWrite = 0;
891 //pDbgc->cInputLines = 0;
892 //pDbgc->fInputOverflow = false;
893 pDbgc->fReady = true;
894 pDbgc->pszScratch = &pDbgc->achScratch[0];
895 //pDbgc->iArg = 0;
896 //pDbgc->rcOutput = 0;
897 //pDbgc->rcCmd = 0;
898
899 dbgcEvalInit();
900
901 *ppDbgc = pDbgc;
902 return VINF_SUCCESS;
903}
904
905/**
906 * Destroys a DBGC instance created by dbgcCreate.
907 *
908 * @param pDbgc Pointer to the debugger console instance data.
909 */
910void dbgcDestroy(PDBGC pDbgc)
911{
912 AssertPtr(pDbgc);
913
914 /* Disable log hook. */
915 if (pDbgc->fLog)
916 {
917
918 }
919
920 /* Unload all plug-ins. */
921 dbgcPlugInUnloadAll(pDbgc);
922
923 /* Detach from the VM. */
924 if (pDbgc->pVM)
925 DBGFR3Detach(pDbgc->pVM);
926
927 /* finally, free the instance memory. */
928 RTMemFree(pDbgc);
929}
930
931
932/**
933 * Make a console instance.
934 *
935 * This will not return until either an 'exit' command is issued or a error code
936 * indicating connection loss is encountered.
937 *
938 * @returns VINF_SUCCESS if console termination caused by the 'exit' command.
939 * @returns The VBox status code causing the console termination.
940 *
941 * @param pVM VM Handle.
942 * @param pBack Pointer to the backend structure. This must contain
943 * a full set of function pointers to service the console.
944 * @param fFlags Reserved, must be zero.
945 * @remark A forced termination of the console is easiest done by forcing the
946 * callbacks to return fatal failures.
947 */
948DBGDECL(int) DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)
949{
950 /*
951 * Validate input.
952 */
953 AssertPtrNullReturn(pVM, VERR_INVALID_POINTER);
954
955 /*
956 * Allocate and initialize instance data
957 */
958 PDBGC pDbgc;
959 int rc = dbgcCreate(&pDbgc, pBack, fFlags);
960 if (RT_FAILURE(rc))
961 return rc;
962
963 /*
964 * Print welcome message.
965 */
966 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
967 "Welcome to the VirtualBox Debugger!\n");
968
969 /*
970 * Attach to the specified VM.
971 */
972 if (RT_SUCCESS(rc) && pVM)
973 {
974 rc = DBGFR3Attach(pVM);
975 if (RT_SUCCESS(rc))
976 {
977 pDbgc->pVM = pVM;
978 pDbgc->idCpu = 0;
979 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
980 "Current VM is %08x, CPU #%u\n" /** @todo get and print the VM name! */
981 , pDbgc->pVM, pDbgc->idCpu);
982 }
983 else
984 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);
985 }
986
987 /*
988 * Load plugins.
989 */
990 if (RT_SUCCESS(rc))
991 {
992 if (pVM)
993 dbgcPlugInAutoLoad(pDbgc);
994 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
995 }
996 else
997 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nDBGCCreate error: %Rrc\n", rc);
998
999 /*
1000 * Run the debugger main loop.
1001 */
1002 if (RT_SUCCESS(rc))
1003 rc = dbgcRun(pDbgc);
1004
1005 /*
1006 * Cleanup console debugger session.
1007 */
1008 dbgcDestroy(pDbgc);
1009 return rc == VERR_DBGC_QUIT ? VINF_SUCCESS : rc;
1010}
1011
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette