VirtualBox

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

Last change on this file since 46074 was 46074, checked in by vboxsync, 12 years ago

RTDbgCfg: Added API for setting the log callback.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.3 KB
Line 
1/* $Id: DBGConsole.cpp 46074 2013-05-14 16:25:57Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console.
4 */
5
6/*
7 * Copyright (C) 2006-2013 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/vmm/vmapi.h> /* VMR3GetVM() */
165#include <VBox/err.h>
166#include <VBox/log.h>
167
168#include <iprt/asm.h>
169#include <iprt/assert.h>
170#include <iprt/mem.h>
171#include <iprt/string.h>
172
173#include "DBGCInternal.h"
174#include "DBGPlugIns.h"
175
176
177/*******************************************************************************
178* Internal Functions *
179*******************************************************************************/
180static int dbgcProcessLog(PDBGC pDbgc);
181
182
183/**
184 * Resolves a symbol (or tries to do so at least).
185 *
186 * @returns 0 on success.
187 * @returns VBox status on failure.
188 * @param pDbgc The debug console instance.
189 * @param pszSymbol The symbol name.
190 * @param enmType The result type. Specifying DBGCVAR_TYPE_GC_FAR may
191 * cause failure, avoid it.
192 * @param pResult Where to store the result.
193 */
194int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)
195{
196 int rc;
197
198 /*
199 * Builtin?
200 */
201 PCDBGCSYM pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol);
202 if (pSymDesc)
203 {
204 if (!pSymDesc->pfnGet)
205 return VERR_DBGC_PARSE_WRITEONLY_SYMBOL;
206 return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult);
207 }
208
209 /*
210 * A typical register? (Guest only)
211 */
212 static const char s_szSixLetterRegisters[] =
213 "rflags;eflags;"
214 ;
215 static const char s_szThreeLetterRegisters[] =
216 "eax;rax;" "r10;" "r8d;r8w;r8b;" "cr0;" "dr0;"
217 "ebx;rbx;" "r11;" "r9d;r9w;r8b;" "dr1;"
218 "ecx;rcx;" "r12;" "cr2;" "dr2;"
219 "edx;rdx;" "r13;" "cr3;" "dr3;"
220 "edi;rdi;dil;" "r14;" "cr4;" "dr4;"
221 "esi;rsi;sil;" "r15;" "cr8;"
222 "ebp;rbp;"
223 "esp;rsp;" "dr6;"
224 "rip;eip;" "dr7;"
225 "efl;"
226 ;
227 static const char s_szTwoLetterRegisters[] =
228 "ax;al;ah;" "r8;"
229 "bx;bl;bh;" "r9;"
230 "cx;cl;ch;" "cs;"
231 "dx;dl;dh;" "ds;"
232 "di;" "es;"
233 "si;" "fs;"
234 "bp;" "gs;"
235 "sp;" "ss;"
236 "ip;"
237 ;
238 size_t const cchSymbol = strlen(pszSymbol);
239 if ( (cchSymbol == 2 && strstr(s_szTwoLetterRegisters, pszSymbol))
240 || (cchSymbol == 3 && strstr(s_szThreeLetterRegisters, pszSymbol))
241 || (cchSymbol == 6 && strstr(s_szSixLetterRegisters, pszSymbol)))
242 {
243 if (!strchr(pszSymbol, ';'))
244 {
245 DBGCVAR Var;
246 DBGCVAR_INIT_SYMBOL(&Var, pszSymbol);
247 rc = dbgcOpRegister(pDbgc, &Var, DBGCVAR_CAT_ANY, pResult);
248 if (RT_SUCCESS(rc))
249 return DBGCCmdHlpConvert(&pDbgc->CmdHlp, pResult, enmType, false /*fConvSyms*/, pResult);
250 }
251 }
252
253 /*
254 * Ask PDM.
255 */
256 /** @todo resolve symbols using PDM. */
257
258 /*
259 * Ask the debug info manager.
260 */
261 RTDBGSYMBOL Symbol;
262 rc = DBGFR3AsSymbolByName(pDbgc->pUVM, pDbgc->hDbgAs, pszSymbol, &Symbol, NULL);
263 if (RT_SUCCESS(rc))
264 {
265 /*
266 * Default return is a flat gc address.
267 */
268 DBGCVAR_INIT_GC_FLAT(pResult, Symbol.Value);
269 if (Symbol.cb)
270 DBGCVAR_SET_RANGE(pResult, DBGCVAR_RANGE_BYTES, Symbol.cb);
271
272 switch (enmType)
273 {
274 /* nothing to do. */
275 case DBGCVAR_TYPE_GC_FLAT:
276 case DBGCVAR_TYPE_ANY:
277 return VINF_SUCCESS;
278
279 /* impossible at the moment. */
280 case DBGCVAR_TYPE_GC_FAR:
281 return VERR_DBGC_PARSE_CONVERSION_FAILED;
282
283 /* simply make it numeric. */
284 case DBGCVAR_TYPE_NUMBER:
285 pResult->enmType = DBGCVAR_TYPE_NUMBER;
286 pResult->u.u64Number = Symbol.Value;
287 return VINF_SUCCESS;
288
289 /* cast it. */
290 case DBGCVAR_TYPE_GC_PHYS:
291 case DBGCVAR_TYPE_HC_FLAT:
292 case DBGCVAR_TYPE_HC_PHYS:
293 return DBGCCmdHlpConvert(&pDbgc->CmdHlp, pResult, enmType, false /*fConvSyms*/, pResult);
294
295 default:
296 AssertMsgFailed(("Internal error enmType=%d\n", enmType));
297 return VERR_INVALID_PARAMETER;
298 }
299 }
300
301 return VERR_DBGC_PARSE_NOT_IMPLEMENTED;
302}
303
304
305/**
306 * Process all commands currently in the buffer.
307 *
308 * @returns VBox status code. Any error indicates the termination of the console session.
309 * @param pDbgc Debugger console instance data.
310 * @param fNoExecute Indicates that no commands should actually be executed.
311 */
312static int dbgcProcessCommands(PDBGC pDbgc, bool fNoExecute)
313{
314 /** @todo Replace this with a sh/ksh/csh/rexx like toplevel language that
315 * allows doing function, loops, if, cases, and such. */
316 int rc = VINF_SUCCESS;
317 while (pDbgc->cInputLines)
318 {
319 /*
320 * Empty the log buffer if we're hooking the log.
321 */
322 if (pDbgc->fLog)
323 {
324 rc = dbgcProcessLog(pDbgc);
325 if (RT_FAILURE(rc))
326 break;
327 }
328
329 if (pDbgc->iRead == pDbgc->iWrite)
330 {
331 AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));
332 pDbgc->cInputLines = 0;
333 return 0;
334 }
335
336 /*
337 * Copy the command to the parse buffer.
338 */
339 char ch;
340 char *psz = &pDbgc->achInput[pDbgc->iRead];
341 char *pszTrg = &pDbgc->achScratch[0];
342 while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )
343 {
344 if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])
345 psz = &pDbgc->achInput[0];
346
347 if (psz == &pDbgc->achInput[pDbgc->iWrite])
348 {
349 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));
350 pDbgc->cInputLines = 0;
351 return 0;
352 }
353
354 pszTrg++;
355 }
356 *pszTrg = '\0';
357
358 /*
359 * Advance the buffer.
360 */
361 pDbgc->iRead = psz - &pDbgc->achInput[0];
362 if (ch == '\n')
363 pDbgc->cInputLines--;
364
365 /*
366 * Parse and execute this command.
367 */
368 pDbgc->pszScratch = pszTrg + 1;
369 pDbgc->iArg = 0;
370 rc = dbgcEvalCommand(pDbgc, &pDbgc->achScratch[0], pszTrg - &pDbgc->achScratch[0] - 1, fNoExecute);
371 if ( rc == VERR_DBGC_QUIT
372 || rc == VWRN_DBGC_CMD_PENDING)
373 break;
374 rc = VINF_SUCCESS; /* ignore other statuses */
375 }
376
377 return rc;
378}
379
380
381/**
382 * Handle input buffer overflow.
383 *
384 * Will read any available input looking for a '\n' to reset the buffer on.
385 *
386 * @returns VBox status.
387 * @param pDbgc Debugger console instance data.
388 */
389static int dbgcInputOverflow(PDBGC pDbgc)
390{
391 /*
392 * Assert overflow status and reset the input buffer.
393 */
394 if (!pDbgc->fInputOverflow)
395 {
396 pDbgc->fInputOverflow = true;
397 pDbgc->iRead = pDbgc->iWrite = 0;
398 pDbgc->cInputLines = 0;
399 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");
400 }
401
402 /*
403 * Eat input till no more or there is a '\n'.
404 * When finding a '\n' we'll continue normal processing.
405 */
406 while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
407 {
408 size_t cbRead;
409 int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);
410 if (RT_FAILURE(rc))
411 return rc;
412 char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);
413 if (psz)
414 {
415 pDbgc->fInputOverflow = false;
416 pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;
417 pDbgc->iWrite = (unsigned)cbRead;
418 pDbgc->cInputLines = 0;
419 break;
420 }
421 }
422
423 return 0;
424}
425
426
427/**
428 * Read input and do some preprocessing.
429 *
430 * @returns VBox status.
431 * In addition to the iWrite and achInput, cInputLines is maintained.
432 * In case of an input overflow the fInputOverflow flag will be set.
433 * @param pDbgc Debugger console instance data.
434 */
435static int dbgcInputRead(PDBGC pDbgc)
436{
437 /*
438 * We have ready input.
439 * Read it till we don't have any or we have a full input buffer.
440 */
441 int rc = 0;
442 do
443 {
444 /*
445 * More available buffer space?
446 */
447 size_t cbLeft;
448 if (pDbgc->iWrite > pDbgc->iRead)
449 cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);
450 else
451 cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;
452 if (!cbLeft)
453 {
454 /* overflow? */
455 if (!pDbgc->cInputLines)
456 rc = dbgcInputOverflow(pDbgc);
457 break;
458 }
459
460 /*
461 * Read one char and interpret it.
462 */
463 char achRead[128];
464 size_t cbRead;
465 rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);
466 if (RT_FAILURE(rc))
467 return rc;
468 char *psz = &achRead[0];
469 while (cbRead-- > 0)
470 {
471 char ch = *psz++;
472 switch (ch)
473 {
474 /*
475 * Ignore.
476 */
477 case '\0':
478 case '\r':
479 case '\a':
480 break;
481
482 /*
483 * Backspace.
484 */
485 case '\b':
486 Log2(("DBGC: backspace\n"));
487 if (pDbgc->iRead != pDbgc->iWrite)
488 {
489 unsigned iWriteUndo = pDbgc->iWrite;
490 if (pDbgc->iWrite)
491 pDbgc->iWrite--;
492 else
493 pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;
494
495 if (pDbgc->achInput[pDbgc->iWrite] == '\n')
496 pDbgc->iWrite = iWriteUndo;
497 }
498 break;
499
500 /*
501 * Add char to buffer.
502 */
503 case '\t':
504 case '\n':
505 case ';':
506 switch (ch)
507 {
508 case '\t': ch = ' '; break;
509 case '\n': pDbgc->cInputLines++; break;
510 }
511 default:
512 Log2(("DBGC: ch=%02x\n", (unsigned char)ch));
513 pDbgc->achInput[pDbgc->iWrite] = ch;
514 if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))
515 pDbgc->iWrite = 0;
516 break;
517 }
518 }
519
520 /* Terminate it to make it easier to read in the debugger. */
521 pDbgc->achInput[pDbgc->iWrite] = '\0';
522 } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));
523
524 return rc;
525}
526
527
528/**
529 * Reads input, parses it and executes commands on '\n'.
530 *
531 * @returns VBox status.
532 * @param pDbgc Debugger console instance data.
533 * @param fNoExecute Indicates that no commands should actually be executed.
534 */
535int dbgcProcessInput(PDBGC pDbgc, bool fNoExecute)
536{
537 /*
538 * We know there's input ready, so let's read it first.
539 */
540 int rc = dbgcInputRead(pDbgc);
541 if (RT_FAILURE(rc))
542 return rc;
543
544 /*
545 * Now execute any ready commands.
546 */
547 if (pDbgc->cInputLines)
548 {
549 pDbgc->pBack->pfnSetReady(pDbgc->pBack, false);
550 pDbgc->fReady = false;
551 rc = dbgcProcessCommands(pDbgc, fNoExecute);
552 if (RT_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)
553 pDbgc->fReady = true;
554
555 if ( RT_SUCCESS(rc)
556 && pDbgc->iRead == pDbgc->iWrite
557 && pDbgc->fReady)
558 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
559
560 if ( RT_SUCCESS(rc)
561 && pDbgc->fReady)
562 pDbgc->pBack->pfnSetReady(pDbgc->pBack, true);
563 }
564 else
565 /* Received nonsense; just skip it. */
566 pDbgc->iRead = pDbgc->iWrite;
567
568 return rc;
569}
570
571
572/**
573 * Gets the event context identifier string.
574 * @returns Read only string.
575 * @param enmCtx The context.
576 */
577static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)
578{
579 switch (enmCtx)
580 {
581 case DBGFEVENTCTX_RAW: return "raw";
582 case DBGFEVENTCTX_REM: return "rem";
583 case DBGFEVENTCTX_HM: return "hwaccl";
584 case DBGFEVENTCTX_HYPER: return "hyper";
585 case DBGFEVENTCTX_OTHER: return "other";
586
587 case DBGFEVENTCTX_INVALID: return "!Invalid Event Ctx!";
588 default:
589 AssertMsgFailed(("enmCtx=%d\n", enmCtx));
590 return "!Unknown Event Ctx!";
591 }
592}
593
594
595/**
596 * Processes debugger events.
597 *
598 * @returns VBox status.
599 * @param pDbgc DBGC Instance data.
600 * @param pEvent Pointer to event data.
601 */
602static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)
603{
604 /*
605 * Flush log first.
606 */
607 if (pDbgc->fLog)
608 {
609 int rc = dbgcProcessLog(pDbgc);
610 if (RT_FAILURE(rc))
611 return rc;
612 }
613
614 /*
615 * Process the event.
616 */
617 pDbgc->pszScratch = &pDbgc->achInput[0];
618 pDbgc->iArg = 0;
619 bool fPrintPrompt = true;
620 int rc = VINF_SUCCESS;
621 switch (pEvent->enmType)
622 {
623 /*
624 * The first part is events we have initiated with commands.
625 */
626 case DBGFEVENT_HALT_DONE:
627 {
628 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",
629 pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));
630 pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */
631 if (RT_SUCCESS(rc))
632 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
633 break;
634 }
635
636
637 /*
638 * The second part is events which can occur at any time.
639 */
640 case DBGFEVENT_FATAL_ERROR:
641 {
642 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
643 dbgcGetEventCtx(pEvent->enmCtx));
644 pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */
645 if (RT_SUCCESS(rc))
646 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
647 break;
648 }
649
650 case DBGFEVENT_BREAKPOINT:
651 case DBGFEVENT_BREAKPOINT_HYPER:
652 {
653 bool fRegCtxGuest = pDbgc->fRegCtxGuest;
654 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;
655
656 rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
657 switch (rc)
658 {
659 case VERR_DBGC_BP_NOT_FOUND:
660 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
661 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
662 break;
663
664 case VINF_DBGC_BP_NO_COMMAND:
665 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
666 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
667 break;
668
669 case VINF_BUFFER_OVERFLOW:
670 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
671 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
672 break;
673
674 default:
675 break;
676 }
677 if (RT_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pUVM))
678 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
679 else
680 pDbgc->fRegCtxGuest = fRegCtxGuest;
681 break;
682 }
683
684 case DBGFEVENT_STEPPED:
685 case DBGFEVENT_STEPPED_HYPER:
686 {
687 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;
688
689 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));
690 if (RT_SUCCESS(rc))
691 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
692 break;
693 }
694
695 case DBGFEVENT_ASSERTION_HYPER:
696 {
697 pDbgc->fRegCtxGuest = false;
698
699 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
700 "\ndbgf event: Hypervisor Assertion! (%s)\n"
701 "%s"
702 "%s"
703 "\n",
704 dbgcGetEventCtx(pEvent->enmCtx),
705 pEvent->u.Assert.pszMsg1,
706 pEvent->u.Assert.pszMsg2);
707 if (RT_SUCCESS(rc))
708 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
709 break;
710 }
711
712 case DBGFEVENT_DEV_STOP:
713 {
714 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
715 "\n"
716 "dbgf event: DBGFSTOP (%s)\n"
717 "File: %s\n"
718 "Line: %d\n"
719 "Function: %s\n",
720 dbgcGetEventCtx(pEvent->enmCtx),
721 pEvent->u.Src.pszFile,
722 pEvent->u.Src.uLine,
723 pEvent->u.Src.pszFunction);
724 if (RT_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)
725 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
726 "Message: %s\n",
727 pEvent->u.Src.pszMessage);
728 if (RT_SUCCESS(rc))
729 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
730 break;
731 }
732
733
734 case DBGFEVENT_INVALID_COMMAND:
735 {
736 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");
737 break;
738 }
739
740 case DBGFEVENT_POWERING_OFF:
741 {
742 pDbgc->fReady = false;
743 pDbgc->pBack->pfnSetReady(pDbgc->pBack, false);
744 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is powering off!\n");
745 fPrintPrompt = false;
746 rc = VERR_GENERAL_FAILURE;
747 break;
748 }
749
750
751 default:
752 {
753 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
754 break;
755 }
756 }
757
758 /*
759 * Prompt, anyone?
760 */
761 if (fPrintPrompt && RT_SUCCESS(rc))
762 {
763 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
764 pDbgc->fReady = true;
765 if (RT_SUCCESS(rc))
766 pDbgc->pBack->pfnSetReady(pDbgc->pBack, true);
767 }
768
769 return rc;
770}
771
772
773/**
774 * Prints any log lines from the log buffer.
775 *
776 * The caller must not call function this unless pDbgc->fLog is set.
777 *
778 * @returns VBox status. (output related)
779 * @param pDbgc Debugger console instance data.
780 */
781static int dbgcProcessLog(PDBGC pDbgc)
782{
783 /** @todo */
784 NOREF(pDbgc);
785 return 0;
786}
787
788/** @callback_method_impl{FNRTDBGCFGLOG} */
789static DECLCALLBACK(void) dbgcDbgCfgLogCallback(RTDBGCFG hDbgCfg, uint32_t iLevel, const char *pszMsg, void *pvUser)
790{
791 /** @todo Add symbol noise setting. */
792 NOREF(hDbgCfg); NOREF(iLevel);
793 PDBGC pDbgc = (PDBGC)pvUser;
794 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%s", pszMsg);
795}
796
797
798/**
799 * Run the debugger console.
800 *
801 * @returns VBox status.
802 * @param pDbgc Pointer to the debugger console instance data.
803 */
804int dbgcRun(PDBGC pDbgc)
805{
806 /*
807 * We're ready for commands now.
808 */
809 pDbgc->fReady = true;
810 pDbgc->pBack->pfnSetReady(pDbgc->pBack, true);
811
812 /*
813 * Main Debugger Loop.
814 *
815 * This loop will either block on waiting for input or on waiting on
816 * debug events. If we're forwarding the log we cannot wait for long
817 * before we must flush the log.
818 */
819 int rc;
820 for (;;)
821 {
822 rc = VERR_SEM_OUT_OF_TURN;
823 if (pDbgc->pUVM)
824 rc = DBGFR3QueryWaitable(pDbgc->pUVM);
825
826 if (RT_SUCCESS(rc))
827 {
828 /*
829 * Wait for a debug event.
830 */
831 PCDBGFEVENT pEvent;
832 rc = DBGFR3EventWait(pDbgc->pUVM, pDbgc->fLog ? 1 : 32, &pEvent);
833 if (RT_SUCCESS(rc))
834 {
835 rc = dbgcProcessEvent(pDbgc, pEvent);
836 if (RT_FAILURE(rc))
837 break;
838 }
839 else if (rc != VERR_TIMEOUT)
840 break;
841
842 /*
843 * Check for input.
844 */
845 if (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
846 {
847 rc = dbgcProcessInput(pDbgc, false /* fNoExecute */);
848 if (RT_FAILURE(rc))
849 break;
850 }
851 }
852 else if (rc == VERR_SEM_OUT_OF_TURN)
853 {
854 /*
855 * Wait for input. If Logging is enabled we'll only wait very briefly.
856 */
857 if (pDbgc->pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))
858 {
859 rc = dbgcProcessInput(pDbgc, false /* fNoExecute */);
860 if (RT_FAILURE(rc))
861 break;
862 }
863 }
864 else
865 break;
866
867 /*
868 * Forward log output.
869 */
870 if (pDbgc->fLog)
871 {
872 rc = dbgcProcessLog(pDbgc);
873 if (RT_FAILURE(rc))
874 break;
875 }
876 }
877
878 return rc;
879}
880
881
882/**
883 * Creates a a new instance.
884 *
885 * @returns VBox status code.
886 * @param ppDbgc Where to store the pointer to the instance data.
887 * @param pBack Pointer to the backend.
888 * @param fFlags The flags.
889 */
890int dbgcCreate(PDBGC *ppDbgc, PDBGCBACK pBack, unsigned fFlags)
891{
892 /*
893 * Validate input.
894 */
895 AssertPtrReturn(pBack, VERR_INVALID_POINTER);
896 AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);
897
898 /*
899 * Allocate and initialize.
900 */
901 PDBGC pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));
902 if (!pDbgc)
903 return VERR_NO_MEMORY;
904
905 dbgcInitCmdHlp(pDbgc);
906 pDbgc->pBack = pBack;
907 pDbgc->pVM = NULL;
908 pDbgc->pUVM = NULL;
909 pDbgc->idCpu = 0;
910 pDbgc->hDbgAs = DBGF_AS_GLOBAL;
911 pDbgc->pszEmulation = "CodeView/WinDbg";
912 pDbgc->paEmulationCmds = &g_aCmdsCodeView[0];
913 pDbgc->cEmulationCmds = g_cCmdsCodeView;
914 pDbgc->paEmulationFuncs = &g_aFuncsCodeView[0];
915 pDbgc->cEmulationFuncs = g_cFuncsCodeView;
916 //pDbgc->fLog = false;
917 pDbgc->fRegCtxGuest = true;
918 pDbgc->fRegTerse = true;
919 //pDbgc->cPagingHierarchyDumps = 0;
920 //pDbgc->DisasmPos = {0};
921 //pDbgc->SourcePos = {0};
922 //pDbgc->DumpPos = {0};
923 pDbgc->pLastPos = &pDbgc->DisasmPos;
924 //pDbgc->cbDumpElement = 0;
925 //pDbgc->cVars = 0;
926 //pDbgc->paVars = NULL;
927 //pDbgc->pPlugInHead = NULL;
928 //pDbgc->pFirstBp = NULL;
929 //pDbgc->abSearch = {0};
930 //pDbgc->cbSearch = 0;
931 pDbgc->cbSearchUnit = 1;
932 pDbgc->cMaxSearchHits = 1;
933 //pDbgc->SearchAddr = {0};
934 //pDbgc->cbSearchRange = 0;
935
936 //pDbgc->uInputZero = 0;
937 //pDbgc->iRead = 0;
938 //pDbgc->iWrite = 0;
939 //pDbgc->cInputLines = 0;
940 //pDbgc->fInputOverflow = false;
941 pDbgc->fReady = true;
942 pDbgc->pszScratch = &pDbgc->achScratch[0];
943 //pDbgc->iArg = 0;
944 //pDbgc->rcOutput = 0;
945 //pDbgc->rcCmd = 0;
946
947 dbgcEvalInit();
948
949 *ppDbgc = pDbgc;
950 return VINF_SUCCESS;
951}
952
953/**
954 * Destroys a DBGC instance created by dbgcCreate.
955 *
956 * @param pDbgc Pointer to the debugger console instance data.
957 */
958void dbgcDestroy(PDBGC pDbgc)
959{
960 AssertPtr(pDbgc);
961
962 /* Disable log hook. */
963 if (pDbgc->fLog)
964 {
965
966 }
967
968 /* Unload all plug-ins. */
969 dbgcPlugInUnloadAll(pDbgc);
970
971 /* Detach from the VM. */
972 if (pDbgc->pUVM)
973 DBGFR3Detach(pDbgc->pUVM);
974
975 /* finally, free the instance memory. */
976 RTMemFree(pDbgc);
977}
978
979
980/**
981 * Make a console instance.
982 *
983 * This will not return until either an 'exit' command is issued or a error code
984 * indicating connection loss is encountered.
985 *
986 * @returns VINF_SUCCESS if console termination caused by the 'exit' command.
987 * @returns The VBox status code causing the console termination.
988 *
989 * @param pUVM The user mode VM handle.
990 * @param pBack Pointer to the backend structure. This must contain
991 * a full set of function pointers to service the console.
992 * @param fFlags Reserved, must be zero.
993 * @remark A forced termination of the console is easiest done by forcing the
994 * callbacks to return fatal failures.
995 */
996DBGDECL(int) DBGCCreate(PUVM pUVM, PDBGCBACK pBack, unsigned fFlags)
997{
998 /*
999 * Validate input.
1000 */
1001 AssertPtrNullReturn(pUVM, VERR_INVALID_VM_HANDLE);
1002 PVM pVM = NULL;
1003 if (pUVM)
1004 {
1005 pVM = VMR3GetVM(pUVM);
1006 AssertPtrReturn(pVM, VERR_INVALID_VM_HANDLE);
1007 }
1008
1009 /*
1010 * Allocate and initialize instance data
1011 */
1012 PDBGC pDbgc;
1013 int rc = dbgcCreate(&pDbgc, pBack, fFlags);
1014 if (RT_FAILURE(rc))
1015 return rc;
1016
1017 /*
1018 * Print welcome message.
1019 */
1020 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1021 "Welcome to the VirtualBox Debugger!\n");
1022
1023 /*
1024 * Attach to the specified VM.
1025 */
1026 if (RT_SUCCESS(rc) && pUVM)
1027 {
1028 rc = DBGFR3Attach(pUVM);
1029 if (RT_SUCCESS(rc))
1030 {
1031 pDbgc->pVM = pVM;
1032 pDbgc->pUVM = pUVM;
1033 pDbgc->idCpu = 0;
1034 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1035 "Current VM is %08x, CPU #%u\n" /** @todo get and print the VM name! */
1036 , pDbgc->pVM, pDbgc->idCpu);
1037 }
1038 else
1039 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);
1040 }
1041
1042 /*
1043 * Load plugins.
1044 */
1045 if (RT_SUCCESS(rc))
1046 {
1047 if (pVM)
1048 dbgcPlugInAutoLoad(pDbgc);
1049 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
1050 if (RT_SUCCESS(rc))
1051 {
1052
1053 /*
1054 * Set debug config log callback.
1055 */
1056 RTDBGCFG hDbgCfg = DBGFR3AsGetConfig(pUVM);
1057 if ( hDbgCfg != NIL_RTDBGCFG
1058 && RTDbgCfgRetain(hDbgCfg) != UINT32_MAX)
1059 {
1060 int rc2 = RTDbgCfgSetLogCallback(hDbgCfg, dbgcDbgCfgLogCallback, pDbgc);
1061 if (RT_FAILURE(rc2))
1062 {
1063 hDbgCfg = NIL_RTDBGCFG;
1064 RTDbgCfgRelease(hDbgCfg);
1065 }
1066 }
1067 else
1068 hDbgCfg = NIL_RTDBGCFG;
1069
1070
1071 /*
1072 * Run the debugger main loop.
1073 */
1074 rc = dbgcRun(pDbgc);
1075
1076
1077 /*
1078 * Remove debug config log callback.
1079 */
1080 if (hDbgCfg != NIL_RTDBGCFG)
1081 {
1082 RTDbgCfgSetLogCallback(hDbgCfg, NULL, NULL);
1083 RTDbgCfgRelease(hDbgCfg);
1084 }
1085 }
1086
1087 }
1088 else
1089 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nDBGCCreate error: %Rrc\n", rc);
1090
1091
1092 /*
1093 * Cleanup console debugger session.
1094 */
1095 dbgcDestroy(pDbgc);
1096 return rc == VERR_DBGC_QUIT ? VINF_SUCCESS : rc;
1097}
1098
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