VirtualBox

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

Last change on this file since 41943 was 41573, checked in by vboxsync, 13 years ago

DBGC: Working on making STRING the inflexible type and SYMBOL the flexible one.

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