VirtualBox

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

Last change on this file since 69564 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use