VirtualBox

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

Last change on this file since 5676 was 5676, checked in by vboxsync, 17 years ago

Split out the DBGCCMDHLP stuff.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 69.5 KB
Line 
1/** $Id: DBGConsole.cpp 5676 2007-11-11 05:50:06Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * 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 a first attempt to make some interactive
22 * debugging facilities for the VirtualBox backend (i.e. the VM). At a later
23 * stage we'll make a fancy gui around this, but for the present a telnet (or
24 * serial terminal) will have to suffice.
25 *
26 * The debugger is only built into the VM with debug builds or when
27 * VBOX_WITH_DEBUGGER is defined. There might be need for \#ifdef'ing on this
28 * define to enable special debugger hooks, but the general approach is to
29 * make generic interfaces. The individual components also can register
30 * external commands, and such code must be within \#ifdef.
31 *
32 *
33 * @section sec_dbgc_op Operation (intentions)
34 *
35 * The console will process commands in a manner similar to the OS/2 and
36 * windows kernel debuggers. This means ';' is a command separator and
37 * that when possible we'll use the same command names as these two uses.
38 *
39 *
40 * @subsection sec_dbg_op_numbers Numbers
41 *
42 * Numbers are hexadecimal unless specified with a prefix indicating
43 * elsewise. Prefixes:
44 * - '0x' - hexadecimal.
45 * - '0i' - decimal
46 * - '0t' - octal.
47 * - '0y' - binary.
48 *
49 *
50 * @subsection sec_dbg_op_address Addressing modes
51 *
52 * - Default is flat. For compatability '%' also means flat.
53 * - Segmented addresses are specified selector:offset.
54 * - Physical addresses are specified using '%%'.
55 * - The default target for the addressing is the guest context, the '#'
56 * will override this and set it to the host.
57 *
58 *
59 * @subsection sec_dbg_op_evalution Evaluation
60 *
61 * As time permits support will be implemented support for a subset of the C
62 * binary operators, starting with '+', '-', '*' and '/'. Support for variables
63 * are provided thru commands 'set' and 'unset' and the unary operator '$'. The
64 * unary '@' operator will indicate function calls. The debugger needs a set of
65 * memory read functions, but we might later extend this to allow registration of
66 * external functions too.
67 *
68 * A special command '?' will then be added which evalutates a given expression
69 * and prints it in all the different formats.
70 *
71 *
72 * @subsection sec_dbg_op_registers Registers
73 *
74 * Registers are addressed using their name. Some registers which have several fields
75 * (like gdtr) will have separate names indicating the different fields. The default
76 * register set is the guest one. To access the hypervisor register one have to
77 * prefix the register names with '.'.
78 *
79 *
80 * @subsection sec_dbg_op_commands Commands
81 *
82 * The commands are all lowercase, case sensitive, and starting with a letter. We will
83 * later add some special commands ('?' for evaulation) and perhaps command classes ('.', '!')
84 *
85 *
86 * @section sec_dbg_tasks Tasks
87 *
88 * To implement DBGT and instrument VMM for basic state inspection and log
89 * viewing, the follwing task must be executed:
90 *
91 * -# Basic threading layer in RT.
92 * -# Basic tcpip server abstration in RT.
93 * -# Write DBGC.
94 * -# Write DBCTCP.
95 * -# Integrate with VMM and the rest.
96 * -# Start writing DBGF (VMM).
97 */
98
99
100
101
102/*******************************************************************************
103* Header Files *
104*******************************************************************************/
105#define LOG_GROUP LOG_GROUP_DBGC
106#include <VBox/dbg.h>
107#include <VBox/dbgf.h>
108#include <VBox/vm.h>
109#include <VBox/vmm.h>
110#include <VBox/mm.h>
111#include <VBox/pgm.h>
112#include <VBox/selm.h>
113#include <VBox/dis.h>
114#include <VBox/param.h>
115#include <VBox/err.h>
116#include <VBox/log.h>
117
118#include <iprt/alloc.h>
119#include <iprt/alloca.h>
120#include <iprt/string.h>
121#include <iprt/assert.h>
122#include <iprt/ctype.h>
123
124#include <stdlib.h>
125#include <stdio.h>
126
127#include "DBGCInternal.h"
128
129
130/*******************************************************************************
131* Global Variables *
132*******************************************************************************/
133/** Bitmap where set bits indicates the characters the may start an operator name. */
134static uint32_t g_bmOperatorChars[256 / (4*8)];
135
136
137
138
139
140
141
142//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
143//
144//
145// V a r i a b l e M a n i p u l a t i o n
146//
147//
148//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
149
150
151
152/** @todo move me!*/
153void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat)
154{
155 if (pVar)
156 {
157 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
158 pVar->u.GCFlat = GCFlat;
159 pVar->enmRangeType = DBGCVAR_RANGE_NONE;
160 pVar->u64Range = 0;
161 }
162}
163
164
165/** @todo move me!*/
166void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb)
167{
168 if (pVar)
169 {
170 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
171 pVar->u.GCFlat = GCFlat;
172 pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
173 pVar->u64Range = cb;
174 }
175}
176
177
178/** @todo move me!*/
179void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2)
180{
181 if (pVar)
182 {
183 if (pVar2)
184 *pVar = *pVar2;
185 else
186 {
187 pVar->enmType = DBGCVAR_TYPE_UNKNOWN;
188 memset(&pVar->u, 0, sizeof(pVar->u));
189 pVar->enmRangeType = DBGCVAR_RANGE_NONE;
190 pVar->u64Range = 0;
191 }
192 }
193}
194
195
196/** @todo move me!*/
197void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb)
198{
199 if (pVar)
200 {
201 pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
202 pVar->u64Range = cb;
203 }
204}
205
206
207/** @todo move me!*/
208void dbgcVarSetNoRange(PDBGCVAR pVar)
209{
210 if (pVar)
211 {
212 pVar->enmRangeType = DBGCVAR_RANGE_NONE;
213 pVar->u64Range = 0;
214 }
215}
216
217
218/**
219 * Converts a DBGC variable to a DBGF address.
220 *
221 * @returns VBox status code.
222 * @param pDbgc The DBGC instance.
223 * @param pVar The variable.
224 * @param pAddress Where to store the address.
225 */
226int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
227{
228 AssertReturn(pVar, VERR_INVALID_PARAMETER);
229 switch (pVar->enmType)
230 {
231 case DBGCVAR_TYPE_GC_FLAT:
232 DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, pVar->u.GCFlat);
233 return VINF_SUCCESS;
234
235 case DBGCVAR_TYPE_NUMBER:
236 DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, (RTGCUINTPTR)pVar->u.u64Number);
237 return VINF_SUCCESS;
238
239 case DBGCVAR_TYPE_GC_FAR:
240 return DBGFR3AddrFromSelOff(pDbgc->pVM, pAddress, pVar->u.GCFar.sel, pVar->u.GCFar.sel);
241
242 case DBGCVAR_TYPE_STRING:
243 case DBGCVAR_TYPE_SYMBOL:
244 {
245 DBGCVAR Var;
246 int rc = pDbgc->CmdHlp.pfnEval(&pDbgc->CmdHlp, &Var, "%%(%DV)", pVar);
247 if (VBOX_FAILURE(rc))
248 return rc;
249 return dbgcVarToDbgfAddr(pDbgc, &Var, pAddress);
250 }
251
252 case DBGCVAR_TYPE_GC_PHYS:
253 case DBGCVAR_TYPE_HC_FLAT:
254 case DBGCVAR_TYPE_HC_FAR:
255 case DBGCVAR_TYPE_HC_PHYS:
256 default:
257 return VERR_PARSE_CONVERSION_FAILED;
258 }
259}
260
261
262
263//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
264//
265//
266// B r e a k p o i n t M a n a g e m e n t
267//
268//
269//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
270
271
272/**
273 * Adds a breakpoint to the DBGC breakpoint list.
274 */
275int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
276{
277 /*
278 * Check if it already exists.
279 */
280 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
281 if (pBp)
282 return VERR_DBGC_BP_EXISTS;
283
284 /*
285 * Add the breakpoint.
286 */
287 if (pszCmd)
288 pszCmd = RTStrStripL(pszCmd);
289 size_t cchCmd = pszCmd ? strlen(pszCmd) : 0;
290 pBp = (PDBGCBP)RTMemAlloc(RT_OFFSETOF(DBGCBP, szCmd[cchCmd + 1]));
291 if (!pBp)
292 return VERR_NO_MEMORY;
293 if (cchCmd)
294 memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
295 else
296 pBp->szCmd[0] = '\0';
297 pBp->cchCmd = cchCmd;
298 pBp->iBp = iBp;
299 pBp->pNext = pDbgc->pFirstBp;
300 pDbgc->pFirstBp = pBp;
301
302 return VINF_SUCCESS;
303}
304
305/**
306 * Updates the a breakpoint.
307 *
308 * @returns VBox status code.
309 * @param pDbgc The DBGC instance.
310 * @param iBp The breakpoint to update.
311 * @param pszCmd The new command.
312 */
313int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
314{
315 /*
316 * Find the breakpoint.
317 */
318 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
319 if (!pBp)
320 return VERR_DBGC_BP_NOT_FOUND;
321
322 /*
323 * Do we need to reallocate?
324 */
325 if (pszCmd)
326 pszCmd = RTStrStripL(pszCmd);
327 if (!pszCmd || !*pszCmd)
328 pBp->szCmd[0] = '\0';
329 else
330 {
331 size_t cchCmd = strlen(pszCmd);
332 if (strlen(pBp->szCmd) >= cchCmd)
333 {
334 memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
335 pBp->cchCmd = cchCmd;
336 }
337 else
338 {
339 /*
340 * Yes, let's do it the simple way...
341 */
342 int rc = dbgcBpDelete(pDbgc, iBp);
343 AssertRC(rc);
344 return dbgcBpAdd(pDbgc, iBp, pszCmd);
345 }
346 }
347 return VINF_SUCCESS;
348}
349
350
351/**
352 * Deletes a breakpoint.
353 *
354 * @returns VBox status code.
355 * @param pDbgc The DBGC instance.
356 * @param iBp The breakpoint to delete.
357 */
358int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp)
359{
360 /*
361 * Search thru the list, when found unlink and free it.
362 */
363 PDBGCBP pBpPrev = NULL;
364 PDBGCBP pBp = pDbgc->pFirstBp;
365 for (; pBp; pBp = pBp->pNext)
366 {
367 if (pBp->iBp == iBp)
368 {
369 if (pBpPrev)
370 pBpPrev->pNext = pBp->pNext;
371 else
372 pDbgc->pFirstBp = pBp->pNext;
373 RTMemFree(pBp);
374 return VINF_SUCCESS;
375 }
376 pBpPrev = pBp;
377 }
378
379 return VERR_DBGC_BP_NOT_FOUND;
380}
381
382
383/**
384 * Get a breakpoint.
385 *
386 * @returns Pointer to the breakpoint.
387 * @returns NULL if the breakpoint wasn't found.
388 * @param pDbgc The DBGC instance.
389 * @param iBp The breakpoint to get.
390 */
391PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp)
392{
393 /*
394 * Enumerate the list.
395 */
396 PDBGCBP pBp = pDbgc->pFirstBp;
397 for (; pBp; pBp = pBp->pNext)
398 if (pBp->iBp == iBp)
399 return pBp;
400 return NULL;
401}
402
403
404/**
405 * Executes the command of a breakpoint.
406 *
407 * @returns VINF_DBGC_BP_NO_COMMAND if there is no command associated with the breakpoint.
408 * @returns VERR_DBGC_BP_NOT_FOUND if the breakpoint wasn't found.
409 * @returns VERR_BUFFER_OVERFLOW if the is not enough space in the scratch buffer for the command.
410 * @returns VBox status code from dbgcProcessCommand() other wise.
411 * @param pDbgc The DBGC instance.
412 * @param iBp The breakpoint to execute.
413 */
414int dbgcBpExec(PDBGC pDbgc, RTUINT iBp)
415{
416 /*
417 * Find the breakpoint.
418 */
419 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
420 if (!pBp)
421 return VERR_DBGC_BP_NOT_FOUND;
422
423 /*
424 * Anything to do?
425 */
426 if (!pBp->cchCmd)
427 return VINF_DBGC_BP_NO_COMMAND;
428
429 /*
430 * Execute the command.
431 * This means copying it to the scratch buffer and process it as if it
432 * were user input. We must save and restore the state of the scratch buffer.
433 */
434 /* Save the scratch state. */
435 char *pszScratch = pDbgc->pszScratch;
436 unsigned iArg = pDbgc->iArg;
437
438 /* Copy the command to the scratch buffer. */
439 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
440 if (pBp->cchCmd >= cbScratch)
441 return VERR_BUFFER_OVERFLOW;
442 memcpy(pDbgc->pszScratch, pBp->szCmd, pBp->cchCmd + 1);
443
444 /* Execute the command. */
445 pDbgc->pszScratch = pDbgc->pszScratch + pBp->cchCmd + 1;
446 int rc = dbgcProcessCommand(pDbgc, pszScratch, pBp->cchCmd);
447
448 /* Restore the scratch state. */
449 pDbgc->iArg = iArg;
450 pDbgc->pszScratch = pszScratch;
451
452 return rc;
453}
454
455
456
457
458
459//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
460//
461//
462// I n p u t , p a r s i n g a n d l o g g i n g
463//
464//
465//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
466
467
468
469/**
470 * Prints any log lines from the log buffer.
471 *
472 * The caller must not call function this unless pDbgc->fLog is set.
473 *
474 * @returns VBox status. (output related)
475 * @param pDbgc Debugger console instance data.
476 */
477static int dbgcProcessLog(PDBGC pDbgc)
478{
479 /** @todo */
480 NOREF(pDbgc);
481 return 0;
482}
483
484
485
486/**
487 * Handle input buffer overflow.
488 *
489 * Will read any available input looking for a '\n' to reset the buffer on.
490 *
491 * @returns VBox status.
492 * @param pDbgc Debugger console instance data.
493 */
494static int dbgcInputOverflow(PDBGC pDbgc)
495{
496 /*
497 * Assert overflow status and reset the input buffer.
498 */
499 if (!pDbgc->fInputOverflow)
500 {
501 pDbgc->fInputOverflow = true;
502 pDbgc->iRead = pDbgc->iWrite = 0;
503 pDbgc->cInputLines = 0;
504 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");
505 }
506
507 /*
508 * Eat input till no more or there is a '\n'.
509 * When finding a '\n' we'll continue normal processing.
510 */
511 while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
512 {
513 size_t cbRead;
514 int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);
515 if (VBOX_FAILURE(rc))
516 return rc;
517 char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);
518 if (psz)
519 {
520 pDbgc->fInputOverflow = false;
521 pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;
522 pDbgc->iWrite = (unsigned)cbRead;
523 pDbgc->cInputLines = 0;
524 break;
525 }
526 }
527
528 return 0;
529}
530
531
532
533/**
534 * Read input and do some preprocessing.
535 *
536 * @returns VBox status.
537 * In addition to the iWrite and achInput, cInputLines is maintained.
538 * In case of an input overflow the fInputOverflow flag will be set.
539 * @param pDbgc Debugger console instance data.
540 */
541static int dbgcInputRead(PDBGC pDbgc)
542{
543 /*
544 * We have ready input.
545 * Read it till we don't have any or we have a full input buffer.
546 */
547 int rc = 0;
548 do
549 {
550 /*
551 * More available buffer space?
552 */
553 size_t cbLeft;
554 if (pDbgc->iWrite > pDbgc->iRead)
555 cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);
556 else
557 cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;
558 if (!cbLeft)
559 {
560 /* overflow? */
561 if (!pDbgc->cInputLines)
562 rc = dbgcInputOverflow(pDbgc);
563 break;
564 }
565
566 /*
567 * Read one char and interpret it.
568 */
569 char achRead[128];
570 size_t cbRead;
571 rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);
572 if (VBOX_FAILURE(rc))
573 return rc;
574 char *psz = &achRead[0];
575 while (cbRead-- > 0)
576 {
577 char ch = *psz++;
578 switch (ch)
579 {
580 /*
581 * Ignore.
582 */
583 case '\0':
584 case '\r':
585 case '\a':
586 break;
587
588 /*
589 * Backspace.
590 */
591 case '\b':
592 Log2(("DBGC: backspace\n"));
593 if (pDbgc->iRead != pDbgc->iWrite)
594 {
595 unsigned iWriteUndo = pDbgc->iWrite;
596 if (pDbgc->iWrite)
597 pDbgc->iWrite--;
598 else
599 pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;
600
601 if (pDbgc->achInput[pDbgc->iWrite] == '\n')
602 pDbgc->iWrite = iWriteUndo;
603 }
604 break;
605
606 /*
607 * Add char to buffer.
608 */
609 case '\t':
610 case '\n':
611 case ';':
612 switch (ch)
613 {
614 case '\t': ch = ' '; break;
615 case '\n': pDbgc->cInputLines++; break;
616 }
617 default:
618 Log2(("DBGC: ch=%02x\n", (unsigned char)ch));
619 pDbgc->achInput[pDbgc->iWrite] = ch;
620 if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))
621 pDbgc->iWrite = 0;
622 break;
623 }
624 }
625
626 /* Terminate it to make it easier to read in the debugger. */
627 pDbgc->achInput[pDbgc->iWrite] = '\0';
628 } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));
629
630 return rc;
631}
632
633
634
635/**
636 * Resolves a symbol (or tries to do so at least).
637 *
638 * @returns 0 on success.
639 * @returns VBox status on failure.
640 * @param pDbgc The debug console instance.
641 * @param pszSymbol The symbol name.
642 * @param enmType The result type.
643 * @param pResult Where to store the result.
644 */
645int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)
646{
647 /*
648 * Builtin?
649 */
650 PCDBGCSYM pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol);
651 if (pSymDesc)
652 {
653 if (!pSymDesc->pfnGet)
654 return VERR_PARSE_WRITEONLY_SYMBOL;
655 return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult);
656 }
657
658
659 /*
660 * Ask PDM.
661 */
662 /** @todo resolve symbols using PDM. */
663
664
665 /*
666 * Ask the debug info manager.
667 */
668 DBGFSYMBOL Symbol;
669 int rc = DBGFR3SymbolByName(pDbgc->pVM, pszSymbol, &Symbol);
670 if (VBOX_SUCCESS(rc))
671 {
672 /*
673 * Default return is a flat gc address.
674 */
675 memset(pResult, 0, sizeof(*pResult));
676 pResult->enmRangeType = Symbol.cb ? DBGCVAR_RANGE_BYTES : DBGCVAR_RANGE_NONE;
677 pResult->u64Range = Symbol.cb;
678 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;
679 pResult->u.GCFlat = Symbol.Value;
680 DBGCVAR VarTmp;
681 switch (enmType)
682 {
683 /* nothing to do. */
684 case DBGCVAR_TYPE_GC_FLAT:
685 case DBGCVAR_TYPE_GC_FAR:
686 case DBGCVAR_TYPE_ANY:
687 return VINF_SUCCESS;
688
689 /* simply make it numeric. */
690 case DBGCVAR_TYPE_NUMBER:
691 pResult->enmType = DBGCVAR_TYPE_NUMBER;
692 pResult->u.u64Number = Symbol.Value;
693 return VINF_SUCCESS;
694
695 /* cast it. */
696
697 case DBGCVAR_TYPE_GC_PHYS:
698 VarTmp = *pResult;
699 return dbgcOpAddrPhys(pDbgc, &VarTmp, pResult);
700
701 case DBGCVAR_TYPE_HC_FAR:
702 case DBGCVAR_TYPE_HC_FLAT:
703 VarTmp = *pResult;
704 return dbgcOpAddrHost(pDbgc, &VarTmp, pResult);
705
706 case DBGCVAR_TYPE_HC_PHYS:
707 VarTmp = *pResult;
708 return dbgcOpAddrHostPhys(pDbgc, &VarTmp, pResult);
709
710 default:
711 AssertMsgFailed(("Internal error enmType=%d\n", enmType));
712 return VERR_INVALID_PARAMETER;
713 }
714 }
715
716 return VERR_PARSE_NOT_IMPLEMENTED;
717}
718
719
720/**
721 * Initalizes g_bmOperatorChars.
722 */
723static void dbgcInitOpCharBitMap(void)
724{
725 memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));
726 for (unsigned iOp = 0; iOp < g_cOps; iOp++)
727 ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]);
728}
729
730
731/**
732 * Checks whether the character may be the start of an operator.
733 *
734 * @returns true/false.
735 * @param ch The character.
736 */
737DECLINLINE(bool) dbgcIsOpChar(char ch)
738{
739 return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);
740}
741
742
743static int dbgcEvalSubString(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pArg)
744{
745 Log2(("dbgcEvalSubString: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
746
747 /*
748 * Removing any quoting and escapings.
749 */
750 char ch = *pszExpr;
751 if (ch == '"' || ch == '\'' || ch == '`')
752 {
753 if (pszExpr[--cchExpr] != ch)
754 return VERR_PARSE_UNBALANCED_QUOTE;
755 cchExpr--;
756 pszExpr++;
757
758 /** @todo string unescaping. */
759 }
760 pszExpr[cchExpr] = '\0';
761
762 /*
763 * Make the argument.
764 */
765 pArg->pDesc = NULL;
766 pArg->pNext = NULL;
767 pArg->enmType = DBGCVAR_TYPE_STRING;
768 pArg->u.pszString = pszExpr;
769 pArg->enmRangeType = DBGCVAR_RANGE_BYTES;
770 pArg->u64Range = cchExpr;
771
772 NOREF(pDbgc);
773 return 0;
774}
775
776
777static int dbgcEvalSubNum(char *pszExpr, unsigned uBase, PDBGCVAR pArg)
778{
779 Log2(("dbgcEvalSubNum: uBase=%d pszExpr=%s\n", uBase, pszExpr));
780 /*
781 * Convert to number.
782 */
783 uint64_t u64 = 0;
784 char ch;
785 while ((ch = *pszExpr) != '\0')
786 {
787 uint64_t u64Prev = u64;
788 unsigned u = ch - '0';
789 if (u < 10 && u < uBase)
790 u64 = u64 * uBase + u;
791 else if (ch >= 'a' && (u = ch - ('a' - 10)) < uBase)
792 u64 = u64 * uBase + u;
793 else if (ch >= 'A' && (u = ch - ('A' - 10)) < uBase)
794 u64 = u64 * uBase + u;
795 else
796 return VERR_PARSE_INVALID_NUMBER;
797
798 /* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */
799 if (u64Prev != u64 / uBase)
800 return VERR_PARSE_NUMBER_TOO_BIG;
801
802 /* next */
803 pszExpr++;
804 }
805
806 /*
807 * Initialize the argument.
808 */
809 pArg->pDesc = NULL;
810 pArg->pNext = NULL;
811 pArg->enmType = DBGCVAR_TYPE_NUMBER;
812 pArg->u.u64Number = u64;
813 pArg->enmRangeType = DBGCVAR_RANGE_NONE;
814 pArg->u64Range = 0;
815
816 return 0;
817}
818
819
820/**
821 * Match variable and variable descriptor, promoting the variable if necessary.
822 *
823 * @returns VBox status code.
824 * @param pDbgc Debug console instanace.
825 * @param pVar Variable.
826 * @param pVarDesc Variable descriptor.
827 */
828static int dbgcEvalSubMatchVar(PDBGC pDbgc, PDBGCVAR pVar, PCDBGCVARDESC pVarDesc)
829{
830 /*
831 * (If match or promoted to match, return, else break.)
832 */
833 switch (pVarDesc->enmCategory)
834 {
835 /*
836 * Anything goes
837 */
838 case DBGCVAR_CAT_ANY:
839 return VINF_SUCCESS;
840
841 /*
842 * Pointer with and without range.
843 * We can try resolve strings and symbols as symbols and
844 * promote numbers to flat GC pointers.
845 */
846 case DBGCVAR_CAT_POINTER_NO_RANGE:
847 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
848 return VERR_PARSE_NO_RANGE_ALLOWED;
849 /* fallthru */
850 case DBGCVAR_CAT_POINTER:
851 switch (pVar->enmType)
852 {
853 case DBGCVAR_TYPE_GC_FLAT:
854 case DBGCVAR_TYPE_GC_FAR:
855 case DBGCVAR_TYPE_GC_PHYS:
856 case DBGCVAR_TYPE_HC_FLAT:
857 case DBGCVAR_TYPE_HC_FAR:
858 case DBGCVAR_TYPE_HC_PHYS:
859 return VINF_SUCCESS;
860
861 case DBGCVAR_TYPE_SYMBOL:
862 case DBGCVAR_TYPE_STRING:
863 {
864 DBGCVAR Var;
865 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
866 if (VBOX_SUCCESS(rc))
867 {
868 /* deal with range */
869 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
870 {
871 Var.enmRangeType = pVar->enmRangeType;
872 Var.u64Range = pVar->u64Range;
873 }
874 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
875 Var.enmRangeType = DBGCVAR_RANGE_NONE;
876 *pVar = Var;
877 return rc;
878 }
879 break;
880 }
881
882 case DBGCVAR_TYPE_NUMBER:
883 {
884 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
885 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
886 pVar->u.GCFlat = GCPtr;
887 return VINF_SUCCESS;
888 }
889
890 default:
891 break;
892 }
893 break;
894
895 /*
896 * GC pointer with and without range.
897 * We can try resolve strings and symbols as symbols and
898 * promote numbers to flat GC pointers.
899 */
900 case DBGCVAR_CAT_GC_POINTER_NO_RANGE:
901 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
902 return VERR_PARSE_NO_RANGE_ALLOWED;
903 /* fallthru */
904 case DBGCVAR_CAT_GC_POINTER:
905 switch (pVar->enmType)
906 {
907 case DBGCVAR_TYPE_GC_FLAT:
908 case DBGCVAR_TYPE_GC_FAR:
909 case DBGCVAR_TYPE_GC_PHYS:
910 return VINF_SUCCESS;
911
912 case DBGCVAR_TYPE_HC_FLAT:
913 case DBGCVAR_TYPE_HC_FAR:
914 case DBGCVAR_TYPE_HC_PHYS:
915 return VERR_PARSE_CONVERSION_FAILED;
916
917 case DBGCVAR_TYPE_SYMBOL:
918 case DBGCVAR_TYPE_STRING:
919 {
920 DBGCVAR Var;
921 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
922 if (VBOX_SUCCESS(rc))
923 {
924 /* deal with range */
925 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
926 {
927 Var.enmRangeType = pVar->enmRangeType;
928 Var.u64Range = pVar->u64Range;
929 }
930 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
931 Var.enmRangeType = DBGCVAR_RANGE_NONE;
932 *pVar = Var;
933 return rc;
934 }
935 break;
936 }
937
938 case DBGCVAR_TYPE_NUMBER:
939 {
940 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
941 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
942 pVar->u.GCFlat = GCPtr;
943 return VINF_SUCCESS;
944 }
945
946 default:
947 break;
948 }
949 break;
950
951 /*
952 * Number with or without a range.
953 * Numbers can be resolved from symbols, but we cannot demote a pointer
954 * to a number.
955 */
956 case DBGCVAR_CAT_NUMBER_NO_RANGE:
957 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
958 return VERR_PARSE_NO_RANGE_ALLOWED;
959 /* fallthru */
960 case DBGCVAR_CAT_NUMBER:
961 switch (pVar->enmType)
962 {
963 case DBGCVAR_TYPE_NUMBER:
964 return VINF_SUCCESS;
965
966 case DBGCVAR_TYPE_SYMBOL:
967 case DBGCVAR_TYPE_STRING:
968 {
969 DBGCVAR Var;
970 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
971 if (VBOX_SUCCESS(rc))
972 {
973 *pVar = Var;
974 return rc;
975 }
976 break;
977 }
978 default:
979 break;
980 }
981 break;
982
983 /*
984 * Strings can easily be made from symbols (and of course strings).
985 * We could consider reformatting the addresses and numbers into strings later...
986 */
987 case DBGCVAR_CAT_STRING:
988 switch (pVar->enmType)
989 {
990 case DBGCVAR_TYPE_SYMBOL:
991 pVar->enmType = DBGCVAR_TYPE_STRING;
992 /* fallthru */
993 case DBGCVAR_TYPE_STRING:
994 return VINF_SUCCESS;
995 default:
996 break;
997 }
998 break;
999
1000 /*
1001 * Symol is pretty much the same thing as a string (at least until we actually implement it).
1002 */
1003 case DBGCVAR_CAT_SYMBOL:
1004 switch (pVar->enmType)
1005 {
1006 case DBGCVAR_TYPE_STRING:
1007 pVar->enmType = DBGCVAR_TYPE_SYMBOL;
1008 /* fallthru */
1009 case DBGCVAR_TYPE_SYMBOL:
1010 return VINF_SUCCESS;
1011 default:
1012 break;
1013 }
1014 break;
1015
1016 /*
1017 * Anything else is illegal.
1018 */
1019 default:
1020 AssertMsgFailed(("enmCategory=%d\n", pVar->enmType));
1021 break;
1022 }
1023
1024 return VERR_PARSE_NO_ARGUMENT_MATCH;
1025}
1026
1027
1028/**
1029 * Matches a set of variables with a description set.
1030 *
1031 * This is typically used for routine arguments before a call. The effects in
1032 * addition to the validation, is that some variables might be propagated to
1033 * other types in order to match the description. The following transformations
1034 * are supported:
1035 * - String reinterpreted as a symbol and resolved to a number or pointer.
1036 * - Number to a pointer.
1037 * - Pointer to a number.
1038 * @returns 0 on success with paVars.
1039 * @returns VBox error code for match errors.
1040 */
1041static int dbgcEvalSubMatchVars(PDBGC pDbgc, unsigned cVarsMin, unsigned cVarsMax,
1042 PCDBGCVARDESC paVarDescs, unsigned cVarDescs,
1043 PDBGCVAR paVars, unsigned cVars)
1044{
1045 /*
1046 * Just do basic min / max checks first.
1047 */
1048 if (cVars < cVarsMin)
1049 return VERR_PARSE_TOO_FEW_ARGUMENTS;
1050 if (cVars > cVarsMax)
1051 return VERR_PARSE_TOO_MANY_ARGUMENTS;
1052
1053 /*
1054 * Match the descriptors and actual variables.
1055 */
1056 PCDBGCVARDESC pPrevDesc = NULL;
1057 unsigned cCurDesc = 0;
1058 unsigned iVar = 0;
1059 unsigned iVarDesc = 0;
1060 while (iVar < cVars)
1061 {
1062 /* walk the descriptors */
1063 if (iVarDesc >= cVarDescs)
1064 return VERR_PARSE_TOO_MANY_ARGUMENTS;
1065 if ( ( paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV
1066 && &paVarDescs[iVarDesc - 1] != pPrevDesc)
1067 || cCurDesc >= paVarDescs[iVarDesc].cTimesMax)
1068 {
1069 iVarDesc++;
1070 if (iVarDesc >= cVarDescs)
1071 return VERR_PARSE_TOO_MANY_ARGUMENTS;
1072 cCurDesc = 0;
1073 }
1074
1075 /*
1076 * Skip thru optional arguments until we find something which matches
1077 * or can easily be promoted to what the descriptor want.
1078 */
1079 for (;;)
1080 {
1081 int rc = dbgcEvalSubMatchVar(pDbgc, &paVars[iVar], &paVarDescs[iVarDesc]);
1082 if (VBOX_SUCCESS(rc))
1083 {
1084 paVars[iVar].pDesc = &paVarDescs[iVarDesc];
1085 cCurDesc++;
1086 break;
1087 }
1088
1089 /* can we advance? */
1090 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
1091 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
1092 if (++iVarDesc >= cVarDescs)
1093 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
1094 cCurDesc = 0;
1095 }
1096
1097 /* next var */
1098 iVar++;
1099 }
1100
1101 /*
1102 * Check that the rest of the descriptors are optional.
1103 */
1104 while (iVarDesc < cVarDescs)
1105 {
1106 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
1107 return VERR_PARSE_TOO_FEW_ARGUMENTS;
1108 cCurDesc = 0;
1109
1110 /* next */
1111 iVarDesc++;
1112 }
1113
1114 return 0;
1115}
1116
1117
1118/**
1119 * Evaluates one argument with respect to unary operators.
1120 *
1121 * @returns 0 on success. pResult contains the result.
1122 * @returns VBox error code on parse or other evaluation error.
1123 *
1124 * @param pDbgc Debugger console instance data.
1125 * @param pszExpr The expression string.
1126 * @param pResult Where to store the result of the expression evaluation.
1127 */
1128static int dbgcEvalSubUnary(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
1129{
1130 Log2(("dbgcEvalSubUnary: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
1131
1132 /*
1133 * The state of the expression is now such that it will start by zero or more
1134 * unary operators and being followed by an expression of some kind.
1135 * The expression is either plain or in parenthesis.
1136 *
1137 * Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-)
1138 * ASSUME: unary operators are all of equal precedence.
1139 */
1140 int rc = 0;
1141 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, pszExpr, false, ' ');
1142 if (pOp)
1143 {
1144 /* binary operators means syntax error. */
1145 if (pOp->fBinary)
1146 return VERR_PARSE_UNEXPECTED_OPERATOR;
1147
1148 /*
1149 * If the next expression (the one following the unary operator) is in a
1150 * parenthesis a full eval is needed. If not the unary eval will suffice.
1151 */
1152 /* calc and strip next expr. */
1153 char *pszExpr2 = pszExpr + pOp->cchName;
1154 while (isblank(*pszExpr2))
1155 pszExpr2++;
1156
1157 if (!*pszExpr2)
1158 rc = VERR_PARSE_EMPTY_ARGUMENT;
1159 else
1160 {
1161 DBGCVAR Arg;
1162 if (*pszExpr2 == '(')
1163 rc = dbgcEvalSub(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
1164 else
1165 rc = dbgcEvalSubUnary(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
1166 if (VBOX_SUCCESS(rc))
1167 rc = pOp->pfnHandlerUnary(pDbgc, &Arg, pResult);
1168 }
1169 }
1170 else
1171 {
1172 /*
1173 * Didn't find any operators, so it we have to check if this can be an
1174 * function call before assuming numeric or string expression.
1175 *
1176 * (ASSUMPTIONS:)
1177 * A function name only contains alphanumerical chars and it can not start
1178 * with a numerical character.
1179 * Immediately following the name is a parenthesis which must over
1180 * the remaining part of the expression.
1181 */
1182 bool fExternal = *pszExpr == '.';
1183 char *pszFun = fExternal ? pszExpr + 1 : pszExpr;
1184 char *pszFunEnd = NULL;
1185 if (pszExpr[cchExpr - 1] == ')' && isalpha(*pszFun))
1186 {
1187 pszFunEnd = pszExpr + 1;
1188 while (*pszFunEnd != '(' && isalnum(*pszFunEnd))
1189 pszFunEnd++;
1190 if (*pszFunEnd != '(')
1191 pszFunEnd = NULL;
1192 }
1193
1194 if (pszFunEnd)
1195 {
1196 /*
1197 * Ok, it's a function call.
1198 */
1199 if (fExternal)
1200 pszExpr++, cchExpr--;
1201 PCDBGCCMD pFun = dbgcRoutineLookup(pDbgc, pszExpr, pszFunEnd - pszExpr, fExternal);
1202 if (!pFun)
1203 return VERR_PARSE_FUNCTION_NOT_FOUND;
1204 if (!pFun->pResultDesc)
1205 return VERR_PARSE_NOT_A_FUNCTION;
1206
1207 /*
1208 * Parse the expression in parenthesis.
1209 */
1210 cchExpr -= pszFunEnd - pszExpr;
1211 pszExpr = pszFunEnd;
1212 /** @todo implement multiple arguments. */
1213 DBGCVAR Arg;
1214 rc = dbgcEvalSub(pDbgc, pszExpr, cchExpr, &Arg);
1215 if (!rc)
1216 {
1217 rc = dbgcEvalSubMatchVars(pDbgc, pFun->cArgsMin, pFun->cArgsMax, pFun->paArgDescs, pFun->cArgDescs, &Arg, 1);
1218 if (!rc)
1219 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, &Arg, 1, pResult);
1220 }
1221 else if (rc == VERR_PARSE_EMPTY_ARGUMENT && pFun->cArgsMin == 0)
1222 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, NULL, 0, pResult);
1223 }
1224 else
1225 {
1226 /*
1227 * Didn't find any operators, so it must be a plain expression.
1228 * This might be numeric or a string expression.
1229 */
1230 char ch = pszExpr[0];
1231 char ch2 = pszExpr[1];
1232 if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))
1233 rc = dbgcEvalSubNum(pszExpr + 2, 16, pResult);
1234 else if (ch == '0' && (ch2 == 'i' || ch2 == 'i'))
1235 rc = dbgcEvalSubNum(pszExpr + 2, 10, pResult);
1236 else if (ch == '0' && (ch2 == 't' || ch2 == 'T'))
1237 rc = dbgcEvalSubNum(pszExpr + 2, 8, pResult);
1238 /// @todo 0b doesn't work as a binary prefix, we confuse it with 0bf8:0123 and stuff.
1239 //else if (ch == '0' && (ch2 == 'b' || ch2 == 'b'))
1240 // rc = dbgcEvalSubNum(pszExpr + 2, 2, pResult);
1241 else
1242 {
1243 /*
1244 * Hexadecimal number or a string?
1245 */
1246 char *psz = pszExpr;
1247 while (isxdigit(*psz))
1248 psz++;
1249 if (!*psz)
1250 rc = dbgcEvalSubNum(pszExpr, 16, pResult);
1251 else if ((*psz == 'h' || *psz == 'H') && !psz[1])
1252 {
1253 *psz = '\0';
1254 rc = dbgcEvalSubNum(pszExpr, 16, pResult);
1255 }
1256 else
1257 rc = dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
1258 }
1259 }
1260 }
1261
1262 return rc;
1263}
1264
1265
1266/**
1267 * Evaluates one argument.
1268 *
1269 * @returns 0 on success. pResult contains the result.
1270 * @returns VBox error code on parse or other evaluation error.
1271 *
1272 * @param pDbgc Debugger console instance data.
1273 * @param pszExpr The expression string.
1274 * @param pResult Where to store the result of the expression evaluation.
1275 */
1276int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
1277{
1278 Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
1279 /*
1280 * First we need to remove blanks in both ends.
1281 * ASSUMES: There is no quoting unless the entire expression is a string.
1282 */
1283
1284 /* stripping. */
1285 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
1286 pszExpr[--cchExpr] = '\0';
1287 while (isblank(*pszExpr))
1288 pszExpr++, cchExpr--;
1289 if (!*pszExpr)
1290 return VERR_PARSE_EMPTY_ARGUMENT;
1291
1292 /* it there is any kind of quoting in the expression, it's string meat. */
1293 if (strpbrk(pszExpr, "\"'`"))
1294 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
1295
1296 /*
1297 * Check if there are any parenthesis which needs removing.
1298 */
1299 if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')')
1300 {
1301 do
1302 {
1303 unsigned cPar = 1;
1304 char *psz = pszExpr + 1;
1305 char ch;
1306 while ((ch = *psz) != '\0')
1307 {
1308 if (ch == '(')
1309 cPar++;
1310 else if (ch == ')')
1311 {
1312 if (cPar <= 0)
1313 return VERR_PARSE_UNBALANCED_PARENTHESIS;
1314 cPar--;
1315 if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */
1316 break;
1317 }
1318 /* next */
1319 psz++;
1320 }
1321 if (ch)
1322 break;
1323
1324 /* remove the parenthesis. */
1325 pszExpr++;
1326 cchExpr -= 2;
1327 pszExpr[cchExpr] = '\0';
1328
1329 /* strip blanks. */
1330 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
1331 pszExpr[--cchExpr] = '\0';
1332 while (isblank(*pszExpr))
1333 pszExpr++, cchExpr--;
1334 if (!*pszExpr)
1335 return VERR_PARSE_EMPTY_ARGUMENT;
1336 } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');
1337 }
1338
1339 /* tabs to spaces. */
1340 char *psz = pszExpr;
1341 while ((psz = strchr(psz, '\t')) != NULL)
1342 *psz = ' ';
1343
1344 /*
1345 * Now, we need to look for the binary operator with the lowest precedence.
1346 *
1347 * If there are no operators we're left with a simple expression which we
1348 * evaluate with respect to unary operators
1349 */
1350 char *pszOpSplit = NULL;
1351 PCDBGCOP pOpSplit = NULL;
1352 unsigned cBinaryOps = 0;
1353 unsigned cPar = 0;
1354 char ch;
1355 char chPrev = ' ';
1356 bool fBinary = false;
1357 psz = pszExpr;
1358
1359 while ((ch = *psz) != '\0')
1360 {
1361 //Log2(("ch=%c cPar=%d fBinary=%d\n", ch, cPar, fBinary));
1362 /*
1363 * Parenthesis.
1364 */
1365 if (ch == '(')
1366 {
1367 cPar++;
1368 fBinary = false;
1369 }
1370 else if (ch == ')')
1371 {
1372 if (cPar <= 0)
1373 return VERR_PARSE_UNBALANCED_PARENTHESIS;
1374 cPar--;
1375 fBinary = true;
1376 }
1377 /*
1378 * Potential operator.
1379 */
1380 else if (cPar == 0 && !isblank(ch))
1381 {
1382 PCDBGCOP pOp = dbgcIsOpChar(ch)
1383 ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev)
1384 : NULL;
1385 if (pOp)
1386 {
1387 /* If not the right kind of operator we've got a syntax error. */
1388 if (pOp->fBinary != fBinary)
1389 return VERR_PARSE_UNEXPECTED_OPERATOR;
1390
1391 /*
1392 * Update the parse state and skip the operator.
1393 */
1394 if (!pOpSplit)
1395 {
1396 pOpSplit = pOp;
1397 pszOpSplit = psz;
1398 cBinaryOps = fBinary;
1399 }
1400 else if (fBinary)
1401 {
1402 cBinaryOps++;
1403 if (pOp->iPrecedence >= pOpSplit->iPrecedence)
1404 {
1405 pOpSplit = pOp;
1406 pszOpSplit = psz;
1407 }
1408 }
1409
1410 psz += pOp->cchName - 1;
1411 fBinary = false;
1412 }
1413 else
1414 fBinary = true;
1415 }
1416
1417 /* next */
1418 psz++;
1419 chPrev = ch;
1420 } /* parse loop. */
1421
1422
1423 /*
1424 * Either we found an operator to divide the expression by
1425 * or we didn't find any. In the first case it's divide and
1426 * conquer. In the latter it's a single expression which
1427 * needs dealing with its unary operators if any.
1428 */
1429 int rc;
1430 if ( cBinaryOps
1431 && pOpSplit->fBinary)
1432 {
1433 /* process 1st sub expression. */
1434 *pszOpSplit = '\0';
1435 DBGCVAR Arg1;
1436 rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, &Arg1);
1437 if (VBOX_SUCCESS(rc))
1438 {
1439 /* process 2nd sub expression. */
1440 char *psz2 = pszOpSplit + pOpSplit->cchName;
1441 DBGCVAR Arg2;
1442 rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), &Arg2);
1443 if (VBOX_SUCCESS(rc))
1444 /* apply the operator. */
1445 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);
1446 }
1447 }
1448 else if (cBinaryOps)
1449 {
1450 /* process sub expression. */
1451 pszOpSplit += pOpSplit->cchName;
1452 DBGCVAR Arg;
1453 rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), &Arg);
1454 if (VBOX_SUCCESS(rc))
1455 /* apply the operator. */
1456 rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, pResult);
1457 }
1458 else
1459 /* plain expression or using unary operators perhaps with paratheses. */
1460 rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, pResult);
1461
1462 return rc;
1463}
1464
1465
1466/**
1467 * Parses the arguments of one command.
1468 *
1469 * @returns 0 on success.
1470 * @returns VBox error code on parse error with *pcArg containing the argument causing trouble.
1471 * @param pDbgc Debugger console instance data.
1472 * @param pCmd Pointer to the command descriptor.
1473 * @param pszArg Pointer to the arguments to parse.
1474 * @param paArgs Where to store the parsed arguments.
1475 * @param cArgs Size of the paArgs array.
1476 * @param pcArgs Where to store the number of arguments.
1477 * In the event of an error this is used to store the index of the offending argument.
1478 */
1479static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs)
1480{
1481 Log2(("dbgcProcessArguments: pCmd=%s pszArgs='%s'\n", pCmd->pszCmd, pszArgs));
1482 /*
1483 * Check if we have any argument and if the command takes any.
1484 */
1485 *pcArgs = 0;
1486 /* strip leading blanks. */
1487 while (*pszArgs && isblank(*pszArgs))
1488 pszArgs++;
1489 if (!*pszArgs)
1490 {
1491 if (!pCmd->cArgsMin)
1492 return 0;
1493 return VERR_PARSE_TOO_FEW_ARGUMENTS;
1494 }
1495 /** @todo fixme - foo() doesn't work. */
1496 if (!pCmd->cArgsMax)
1497 return VERR_PARSE_TOO_MANY_ARGUMENTS;
1498
1499 /*
1500 * This is a hack, it's "temporary" and should go away "when" the parser is
1501 * modified to match arguments while parsing.
1502 */
1503 if ( pCmd->cArgsMax == 1
1504 && pCmd->cArgsMin == 1
1505 && pCmd->cArgDescs == 1
1506 && pCmd->paArgDescs[0].enmCategory == DBGCVAR_CAT_STRING
1507 && cArgs >= 1)
1508 {
1509 *pcArgs = 1;
1510 RTStrStripR(pszArgs);
1511 return dbgcEvalSubString(pDbgc, pszArgs, strlen(pszArgs), &paArgs[0]);
1512 }
1513
1514
1515 /*
1516 * The parse loop.
1517 */
1518 PDBGCVAR pArg0 = &paArgs[0];
1519 PDBGCVAR pArg = pArg0;
1520 *pcArgs = 0;
1521 do
1522 {
1523 /*
1524 * Can we have another argument?
1525 */
1526 if (*pcArgs >= pCmd->cArgsMax)
1527 return VERR_PARSE_TOO_MANY_ARGUMENTS;
1528 if (pArg >= &paArgs[cArgs])
1529 return VERR_PARSE_ARGUMENT_OVERFLOW;
1530
1531 /*
1532 * Find the end of the argument.
1533 */
1534 int cPar = 0;
1535 char chQuote = '\0';
1536 char *pszEnd = NULL;
1537 char *psz = pszArgs;
1538 char ch;
1539 bool fBinary = false;
1540 for (;;)
1541 {
1542 /*
1543 * Check for the end.
1544 */
1545 if ((ch = *psz) == '\0')
1546 {
1547 if (chQuote)
1548 return VERR_PARSE_UNBALANCED_QUOTE;
1549 if (cPar)
1550 return VERR_PARSE_UNBALANCED_PARENTHESIS;
1551 pszEnd = psz;
1552 break;
1553 }
1554 /*
1555 * When quoted we ignore everything but the quotation char.
1556 * We use the REXX way of escaping the quotation char, i.e. double occurence.
1557 */
1558 else if (ch == '\'' || ch == '"' || ch == '`')
1559 {
1560 if (chQuote)
1561 {
1562 /* end quote? */
1563 if (ch == chQuote)
1564 {
1565 if (psz[1] == ch)
1566 psz++; /* skip the escaped quote char */
1567 else
1568 chQuote = '\0'; /* end of quoted string. */
1569 }
1570 }
1571 else
1572 chQuote = ch; /* open new quote */
1573 }
1574 /*
1575 * Parenthesis can of course be nested.
1576 */
1577 else if (ch == '(')
1578 {
1579 cPar++;
1580 fBinary = false;
1581 }
1582 else if (ch == ')')
1583 {
1584 if (!cPar)
1585 return VERR_PARSE_UNBALANCED_PARENTHESIS;
1586 cPar--;
1587 fBinary = true;
1588 }
1589 else if (!chQuote && !cPar)
1590 {
1591 /*
1592 * Encountering blanks may mean the end of it all. A binary operator
1593 * will force continued parsing.
1594 */
1595 if (isblank(*psz))
1596 {
1597 pszEnd = psz++; /* just in case. */
1598 while (isblank(*psz))
1599 psz++;
1600 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
1601 if (!pOp || pOp->fBinary != fBinary)
1602 break; /* the end. */
1603 psz += pOp->cchName;
1604 while (isblank(*psz)) /* skip blanks so we don't get here again */
1605 psz++;
1606 fBinary = false;
1607 continue;
1608 }
1609
1610 /*
1611 * Look for operators without a space up front.
1612 */
1613 if (dbgcIsOpChar(*psz))
1614 {
1615 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
1616 if (pOp)
1617 {
1618 if (pOp->fBinary != fBinary)
1619 {
1620 pszEnd = psz;
1621 /** @todo this is a parsing error really. */
1622 break; /* the end. */
1623 }
1624 psz += pOp->cchName;
1625 while (isblank(*psz)) /* skip blanks so we don't get here again */
1626 psz++;
1627 fBinary = false;
1628 continue;
1629 }
1630 }
1631 fBinary = true;
1632 }
1633
1634 /* next char */
1635 psz++;
1636 }
1637 *pszEnd = '\0';
1638 /* (psz = next char to process) */
1639
1640 /*
1641 * Parse and evaluate the argument.
1642 */
1643 int rc = dbgcEvalSub(pDbgc, pszArgs, strlen(pszArgs), pArg);
1644 if (VBOX_FAILURE(rc))
1645 return rc;
1646
1647 /*
1648 * Next.
1649 */
1650 pArg++;
1651 (*pcArgs)++;
1652 pszArgs = psz;
1653 while (*pszArgs && isblank(*pszArgs))
1654 pszArgs++;
1655 } while (*pszArgs);
1656
1657 /*
1658 * Match the arguments.
1659 */
1660 return dbgcEvalSubMatchVars(pDbgc, pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pArg0, pArg - pArg0);
1661}
1662
1663
1664/**
1665 * Process one command.
1666 *
1667 * @returns VBox status code. Any error indicates the termination of the console session.
1668 * @param pDbgc Debugger console instance data.
1669 * @param pszCmd Pointer to the command.
1670 * @param cchCmd Length of the command.
1671 */
1672int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd)
1673{
1674 char *pszCmdInput = pszCmd;
1675
1676 /*
1677 * Skip blanks.
1678 */
1679 while (isblank(*pszCmd))
1680 pszCmd++, cchCmd--;
1681
1682 /* external command? */
1683 bool fExternal = *pszCmd == '.';
1684 if (fExternal)
1685 pszCmd++, cchCmd--;
1686
1687 /*
1688 * Find arguments.
1689 */
1690 char *pszArgs = pszCmd;
1691 while (isalnum(*pszArgs))
1692 pszArgs++;
1693 if (*pszArgs && (!isblank(*pszArgs) || pszArgs == pszCmd))
1694 {
1695 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Syntax error in command '%s'!\n", pszCmdInput);
1696 return 0;
1697 }
1698
1699 /*
1700 * Find the command.
1701 */
1702 PCDBGCCMD pCmd = dbgcRoutineLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);
1703 if (!pCmd || (pCmd->fFlags & DBGCCMD_FLAGS_FUNCTION))
1704 return pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Unknown command '%s'!\n", pszCmdInput);
1705
1706 /*
1707 * Parse arguments (if any).
1708 */
1709 unsigned cArgs;
1710 int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg], ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs);
1711
1712 /*
1713 * Execute the command.
1714 */
1715 if (!rc)
1716 {
1717 rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[0], cArgs, NULL);
1718 }
1719 else
1720 {
1721 /* report parse / eval error. */
1722 switch (rc)
1723 {
1724 case VERR_PARSE_TOO_FEW_ARGUMENTS:
1725 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1726 "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);
1727 break;
1728 case VERR_PARSE_TOO_MANY_ARGUMENTS:
1729 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1730 "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);
1731 break;
1732 case VERR_PARSE_ARGUMENT_OVERFLOW:
1733 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1734 "Syntax error: Too many arguments.\n");
1735 break;
1736 case VERR_PARSE_UNBALANCED_QUOTE:
1737 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1738 "Syntax error: Unbalanced quote (argument %d).\n", cArgs);
1739 break;
1740 case VERR_PARSE_UNBALANCED_PARENTHESIS:
1741 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1742 "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);
1743 break;
1744 case VERR_PARSE_EMPTY_ARGUMENT:
1745 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1746 "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);
1747 break;
1748 case VERR_PARSE_UNEXPECTED_OPERATOR:
1749 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1750 "Syntax error: Invalid operator usage (argument %d).\n", cArgs);
1751 break;
1752 case VERR_PARSE_INVALID_NUMBER:
1753 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1754 "Syntax error: Ivalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);
1755 break;
1756 case VERR_PARSE_NUMBER_TOO_BIG:
1757 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1758 "Error: Numeric overflow (argument %d).\n", cArgs);
1759 break;
1760 case VERR_PARSE_INVALID_OPERATION:
1761 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1762 "Error: Invalid operation attempted (argument %d).\n", cArgs);
1763 break;
1764 case VERR_PARSE_FUNCTION_NOT_FOUND:
1765 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1766 "Error: Function not found (argument %d).\n", cArgs);
1767 break;
1768 case VERR_PARSE_NOT_A_FUNCTION:
1769 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1770 "Error: The function specified is not a function (argument %d).\n", cArgs);
1771 break;
1772 case VERR_PARSE_NO_MEMORY:
1773 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1774 "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);
1775 break;
1776 case VERR_PARSE_INCORRECT_ARG_TYPE:
1777 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1778 "Error: Incorrect argument type (argument %d?).\n", cArgs);
1779 break;
1780 case VERR_PARSE_VARIABLE_NOT_FOUND:
1781 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1782 "Error: An undefined variable was referenced (argument %d).\n", cArgs);
1783 break;
1784 case VERR_PARSE_CONVERSION_FAILED:
1785 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1786 "Error: A conversion between two types failed (argument %d).\n", cArgs);
1787 break;
1788 case VERR_PARSE_NOT_IMPLEMENTED:
1789 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1790 "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);
1791 break;
1792 case VERR_PARSE_BAD_RESULT_TYPE:
1793 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1794 "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);
1795 break;
1796 case VERR_PARSE_WRITEONLY_SYMBOL:
1797 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1798 "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);
1799 break;
1800
1801 default:
1802 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1803 "Error: Unknown error %d!\n", rc);
1804 return rc;
1805 }
1806
1807 /*
1808 * Parse errors are non fatal.
1809 */
1810 if (rc >= VERR_PARSE_FIRST && rc < VERR_PARSE_LAST)
1811 rc = 0;
1812 }
1813
1814 return rc;
1815}
1816
1817
1818/**
1819 * Process all commands current in the buffer.
1820 *
1821 * @returns VBox status code. Any error indicates the termination of the console session.
1822 * @param pDbgc Debugger console instance data.
1823 */
1824static int dbgcProcessCommands(PDBGC pDbgc)
1825{
1826 int rc = 0;
1827 while (pDbgc->cInputLines)
1828 {
1829 /*
1830 * Empty the log buffer if we're hooking the log.
1831 */
1832 if (pDbgc->fLog)
1833 {
1834 rc = dbgcProcessLog(pDbgc);
1835 if (VBOX_FAILURE(rc))
1836 break;
1837 }
1838
1839 if (pDbgc->iRead == pDbgc->iWrite)
1840 {
1841 AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));
1842 pDbgc->cInputLines = 0;
1843 return 0;
1844 }
1845
1846 /*
1847 * Copy the command to the parse buffer.
1848 */
1849 char ch;
1850 char *psz = &pDbgc->achInput[pDbgc->iRead];
1851 char *pszTrg = &pDbgc->achScratch[0];
1852 while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )
1853 {
1854 if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])
1855 psz = &pDbgc->achInput[0];
1856
1857 if (psz == &pDbgc->achInput[pDbgc->iWrite])
1858 {
1859 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));
1860 pDbgc->cInputLines = 0;
1861 return 0;
1862 }
1863
1864 pszTrg++;
1865 }
1866 *pszTrg = '\0';
1867
1868 /*
1869 * Advance the buffer.
1870 */
1871 pDbgc->iRead = psz - &pDbgc->achInput[0];
1872 if (ch == '\n')
1873 pDbgc->cInputLines--;
1874
1875 /*
1876 * Parse and execute this command.
1877 */
1878 pDbgc->pszScratch = psz;
1879 pDbgc->iArg = 0;
1880 rc = dbgcProcessCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1);
1881 if (rc)
1882 break;
1883 }
1884
1885 return rc;
1886}
1887
1888
1889/**
1890 * Reads input, parses it and executes commands on '\n'.
1891 *
1892 * @returns VBox status.
1893 * @param pDbgc Debugger console instance data.
1894 */
1895static int dbgcProcessInput(PDBGC pDbgc)
1896{
1897 /*
1898 * We know there's input ready, so let's read it first.
1899 */
1900 int rc = dbgcInputRead(pDbgc);
1901 if (VBOX_FAILURE(rc))
1902 return rc;
1903
1904 /*
1905 * Now execute any ready commands.
1906 */
1907 if (pDbgc->cInputLines)
1908 {
1909 /** @todo this fReady stuff is broken. */
1910 pDbgc->fReady = false;
1911 rc = dbgcProcessCommands(pDbgc);
1912 if (VBOX_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)
1913 pDbgc->fReady = true;
1914 if ( VBOX_SUCCESS(rc)
1915 && pDbgc->iRead == pDbgc->iWrite
1916 && pDbgc->fReady)
1917 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
1918 }
1919
1920 return rc;
1921}
1922
1923
1924/**
1925 * Gets the event context identifier string.
1926 * @returns Read only string.
1927 * @param enmCtx The context.
1928 */
1929static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)
1930{
1931 switch (enmCtx)
1932 {
1933 case DBGFEVENTCTX_RAW: return "raw";
1934 case DBGFEVENTCTX_REM: return "rem";
1935 case DBGFEVENTCTX_HWACCL: return "hwaccl";
1936 case DBGFEVENTCTX_HYPER: return "hyper";
1937 case DBGFEVENTCTX_OTHER: return "other";
1938
1939 case DBGFEVENTCTX_INVALID: return "!Invalid Event Ctx!";
1940 default:
1941 AssertMsgFailed(("enmCtx=%d\n", enmCtx));
1942 return "!Unknown Event Ctx!";
1943 }
1944}
1945
1946
1947/**
1948 * Processes debugger events.
1949 *
1950 * @returns VBox status.
1951 * @param pDbgc DBGC Instance data.
1952 * @param pEvent Pointer to event data.
1953 */
1954static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)
1955{
1956 /*
1957 * Flush log first.
1958 */
1959 if (pDbgc->fLog)
1960 {
1961 int rc = dbgcProcessLog(pDbgc);
1962 if (VBOX_FAILURE(rc))
1963 return rc;
1964 }
1965
1966 /*
1967 * Process the event.
1968 */
1969 pDbgc->pszScratch = &pDbgc->achInput[0];
1970 pDbgc->iArg = 0;
1971 bool fPrintPrompt = true;
1972 int rc = VINF_SUCCESS;
1973 switch (pEvent->enmType)
1974 {
1975 /*
1976 * The first part is events we have initiated with commands.
1977 */
1978 case DBGFEVENT_HALT_DONE:
1979 {
1980 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",
1981 pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));
1982 pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */
1983 if (VBOX_SUCCESS(rc))
1984 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
1985 break;
1986 }
1987
1988
1989 /*
1990 * The second part is events which can occur at any time.
1991 */
1992 case DBGFEVENT_FATAL_ERROR:
1993 {
1994 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
1995 dbgcGetEventCtx(pEvent->enmCtx));
1996 pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */
1997 if (VBOX_SUCCESS(rc))
1998 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
1999 break;
2000 }
2001
2002 case DBGFEVENT_BREAKPOINT:
2003 case DBGFEVENT_BREAKPOINT_HYPER:
2004 {
2005 bool fRegCtxGuest = pDbgc->fRegCtxGuest;
2006 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;
2007
2008 rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
2009 switch (rc)
2010 {
2011 case VERR_DBGC_BP_NOT_FOUND:
2012 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
2013 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
2014 break;
2015
2016 case VINF_DBGC_BP_NO_COMMAND:
2017 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
2018 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
2019 break;
2020
2021 case VINF_BUFFER_OVERFLOW:
2022 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
2023 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
2024 break;
2025
2026 default:
2027 break;
2028 }
2029 if (VBOX_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))
2030 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
2031 else
2032 pDbgc->fRegCtxGuest = fRegCtxGuest;
2033 break;
2034 }
2035
2036 case DBGFEVENT_STEPPED:
2037 case DBGFEVENT_STEPPED_HYPER:
2038 {
2039 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;
2040
2041 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));
2042 if (VBOX_SUCCESS(rc))
2043 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
2044 break;
2045 }
2046
2047 case DBGFEVENT_ASSERTION_HYPER:
2048 {
2049 pDbgc->fRegCtxGuest = false;
2050
2051 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
2052 "\ndbgf event: Hypervisor Assertion! (%s)\n"
2053 "%s"
2054 "%s"
2055 "\n",
2056 dbgcGetEventCtx(pEvent->enmCtx),
2057 pEvent->u.Assert.pszMsg1,
2058 pEvent->u.Assert.pszMsg2);
2059 if (VBOX_SUCCESS(rc))
2060 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
2061 break;
2062 }
2063
2064 case DBGFEVENT_DEV_STOP:
2065 {
2066 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
2067 "\n"
2068 "dbgf event: DBGFSTOP (%s)\n"
2069 "File: %s\n"
2070 "Line: %d\n"
2071 "Function: %s\n",
2072 dbgcGetEventCtx(pEvent->enmCtx),
2073 pEvent->u.Src.pszFile,
2074 pEvent->u.Src.uLine,
2075 pEvent->u.Src.pszFunction);
2076 if (VBOX_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)
2077 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
2078 "Message: %s\n",
2079 pEvent->u.Src.pszMessage);
2080 if (VBOX_SUCCESS(rc))
2081 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
2082 break;
2083 }
2084
2085
2086 case DBGFEVENT_INVALID_COMMAND:
2087 {
2088 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");
2089 fPrintPrompt = !pDbgc->fReady;
2090 break;
2091 }
2092
2093 case DBGFEVENT_TERMINATING:
2094 {
2095 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");
2096 rc = VERR_GENERAL_FAILURE;
2097 break;
2098 }
2099
2100
2101 default:
2102 {
2103 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
2104 fPrintPrompt = !pDbgc->fReady;
2105 break;
2106 }
2107 }
2108
2109 /*
2110 * Prompt, anyone?
2111 */
2112 if (fPrintPrompt && VBOX_SUCCESS(rc))
2113 {
2114 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
2115 }
2116
2117 return rc;
2118}
2119
2120
2121
2122
2123
2124/**
2125 * Make a console instance.
2126 *
2127 * This will not return until either an 'exit' command is issued or a error code
2128 * indicating connection loss is encountered.
2129 *
2130 * @returns VINF_SUCCESS if console termination caused by the 'exit' command.
2131 * @returns The VBox status code causing the console termination.
2132 *
2133 * @param pVM VM Handle.
2134 * @param pBack Pointer to the backend structure. This must contain
2135 * a full set of function pointers to service the console.
2136 * @param fFlags Reserved, must be zero.
2137 * @remark A forced termination of the console is easiest done by forcing the
2138 * callbacks to return fatal failures.
2139 */
2140DBGDECL(int) DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)
2141{
2142 /*
2143 * Validate input.
2144 */
2145 AssertReturn(VALID_PTR(pVM), VERR_INVALID_PARAMETER);
2146 AssertReturn(VALID_PTR(pBack), VERR_INVALID_PARAMETER);
2147 AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);
2148
2149 /*
2150 * Allocate and initialize instance data
2151 */
2152 PDBGC pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));
2153 if (!pDbgc)
2154 return VERR_NO_MEMORY;
2155
2156 dbgcInitCmdHlp(pDbgc);
2157 pDbgc->pBack = pBack;
2158 pDbgc->pVM = NULL;
2159 pDbgc->pszEmulation = "CodeView/WinDbg";
2160 pDbgc->paEmulationCmds = &g_aCmdsCodeView[0];
2161 pDbgc->cEmulationCmds = g_cCmdsCodeView;
2162 //pDbgc->fLog = false;
2163 pDbgc->fRegCtxGuest = true;
2164 pDbgc->fRegTerse = true;
2165 //pDbgc->DisasmPos = {0};
2166 //pDbgc->SourcePos = {0};
2167 //pDbgc->DumpPos = {0};
2168 //pDbgc->cbDumpElement = 0;
2169 //pDbgc->cVars = 0;
2170 //pDbgc->paVars = NULL;
2171 //pDbgc->pFirstBp = NULL;
2172 //pDbgc->uInputZero = 0;
2173 //pDbgc->iRead = 0;
2174 //pDbgc->iWrite = 0;
2175 //pDbgc->cInputLines = 0;
2176 //pDbgc->fInputOverflow = false;
2177 pDbgc->fReady = true;
2178 pDbgc->pszScratch = &pDbgc->achScratch[0];
2179 //pDbgc->iArg = 0;
2180 //pDbgc->rcOutput = 0;
2181
2182 dbgcInitOpCharBitMap();
2183
2184 /*
2185 * Print welcome message.
2186 */
2187 int rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
2188 "Welcome to the VirtualBox Debugger!\n");
2189 if (VBOX_FAILURE(rc))
2190 goto l_failure;
2191
2192 /*
2193 * Attach to the VM.
2194 */
2195 rc = DBGFR3Attach(pVM);
2196 if (VBOX_FAILURE(rc))
2197 {
2198 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);
2199 goto l_failure;
2200 }
2201 pDbgc->pVM = pVM;
2202
2203 /*
2204 * Print commandline and auto select result.
2205 */
2206 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
2207 "Current VM is %08x\n" /** @todo get and print the VM name! */
2208 "VBoxDbg> ",
2209 pDbgc->pVM);
2210 if (VBOX_FAILURE(rc))
2211 goto l_failure;
2212
2213 /*
2214 * Main Debugger Loop.
2215 *
2216 * This loop will either block on waiting for input or on waiting on
2217 * debug events. If we're forwarding the log we cannot wait for long
2218 * before we must flush the log.
2219 */
2220 for (rc = 0;;)
2221 {
2222 if (pDbgc->pVM && DBGFR3CanWait(pDbgc->pVM))
2223 {
2224 /*
2225 * Wait for a debug event.
2226 */
2227 PCDBGFEVENT pEvent;
2228 rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);
2229 if (VBOX_SUCCESS(rc))
2230 {
2231 rc = dbgcProcessEvent(pDbgc, pEvent);
2232 if (VBOX_FAILURE(rc))
2233 break;
2234 }
2235 else if (rc != VERR_TIMEOUT)
2236 break;
2237
2238 /*
2239 * Check for input.
2240 */
2241 if (pBack->pfnInput(pDbgc->pBack, 0))
2242 {
2243 rc = dbgcProcessInput(pDbgc);
2244 if (VBOX_FAILURE(rc))
2245 break;
2246 }
2247 }
2248 else
2249 {
2250 /*
2251 * Wait for input. If Logging is enabled we'll only wait very briefly.
2252 */
2253 if (pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))
2254 {
2255 rc = dbgcProcessInput(pDbgc);
2256 if (VBOX_FAILURE(rc))
2257 break;
2258 }
2259 }
2260
2261 /*
2262 * Forward log output.
2263 */
2264 if (pDbgc->fLog)
2265 {
2266 rc = dbgcProcessLog(pDbgc);
2267 if (VBOX_FAILURE(rc))
2268 break;
2269 }
2270 }
2271
2272
2273l_failure:
2274 /*
2275 * Cleanup console debugger session.
2276 */
2277 /* Disable log hook. */
2278 if (pDbgc->fLog)
2279 {
2280
2281 }
2282
2283 /* Detach from the VM. */
2284 if (pDbgc->pVM)
2285 DBGFR3Detach(pDbgc->pVM);
2286
2287 /* finally, free the instance memory. */
2288 RTMemFree(pDbgc);
2289
2290 return rc;
2291}
2292
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