VirtualBox

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

Last change on this file since 59036 was 58909, checked in by vboxsync, 9 years ago

DBGF: More groundwork for port I/O, MMIO, interrupt and generic event breakpoints.

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