VirtualBox

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

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

DBGConsole.cpp: don't quit on error.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.2 KB
Line 
1/* $Id: DBGConsole.cpp 35829 2011-02-03 10:18:53Z 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.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/** @page pg_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 = VINF_SUCCESS;
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 == VERR_DBGC_QUIT
343 || rc == VWRN_DBGC_CMD_PENDING)
344 break;
345 rc = VINF_SUCCESS; /* ignore other statuses */
346 }
347
348 return rc;
349}
350
351
352/**
353 * Handle input buffer overflow.
354 *
355 * Will read any available input looking for a '\n' to reset the buffer on.
356 *
357 * @returns VBox status.
358 * @param pDbgc Debugger console instance data.
359 */
360static int dbgcInputOverflow(PDBGC pDbgc)
361{
362 /*
363 * Assert overflow status and reset the input buffer.
364 */
365 if (!pDbgc->fInputOverflow)
366 {
367 pDbgc->fInputOverflow = true;
368 pDbgc->iRead = pDbgc->iWrite = 0;
369 pDbgc->cInputLines = 0;
370 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");
371 }
372
373 /*
374 * Eat input till no more or there is a '\n'.
375 * When finding a '\n' we'll continue normal processing.
376 */
377 while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
378 {
379 size_t cbRead;
380 int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);
381 if (RT_FAILURE(rc))
382 return rc;
383 char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);
384 if (psz)
385 {
386 pDbgc->fInputOverflow = false;
387 pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;
388 pDbgc->iWrite = (unsigned)cbRead;
389 pDbgc->cInputLines = 0;
390 break;
391 }
392 }
393
394 return 0;
395}
396
397
398/**
399 * Read input and do some preprocessing.
400 *
401 * @returns VBox status.
402 * In addition to the iWrite and achInput, cInputLines is maintained.
403 * In case of an input overflow the fInputOverflow flag will be set.
404 * @param pDbgc Debugger console instance data.
405 */
406static int dbgcInputRead(PDBGC pDbgc)
407{
408 /*
409 * We have ready input.
410 * Read it till we don't have any or we have a full input buffer.
411 */
412 int rc = 0;
413 do
414 {
415 /*
416 * More available buffer space?
417 */
418 size_t cbLeft;
419 if (pDbgc->iWrite > pDbgc->iRead)
420 cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);
421 else
422 cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;
423 if (!cbLeft)
424 {
425 /* overflow? */
426 if (!pDbgc->cInputLines)
427 rc = dbgcInputOverflow(pDbgc);
428 break;
429 }
430
431 /*
432 * Read one char and interpret it.
433 */
434 char achRead[128];
435 size_t cbRead;
436 rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);
437 if (RT_FAILURE(rc))
438 return rc;
439 char *psz = &achRead[0];
440 while (cbRead-- > 0)
441 {
442 char ch = *psz++;
443 switch (ch)
444 {
445 /*
446 * Ignore.
447 */
448 case '\0':
449 case '\r':
450 case '\a':
451 break;
452
453 /*
454 * Backspace.
455 */
456 case '\b':
457 Log2(("DBGC: backspace\n"));
458 if (pDbgc->iRead != pDbgc->iWrite)
459 {
460 unsigned iWriteUndo = pDbgc->iWrite;
461 if (pDbgc->iWrite)
462 pDbgc->iWrite--;
463 else
464 pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;
465
466 if (pDbgc->achInput[pDbgc->iWrite] == '\n')
467 pDbgc->iWrite = iWriteUndo;
468 }
469 break;
470
471 /*
472 * Add char to buffer.
473 */
474 case '\t':
475 case '\n':
476 case ';':
477 switch (ch)
478 {
479 case '\t': ch = ' '; break;
480 case '\n': pDbgc->cInputLines++; break;
481 }
482 default:
483 Log2(("DBGC: ch=%02x\n", (unsigned char)ch));
484 pDbgc->achInput[pDbgc->iWrite] = ch;
485 if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))
486 pDbgc->iWrite = 0;
487 break;
488 }
489 }
490
491 /* Terminate it to make it easier to read in the debugger. */
492 pDbgc->achInput[pDbgc->iWrite] = '\0';
493 } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));
494
495 return rc;
496}
497
498
499/**
500 * Reads input, parses it and executes commands on '\n'.
501 *
502 * @returns VBox status.
503 * @param pDbgc Debugger console instance data.
504 * @param fNoExecute Indicates that no commands should actually be executed.
505 */
506int dbgcProcessInput(PDBGC pDbgc, bool fNoExecute)
507{
508 /*
509 * We know there's input ready, so let's read it first.
510 */
511 int rc = dbgcInputRead(pDbgc);
512 if (RT_FAILURE(rc))
513 return rc;
514
515 /*
516 * Now execute any ready commands.
517 */
518 if (pDbgc->cInputLines)
519 {
520 pDbgc->pBack->pfnSetReady(pDbgc->pBack, false);
521 pDbgc->fReady = false;
522 rc = dbgcProcessCommands(pDbgc, fNoExecute);
523 if (RT_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)
524 pDbgc->fReady = true;
525
526 if ( RT_SUCCESS(rc)
527 && pDbgc->iRead == pDbgc->iWrite
528 && pDbgc->fReady)
529 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
530
531 if ( RT_SUCCESS(rc)
532 && pDbgc->fReady)
533 pDbgc->pBack->pfnSetReady(pDbgc->pBack, true);
534 }
535 else
536 /* Received nonsense; just skip it. */
537 pDbgc->iRead = pDbgc->iWrite;
538
539 return rc;
540}
541
542
543/**
544 * Gets the event context identifier string.
545 * @returns Read only string.
546 * @param enmCtx The context.
547 */
548static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)
549{
550 switch (enmCtx)
551 {
552 case DBGFEVENTCTX_RAW: return "raw";
553 case DBGFEVENTCTX_REM: return "rem";
554 case DBGFEVENTCTX_HWACCL: return "hwaccl";
555 case DBGFEVENTCTX_HYPER: return "hyper";
556 case DBGFEVENTCTX_OTHER: return "other";
557
558 case DBGFEVENTCTX_INVALID: return "!Invalid Event Ctx!";
559 default:
560 AssertMsgFailed(("enmCtx=%d\n", enmCtx));
561 return "!Unknown Event Ctx!";
562 }
563}
564
565
566/**
567 * Processes debugger events.
568 *
569 * @returns VBox status.
570 * @param pDbgc DBGC Instance data.
571 * @param pEvent Pointer to event data.
572 */
573static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)
574{
575 /*
576 * Flush log first.
577 */
578 if (pDbgc->fLog)
579 {
580 int rc = dbgcProcessLog(pDbgc);
581 if (RT_FAILURE(rc))
582 return rc;
583 }
584
585 /*
586 * Process the event.
587 */
588 pDbgc->pszScratch = &pDbgc->achInput[0];
589 pDbgc->iArg = 0;
590 bool fPrintPrompt = true;
591 int rc = VINF_SUCCESS;
592 switch (pEvent->enmType)
593 {
594 /*
595 * The first part is events we have initiated with commands.
596 */
597 case DBGFEVENT_HALT_DONE:
598 {
599 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",
600 pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));
601 pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */
602 if (RT_SUCCESS(rc))
603 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
604 break;
605 }
606
607
608 /*
609 * The second part is events which can occur at any time.
610 */
611 case DBGFEVENT_FATAL_ERROR:
612 {
613 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
614 dbgcGetEventCtx(pEvent->enmCtx));
615 pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */
616 if (RT_SUCCESS(rc))
617 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
618 break;
619 }
620
621 case DBGFEVENT_BREAKPOINT:
622 case DBGFEVENT_BREAKPOINT_HYPER:
623 {
624 bool fRegCtxGuest = pDbgc->fRegCtxGuest;
625 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;
626
627 rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
628 switch (rc)
629 {
630 case VERR_DBGC_BP_NOT_FOUND:
631 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
632 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
633 break;
634
635 case VINF_DBGC_BP_NO_COMMAND:
636 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
637 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
638 break;
639
640 case VINF_BUFFER_OVERFLOW:
641 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
642 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
643 break;
644
645 default:
646 break;
647 }
648 if (RT_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))
649 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
650 else
651 pDbgc->fRegCtxGuest = fRegCtxGuest;
652 break;
653 }
654
655 case DBGFEVENT_STEPPED:
656 case DBGFEVENT_STEPPED_HYPER:
657 {
658 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;
659
660 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));
661 if (RT_SUCCESS(rc))
662 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
663 break;
664 }
665
666 case DBGFEVENT_ASSERTION_HYPER:
667 {
668 pDbgc->fRegCtxGuest = false;
669
670 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
671 "\ndbgf event: Hypervisor Assertion! (%s)\n"
672 "%s"
673 "%s"
674 "\n",
675 dbgcGetEventCtx(pEvent->enmCtx),
676 pEvent->u.Assert.pszMsg1,
677 pEvent->u.Assert.pszMsg2);
678 if (RT_SUCCESS(rc))
679 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
680 break;
681 }
682
683 case DBGFEVENT_DEV_STOP:
684 {
685 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
686 "\n"
687 "dbgf event: DBGFSTOP (%s)\n"
688 "File: %s\n"
689 "Line: %d\n"
690 "Function: %s\n",
691 dbgcGetEventCtx(pEvent->enmCtx),
692 pEvent->u.Src.pszFile,
693 pEvent->u.Src.uLine,
694 pEvent->u.Src.pszFunction);
695 if (RT_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)
696 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
697 "Message: %s\n",
698 pEvent->u.Src.pszMessage);
699 if (RT_SUCCESS(rc))
700 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
701 break;
702 }
703
704
705 case DBGFEVENT_INVALID_COMMAND:
706 {
707 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");
708 break;
709 }
710
711 case DBGFEVENT_TERMINATING:
712 {
713 pDbgc->fReady = false;
714 pDbgc->pBack->pfnSetReady(pDbgc->pBack, false);
715 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");
716 fPrintPrompt = false;
717 rc = VERR_GENERAL_FAILURE;
718 break;
719 }
720
721
722 default:
723 {
724 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
725 break;
726 }
727 }
728
729 /*
730 * Prompt, anyone?
731 */
732 if (fPrintPrompt && RT_SUCCESS(rc))
733 {
734 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
735 pDbgc->fReady = true;
736 if (RT_SUCCESS(rc))
737 pDbgc->pBack->pfnSetReady(pDbgc->pBack, true);
738 }
739
740 return rc;
741}
742
743
744/**
745 * Prints any log lines from the log buffer.
746 *
747 * The caller must not call function this unless pDbgc->fLog is set.
748 *
749 * @returns VBox status. (output related)
750 * @param pDbgc Debugger console instance data.
751 */
752static int dbgcProcessLog(PDBGC pDbgc)
753{
754 /** @todo */
755 NOREF(pDbgc);
756 return 0;
757}
758
759
760/**
761 * Run the debugger console.
762 *
763 * @returns VBox status.
764 * @param pDbgc Pointer to the debugger console instance data.
765 */
766int dbgcRun(PDBGC pDbgc)
767{
768 /*
769 * We're ready for commands now.
770 */
771 pDbgc->fReady = true;
772 pDbgc->pBack->pfnSetReady(pDbgc->pBack, true);
773
774 /*
775 * Main Debugger Loop.
776 *
777 * This loop will either block on waiting for input or on waiting on
778 * debug events. If we're forwarding the log we cannot wait for long
779 * before we must flush the log.
780 */
781 int rc = VINF_SUCCESS;
782 for (;;)
783 {
784 if ( pDbgc->pVM
785 && DBGFR3CanWait(pDbgc->pVM))
786 {
787 /*
788 * Wait for a debug event.
789 */
790 PCDBGFEVENT pEvent;
791 rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);
792 if (RT_SUCCESS(rc))
793 {
794 rc = dbgcProcessEvent(pDbgc, pEvent);
795 if (RT_FAILURE(rc))
796 break;
797 }
798 else if (rc != VERR_TIMEOUT)
799 break;
800
801 /*
802 * Check for input.
803 */
804 if (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
805 {
806 rc = dbgcProcessInput(pDbgc, false /* fNoExecute */);
807 if (RT_FAILURE(rc))
808 break;
809 }
810 }
811 else
812 {
813 /*
814 * Wait for input. If Logging is enabled we'll only wait very briefly.
815 */
816 if (pDbgc->pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))
817 {
818 rc = dbgcProcessInput(pDbgc, false /* fNoExecute */);
819 if (RT_FAILURE(rc))
820 break;
821 }
822 }
823
824 /*
825 * Forward log output.
826 */
827 if (pDbgc->fLog)
828 {
829 rc = dbgcProcessLog(pDbgc);
830 if (RT_FAILURE(rc))
831 break;
832 }
833 }
834
835 return rc;
836}
837
838
839/**
840 * Creates a a new instance.
841 *
842 * @returns VBox status code.
843 * @param ppDbgc Where to store the pointer to the instance data.
844 * @param pBack Pointer to the backend.
845 * @param fFlags The flags.
846 */
847int dbgcCreate(PDBGC *ppDbgc, PDBGCBACK pBack, unsigned fFlags)
848{
849 /*
850 * Validate input.
851 */
852 AssertPtrReturn(pBack, VERR_INVALID_POINTER);
853 AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);
854
855 /*
856 * Allocate and initialize.
857 */
858 PDBGC pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));
859 if (!pDbgc)
860 return VERR_NO_MEMORY;
861
862 dbgcInitCmdHlp(pDbgc);
863 pDbgc->pBack = pBack;
864 pDbgc->pVM = NULL;
865 pDbgc->idCpu = 0;
866 pDbgc->hDbgAs = DBGF_AS_GLOBAL;
867 pDbgc->pszEmulation = "CodeView/WinDbg";
868 pDbgc->paEmulationCmds = &g_aCmdsCodeView[0];
869 pDbgc->cEmulationCmds = g_cCmdsCodeView;
870 //pDbgc->fLog = false;
871 pDbgc->fRegCtxGuest = true;
872 pDbgc->fRegTerse = true;
873 //pDbgc->cPagingHierarchyDumps = 0;
874 //pDbgc->DisasmPos = {0};
875 //pDbgc->SourcePos = {0};
876 //pDbgc->DumpPos = {0};
877 pDbgc->pLastPos = &pDbgc->DisasmPos;
878 //pDbgc->cbDumpElement = 0;
879 //pDbgc->cVars = 0;
880 //pDbgc->paVars = NULL;
881 //pDbgc->pPlugInHead = NULL;
882 //pDbgc->pFirstBp = NULL;
883 //pDbgc->abSearch = {0};
884 //pDbgc->cbSearch = 0;
885 pDbgc->cbSearchUnit = 1;
886 pDbgc->cMaxSearchHits = 1;
887 //pDbgc->SearchAddr = {0};
888 //pDbgc->cbSearchRange = 0;
889
890 //pDbgc->uInputZero = 0;
891 //pDbgc->iRead = 0;
892 //pDbgc->iWrite = 0;
893 //pDbgc->cInputLines = 0;
894 //pDbgc->fInputOverflow = false;
895 pDbgc->fReady = true;
896 pDbgc->pszScratch = &pDbgc->achScratch[0];
897 //pDbgc->iArg = 0;
898 //pDbgc->rcOutput = 0;
899 //pDbgc->rcCmd = 0;
900
901 dbgcEvalInit();
902
903 *ppDbgc = pDbgc;
904 return VINF_SUCCESS;
905}
906
907/**
908 * Destroys a DBGC instance created by dbgcCreate.
909 *
910 * @param pDbgc Pointer to the debugger console instance data.
911 */
912void dbgcDestroy(PDBGC pDbgc)
913{
914 AssertPtr(pDbgc);
915
916 /* Disable log hook. */
917 if (pDbgc->fLog)
918 {
919
920 }
921
922 /* Unload all plug-ins. */
923 dbgcPlugInUnloadAll(pDbgc);
924
925 /* Detach from the VM. */
926 if (pDbgc->pVM)
927 DBGFR3Detach(pDbgc->pVM);
928
929 /* finally, free the instance memory. */
930 RTMemFree(pDbgc);
931}
932
933
934/**
935 * Make a console instance.
936 *
937 * This will not return until either an 'exit' command is issued or a error code
938 * indicating connection loss is encountered.
939 *
940 * @returns VINF_SUCCESS if console termination caused by the 'exit' command.
941 * @returns The VBox status code causing the console termination.
942 *
943 * @param pVM VM Handle.
944 * @param pBack Pointer to the backend structure. This must contain
945 * a full set of function pointers to service the console.
946 * @param fFlags Reserved, must be zero.
947 * @remark A forced termination of the console is easiest done by forcing the
948 * callbacks to return fatal failures.
949 */
950DBGDECL(int) DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)
951{
952 /*
953 * Validate input.
954 */
955 AssertPtrNullReturn(pVM, VERR_INVALID_POINTER);
956
957 /*
958 * Allocate and initialize instance data
959 */
960 PDBGC pDbgc;
961 int rc = dbgcCreate(&pDbgc, pBack, fFlags);
962 if (RT_FAILURE(rc))
963 return rc;
964
965 /*
966 * Print welcome message.
967 */
968 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
969 "Welcome to the VirtualBox Debugger!\n");
970
971 /*
972 * Attach to the specified VM.
973 */
974 if (RT_SUCCESS(rc) && pVM)
975 {
976 rc = DBGFR3Attach(pVM);
977 if (RT_SUCCESS(rc))
978 {
979 pDbgc->pVM = pVM;
980 pDbgc->idCpu = 0;
981 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
982 "Current VM is %08x, CPU #%u\n" /** @todo get and print the VM name! */
983 , pDbgc->pVM, pDbgc->idCpu);
984 }
985 else
986 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);
987 }
988
989 /*
990 * Load plugins.
991 */
992 if (RT_SUCCESS(rc))
993 {
994 if (pVM)
995 dbgcPlugInAutoLoad(pDbgc);
996 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
997 }
998 else
999 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nDBGCCreate error: %Rrc\n", rc);
1000
1001 /*
1002 * Run the debugger main loop.
1003 */
1004 if (RT_SUCCESS(rc))
1005 rc = dbgcRun(pDbgc);
1006
1007 /*
1008 * Cleanup console debugger session.
1009 */
1010 dbgcDestroy(pDbgc);
1011 return rc == VERR_DBGC_QUIT ? VINF_SUCCESS : rc;
1012}
1013
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