VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGCCmdHlp.cpp@ 32786

Last change on this file since 32786 was 31966, checked in by vboxsync, 14 years ago

DBGF,PGM,DBGC: dumping page tables - hacking still in progress (sigh, this takes for ever).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.5 KB
Line 
1/* $Id: DBGCCmdHlp.cpp 31966 2010-08-25 16:15:25Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console, Command Helpers.
4 */
5
6/*
7 * Copyright (C) 2006-2010 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* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_DBGC
22#include <VBox/dbg.h>
23#include <VBox/dbgf.h>
24#include <VBox/vm.h>
25#include <VBox/vmm.h>
26#include <VBox/mm.h>
27#include <VBox/pgm.h>
28#include <VBox/selm.h>
29#include <VBox/dis.h>
30#include <VBox/param.h>
31#include <VBox/err.h>
32#include <VBox/log.h>
33
34#include <iprt/alloc.h>
35#include <iprt/alloca.h>
36#include <iprt/string.h>
37#include <iprt/assert.h>
38#include <iprt/ctype.h>
39
40#include "DBGCInternal.h"
41
42
43
44/**
45 * Command helper for writing text to the debug console.
46 *
47 * @returns VBox status.
48 * @param pCmdHlp Pointer to the command callback structure.
49 * @param pvBuf What to write.
50 * @param cbBuf Number of bytes to write.
51 * @param pcbWritten Where to store the number of bytes actually written.
52 * If NULL the entire buffer must be successfully written.
53 */
54static DECLCALLBACK(int) dbgcHlpWrite(PDBGCCMDHLP pCmdHlp, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
55{
56 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
57 return pDbgc->pBack->pfnWrite(pDbgc->pBack, pvBuf, cbBuf, pcbWritten);
58}
59
60
61/**
62 * Command helper for writing formatted text to the debug console.
63 *
64 * @returns VBox status.
65 * @param pCmdHlp Pointer to the command callback structure.
66 * @param pcb Where to store the number of bytes written.
67 * @param pszFormat The format string.
68 * This is using the log formatter, so it's format extensions can be used.
69 * @param ... Arguments specified in the format string.
70 */
71static DECLCALLBACK(int) dbgcHlpPrintf(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, ...)
72{
73 /*
74 * Do the formatting and output.
75 */
76 va_list args;
77 va_start(args, pszFormat);
78 int rc = pCmdHlp->pfnPrintfV(pCmdHlp, pcbWritten, pszFormat, args);
79 va_end(args);
80
81 return rc;
82}
83
84/**
85 * Callback to format non-standard format specifiers.
86 *
87 * @returns The number of bytes formatted.
88 * @param pvArg Formatter argument.
89 * @param pfnOutput Pointer to output function.
90 * @param pvArgOutput Argument for the output function.
91 * @param ppszFormat Pointer to the format string pointer. Advance this till the char
92 * after the format specifier.
93 * @param pArgs Pointer to the argument list. Use this to fetch the arguments.
94 * @param cchWidth Format Width. -1 if not specified.
95 * @param cchPrecision Format Precision. -1 if not specified.
96 * @param fFlags Flags (RTSTR_NTFS_*).
97 * @param chArgSize The argument size specifier, 'l' or 'L'.
98 */
99static DECLCALLBACK(size_t) dbgcStringFormatter(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
100 const char **ppszFormat, va_list *pArgs, int cchWidth,
101 int cchPrecision, unsigned fFlags, char chArgSize)
102{
103 NOREF(cchWidth); NOREF(cchPrecision); NOREF(fFlags); NOREF(chArgSize); NOREF(pvArg);
104 if (**ppszFormat != 'D')
105 {
106 (*ppszFormat)++;
107 return 0;
108 }
109
110 (*ppszFormat)++;
111 switch (**ppszFormat)
112 {
113 /*
114 * Print variable without range.
115 * The argument is a const pointer to the variable.
116 */
117 case 'V':
118 {
119 (*ppszFormat)++;
120 PCDBGCVAR pVar = va_arg(*pArgs, PCDBGCVAR);
121 switch (pVar->enmType)
122 {
123 case DBGCVAR_TYPE_GC_FLAT:
124 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%RGv", pVar->u.GCFlat);
125 case DBGCVAR_TYPE_GC_FAR:
126 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x", pVar->u.GCFar.sel, pVar->u.GCFar.off);
127 case DBGCVAR_TYPE_GC_PHYS:
128 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%RGp", pVar->u.GCPhys);
129 case DBGCVAR_TYPE_HC_FLAT:
130 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%RHv", (uintptr_t)pVar->u.pvHCFlat);
131 case DBGCVAR_TYPE_HC_FAR:
132 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x", pVar->u.HCFar.sel, pVar->u.HCFar.off);
133 case DBGCVAR_TYPE_HC_PHYS:
134 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%RHp", pVar->u.HCPhys);
135 case DBGCVAR_TYPE_STRING:
136 return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);
137 case DBGCVAR_TYPE_NUMBER:
138 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx", pVar->u.u64Number);
139
140 case DBGCVAR_TYPE_UNKNOWN:
141 default:
142 return pfnOutput(pvArgOutput, "??", 2);
143 }
144 }
145
146 /*
147 * Print variable with range.
148 * The argument is a const pointer to the variable.
149 */
150 case 'v':
151 {
152 (*ppszFormat)++;
153 PCDBGCVAR pVar = va_arg(*pArgs, PCDBGCVAR);
154
155 char szRange[32];
156 switch (pVar->enmRangeType)
157 {
158 case DBGCVAR_RANGE_NONE:
159 szRange[0] = '\0';
160 break;
161 case DBGCVAR_RANGE_ELEMENTS:
162 RTStrPrintf(szRange, sizeof(szRange), " L %llx", pVar->u64Range);
163 break;
164 case DBGCVAR_RANGE_BYTES:
165 RTStrPrintf(szRange, sizeof(szRange), " LB %llx", pVar->u64Range);
166 break;
167 }
168
169 switch (pVar->enmType)
170 {
171 case DBGCVAR_TYPE_GC_FLAT:
172 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%RGv%s", pVar->u.GCFlat, szRange);
173 case DBGCVAR_TYPE_GC_FAR:
174 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x%s", pVar->u.GCFar.sel, pVar->u.GCFar.off, szRange);
175 case DBGCVAR_TYPE_GC_PHYS:
176 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%RGp%s", pVar->u.GCPhys, szRange);
177 case DBGCVAR_TYPE_HC_FLAT:
178 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%RHv%s", (uintptr_t)pVar->u.pvHCFlat, szRange);
179 case DBGCVAR_TYPE_HC_FAR:
180 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x%s", pVar->u.HCFar.sel, pVar->u.HCFar.off, szRange);
181 case DBGCVAR_TYPE_HC_PHYS:
182 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%RHp%s", pVar->u.HCPhys, szRange);
183 case DBGCVAR_TYPE_STRING:
184 return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);
185 case DBGCVAR_TYPE_NUMBER:
186 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx%s", pVar->u.u64Number, szRange);
187
188 case DBGCVAR_TYPE_UNKNOWN:
189 default:
190 return pfnOutput(pvArgOutput, "??", 2);
191 }
192 }
193
194 default:
195 AssertMsgFailed(("Invalid format type '%s'!\n", **ppszFormat));
196 return 0;
197 }
198}
199
200
201/**
202 * Output callback.
203 *
204 * @returns number of bytes written.
205 * @param pvArg User argument.
206 * @param pachChars Pointer to an array of utf-8 characters.
207 * @param cbChars Number of bytes in the character array pointed to by pachChars.
208 */
209static DECLCALLBACK(size_t) dbgcFormatOutput(void *pvArg, const char *pachChars, size_t cbChars)
210{
211 PDBGC pDbgc = (PDBGC)pvArg;
212 if (cbChars)
213 {
214 int rc = pDbgc->pBack->pfnWrite(pDbgc->pBack, pachChars, cbChars, NULL);
215 if (RT_FAILURE(rc))
216 {
217 pDbgc->rcOutput = rc;
218 cbChars = 0;
219 }
220 }
221
222 return cbChars;
223}
224
225
226
227/**
228 * Command helper for writing formatted text to the debug console.
229 *
230 * @returns VBox status.
231 * @param pCmdHlp Pointer to the command callback structure.
232 * @param pcbWritten Where to store the number of bytes written.
233 * @param pszFormat The format string.
234 * This is using the log formatter, so it's format extensions can be used.
235 * @param args Arguments specified in the format string.
236 */
237static DECLCALLBACK(int) dbgcHlpPrintfV(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, va_list args)
238{
239 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
240
241 /*
242 * Do the formatting and output.
243 */
244 pDbgc->rcOutput = 0;
245 size_t cb = RTStrFormatV(dbgcFormatOutput, pDbgc, dbgcStringFormatter, pDbgc, pszFormat, args);
246
247 if (pcbWritten)
248 *pcbWritten = cb;
249
250 return pDbgc->rcOutput;
251}
252
253
254/**
255 * Reports an error from a DBGF call.
256 *
257 * @returns VBox status code appropriate to return from a command.
258 * @param pCmdHlp Pointer to command helpers.
259 * @param rc The VBox status code returned by a DBGF call.
260 * @param pszFormat Format string for additional messages. Can be NULL.
261 * @param ... Format arguments, optional.
262 */
263static DECLCALLBACK(int) dbgcHlpVBoxErrorV(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, va_list args)
264{
265 switch (rc)
266 {
267 case VINF_SUCCESS:
268 break;
269
270 default:
271 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %Rrc: %s", rc, pszFormat ? " " : "\n");
272 if (RT_SUCCESS(rc) && pszFormat)
273 rc = pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
274 if (RT_SUCCESS(rc))
275 rc = VERR_DBGC_COMMAND_FAILED;
276 break;
277 }
278 return rc;
279}
280
281
282/**
283 * Reports an error from a DBGF call.
284 *
285 * @returns VBox status code appropriate to return from a command.
286 * @param pCmdHlp Pointer to command helpers.
287 * @param rc The VBox status code returned by a DBGF call.
288 * @param pszFormat Format string for additional messages. Can be NULL.
289 * @param ... Format arguments, optional.
290 */
291static DECLCALLBACK(int) dbgcHlpVBoxError(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...)
292{
293 va_list args;
294 va_start(args, pszFormat);
295 int rcRet = pCmdHlp->pfnVBoxErrorV(pCmdHlp, rc, pszFormat, args);
296 va_end(args);
297 return rcRet;
298}
299
300
301/**
302 * Command helper for reading memory specified by a DBGC variable.
303 *
304 * @returns VBox status code appropriate to return from a command.
305 * @param pCmdHlp Pointer to the command callback structure.
306 * @param pVM VM handle if GC or physical HC address.
307 * @param pvBuffer Where to store the read data.
308 * @param cbRead Number of bytes to read.
309 * @param pVarPointer DBGC variable specifying where to start reading.
310 * @param pcbRead Where to store the number of bytes actually read.
311 * This optional, but it's useful when read GC virtual memory where a
312 * page in the requested range might not be present.
313 * If not specified not-present failure or end of a HC physical page
314 * will cause failure.
315 */
316static DECLCALLBACK(int) dbgcHlpMemRead(PDBGCCMDHLP pCmdHlp, PVM pVM, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead)
317{
318 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
319 DBGFADDRESS Address;
320 int rc;
321
322 /*
323 * Dummy check.
324 */
325 if (cbRead == 0)
326 {
327 if (*pcbRead)
328 *pcbRead = 0;
329 return VINF_SUCCESS;
330 }
331
332 /*
333 * Convert Far addresses getting size and the correct base address.
334 * Getting and checking the size is what makes this messy and slow.
335 */
336 DBGCVAR Var = *pVarPointer;
337 switch (pVarPointer->enmType)
338 {
339 case DBGCVAR_TYPE_GC_FAR:
340 /* Use DBGFR3AddrFromSelOff for the conversion. */
341 Assert(pDbgc->pVM);
342 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, pDbgc->idCpu, &Address, Var.u.GCFar.sel, Var.u.GCFar.off);
343 if (RT_FAILURE(rc))
344 return rc;
345
346 /* don't bother with flat selectors (for now). */
347 if (!DBGFADDRESS_IS_FLAT(&Address))
348 {
349 DBGFSELINFO SelInfo;
350 rc = DBGFR3SelQueryInfo(pDbgc->pVM, pDbgc->idCpu, Address.Sel,
351 DBGFSELQI_FLAGS_DT_GUEST | DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE, &SelInfo);
352 if (RT_SUCCESS(rc))
353 {
354 RTGCUINTPTR cb; /* -1 byte */
355 if (DBGFSelInfoIsExpandDown(&SelInfo))
356 {
357 if ( !SelInfo.u.Raw.Gen.u1Granularity
358 && Address.off > UINT16_C(0xffff))
359 return VERR_OUT_OF_SELECTOR_BOUNDS;
360 if (Address.off <= SelInfo.cbLimit)
361 return VERR_OUT_OF_SELECTOR_BOUNDS;
362 cb = (SelInfo.u.Raw.Gen.u1Granularity ? UINT32_C(0xffffffff) : UINT32_C(0xffff)) - Address.off;
363 }
364 else
365 {
366 if (Address.off > SelInfo.cbLimit)
367 return VERR_OUT_OF_SELECTOR_BOUNDS;
368 cb = SelInfo.cbLimit - Address.off;
369 }
370 if (cbRead - 1 > cb)
371 {
372 if (!pcbRead)
373 return VERR_OUT_OF_SELECTOR_BOUNDS;
374 cbRead = cb + 1;
375 }
376 }
377 }
378 Var.enmType = DBGCVAR_TYPE_GC_FLAT;
379 Var.u.GCFlat = Address.FlatPtr;
380 break;
381
382 case DBGCVAR_TYPE_GC_FLAT:
383 case DBGCVAR_TYPE_GC_PHYS:
384 case DBGCVAR_TYPE_HC_FLAT:
385 case DBGCVAR_TYPE_HC_PHYS:
386 break;
387
388 case DBGCVAR_TYPE_HC_FAR: /* not supported yet! */
389 default:
390 return VERR_NOT_IMPLEMENTED;
391 }
392
393
394
395 /*
396 * Copy page by page.
397 */
398 size_t cbLeft = cbRead;
399 for (;;)
400 {
401 /*
402 * Calc read size.
403 */
404 size_t cb = RT_MIN(PAGE_SIZE, cbLeft);
405 switch (pVarPointer->enmType)
406 {
407 case DBGCVAR_TYPE_GC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCFlat & PAGE_OFFSET_MASK)); break;
408 case DBGCVAR_TYPE_GC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCPhys & PAGE_OFFSET_MASK)); break;
409 case DBGCVAR_TYPE_HC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - ((uintptr_t)Var.u.pvHCFlat & PAGE_OFFSET_MASK)); break;
410 case DBGCVAR_TYPE_HC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - ((size_t)Var.u.HCPhys & PAGE_OFFSET_MASK)); break; /* size_t: MSC has braindead loss of data warnings! */
411 default: break;
412 }
413
414 /*
415 * Perform read.
416 */
417 switch (Var.enmType)
418 {
419 case DBGCVAR_TYPE_GC_FLAT:
420 rc = DBGFR3MemRead(pDbgc->pVM, pDbgc->idCpu,
421 DBGFR3AddrFromFlat(pVM, &Address, Var.u.GCFlat),
422 pvBuffer, cb);
423 break;
424
425 case DBGCVAR_TYPE_GC_PHYS:
426 rc = DBGFR3MemRead(pDbgc->pVM, pDbgc->idCpu,
427 DBGFR3AddrFromPhys(pVM, &Address, Var.u.GCPhys),
428 pvBuffer, cb);
429 break;
430
431 case DBGCVAR_TYPE_HC_PHYS:
432 case DBGCVAR_TYPE_HC_FLAT:
433 case DBGCVAR_TYPE_HC_FAR:
434 {
435 DBGCVAR Var2;
436 rc = dbgcOpAddrFlat(pDbgc, &Var, &Var2);
437 if (RT_SUCCESS(rc))
438 {
439 /** @todo protect this!!! */
440 memcpy(pvBuffer, Var2.u.pvHCFlat, cb);
441 rc = 0;
442 }
443 else
444 rc = VERR_INVALID_POINTER;
445 break;
446 }
447
448 default:
449 rc = VERR_PARSE_INCORRECT_ARG_TYPE;
450 }
451
452 /*
453 * Check for failure.
454 */
455 if (RT_FAILURE(rc))
456 {
457 if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)
458 return VINF_SUCCESS;
459 return rc;
460 }
461
462 /*
463 * Next.
464 */
465 cbLeft -= cb;
466 if (!cbLeft)
467 break;
468 pvBuffer = (char *)pvBuffer + cb;
469 rc = DBGCCmdHlpEval(pCmdHlp, &Var, "%DV + %d", &Var, cb);
470 if (RT_FAILURE(rc))
471 {
472 if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)
473 return VINF_SUCCESS;
474 return rc;
475 }
476 }
477
478 /*
479 * Done
480 */
481 if (pcbRead)
482 *pcbRead = cbRead;
483 return 0;
484}
485
486/**
487 * Command helper for writing memory specified by a DBGC variable.
488 *
489 * @returns VBox status code appropriate to return from a command.
490 * @param pCmdHlp Pointer to the command callback structure.
491 * @param pVM VM handle if GC or physical HC address.
492 * @param pvBuffer What to write.
493 * @param cbWrite Number of bytes to write.
494 * @param pVarPointer DBGC variable specifying where to start reading.
495 * @param pcbWritten Where to store the number of bytes written.
496 * This is optional. If NULL be aware that some of the buffer
497 * might have been written to the specified address.
498 */
499static DECLCALLBACK(int) dbgcHlpMemWrite(PDBGCCMDHLP pCmdHlp, PVM pVM, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten)
500{
501 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
502 DBGFADDRESS Address;
503 int rc;
504
505 /*
506 * Dummy check.
507 */
508 if (cbWrite == 0)
509 {
510 if (*pcbWritten)
511 *pcbWritten = 0;
512 return VINF_SUCCESS;
513 }
514
515 /*
516 * Convert Far addresses getting size and the correct base address.
517 * Getting and checking the size is what makes this messy and slow.
518 */
519 DBGCVAR Var = *pVarPointer;
520 switch (pVarPointer->enmType)
521 {
522 case DBGCVAR_TYPE_GC_FAR:
523 {
524 /* Use DBGFR3AddrFromSelOff for the conversion. */
525 Assert(pDbgc->pVM);
526 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, pDbgc->idCpu, &Address, Var.u.GCFar.sel, Var.u.GCFar.off);
527 if (RT_FAILURE(rc))
528 return rc;
529
530 /* don't bother with flat selectors (for now). */
531 if (!DBGFADDRESS_IS_FLAT(&Address))
532 {
533 DBGFSELINFO SelInfo;
534 rc = DBGFR3SelQueryInfo(pDbgc->pVM, pDbgc->idCpu, Address.Sel,
535 DBGFSELQI_FLAGS_DT_GUEST | DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE, &SelInfo);
536 if (RT_SUCCESS(rc))
537 {
538 RTGCUINTPTR cb; /* -1 byte */
539 if (DBGFSelInfoIsExpandDown(&SelInfo))
540 {
541 if ( !SelInfo.u.Raw.Gen.u1Granularity
542 && Address.off > UINT16_C(0xffff))
543 return VERR_OUT_OF_SELECTOR_BOUNDS;
544 if (Address.off <= SelInfo.cbLimit)
545 return VERR_OUT_OF_SELECTOR_BOUNDS;
546 cb = (SelInfo.u.Raw.Gen.u1Granularity ? UINT32_C(0xffffffff) : UINT32_C(0xffff)) - Address.off;
547 }
548 else
549 {
550 if (Address.off > SelInfo.cbLimit)
551 return VERR_OUT_OF_SELECTOR_BOUNDS;
552 cb = SelInfo.cbLimit - Address.off;
553 }
554 if (cbWrite - 1 > cb)
555 {
556 if (!pcbWritten)
557 return VERR_OUT_OF_SELECTOR_BOUNDS;
558 cbWrite = cb + 1;
559 }
560 }
561 }
562 Var.enmType = DBGCVAR_TYPE_GC_FLAT;
563 Var.u.GCFlat = Address.FlatPtr;
564 }
565 /* fall thru */
566 case DBGCVAR_TYPE_GC_FLAT:
567 rc = DBGFR3MemWrite(pVM, pDbgc->idCpu,
568 DBGFR3AddrFromFlat(pVM, &Address, Var.u.GCFlat),
569 pvBuffer, cbWrite);
570 if (pcbWritten && RT_SUCCESS(rc))
571 *pcbWritten = cbWrite;
572 return rc;
573
574 case DBGCVAR_TYPE_GC_PHYS:
575 rc = DBGFR3MemWrite(pVM, pDbgc->idCpu,
576 DBGFR3AddrFromPhys(pVM, &Address, Var.u.GCPhys),
577 pvBuffer, cbWrite);
578 if (pcbWritten && RT_SUCCESS(rc))
579 *pcbWritten = cbWrite;
580 return rc;
581
582 case DBGCVAR_TYPE_HC_FLAT:
583 case DBGCVAR_TYPE_HC_PHYS:
584 case DBGCVAR_TYPE_HC_FAR:
585 {
586 /*
587 * Copy HC memory page by page.
588 */
589 if (pcbWritten)
590 *pcbWritten = 0;
591 while (cbWrite > 0)
592 {
593 /* convert to flat address */
594 DBGCVAR Var2;
595 rc = dbgcOpAddrFlat(pDbgc, &Var, &Var2);
596 if (RT_FAILURE(rc))
597 {
598 if (pcbWritten && *pcbWritten)
599 return -VERR_INVALID_POINTER;
600 return VERR_INVALID_POINTER;
601 }
602
603 /* calc size. */
604 size_t cbChunk = PAGE_SIZE;
605 cbChunk -= (uintptr_t)Var.u.pvHCFlat & PAGE_OFFSET_MASK;
606 if (cbChunk > cbWrite)
607 cbChunk = cbWrite;
608
609 /** @todo protect this!!! */
610 memcpy(Var2.u.pvHCFlat, pvBuffer, cbChunk);
611
612 /* advance */
613 if (Var.enmType == DBGCVAR_TYPE_HC_FLAT)
614 Var.u.pvHCFlat = (uint8_t *)Var.u.pvHCFlat + cbChunk;
615 else
616 Var.u.HCPhys += cbChunk;
617 pvBuffer = (uint8_t const *)pvBuffer + cbChunk;
618 if (pcbWritten)
619 *pcbWritten += cbChunk;
620 cbWrite -= cbChunk;
621 }
622
623 return VINF_SUCCESS;
624 }
625
626 default:
627 return VERR_NOT_IMPLEMENTED;
628 }
629}
630
631
632/**
633 * Executes one command expression.
634 * (Hopefully the parser and functions are fully reentrant.)
635 *
636 * @returns VBox status code appropriate to return from a command.
637 * @param pCmdHlp Pointer to the command callback structure.
638 * @param pszExpr The expression. Format string with the format DBGC extensions.
639 * @param ... Format arguments.
640 */
641static DECLCALLBACK(int) dbgcHlpExec(PDBGCCMDHLP pCmdHlp, const char *pszExpr, ...)
642{
643 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
644 /* Save the scratch state. */
645 char *pszScratch = pDbgc->pszScratch;
646 unsigned iArg = pDbgc->iArg;
647
648 /*
649 * Format the expression.
650 */
651 va_list args;
652 va_start(args, pszExpr);
653 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
654 size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, pDbgc->pszScratch, cbScratch, pszExpr, args);
655 va_end(args);
656 if (cb >= cbScratch)
657 return VERR_BUFFER_OVERFLOW;
658
659 /*
660 * Execute the command.
661 * We save and restore the arg index and scratch buffer pointer.
662 */
663 pDbgc->pszScratch = pDbgc->pszScratch + cb + 1;
664 int rc = dbgcProcessCommand(pDbgc, pszScratch, cb, false /* fNoExecute */);
665
666 /* Restore the scratch state. */
667 pDbgc->iArg = iArg;
668 pDbgc->pszScratch = pszScratch;
669
670 return rc;
671}
672
673
674/**
675 * @copydoc DBGCCMDHLP::pfnEvalV
676 */
677static DECLCALLBACK(int) dbgcHlpEvalV(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, va_list va)
678{
679 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
680
681 /*
682 * Format the expression.
683 */
684 char szExprFormatted[2048];
685 size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, szExprFormatted, sizeof(szExprFormatted), pszExpr, va);
686 /* ignore overflows. */
687
688 return dbgcEvalSub(pDbgc, &szExprFormatted[0], cb, pResult);
689}
690
691
692/**
693 * @copydoc DBGCCMDHLP::pfnFailV
694 */
695static DECLCALLBACK(int) dbgcHlpFailV(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, const char *pszFormat, va_list va)
696{
697 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
698
699 /*
700 * Do the formatting and output.
701 */
702 pDbgc->rcOutput = VINF_SUCCESS;
703 RTStrFormat(dbgcFormatOutput, pDbgc, dbgcStringFormatter, pDbgc, "%s: error: ", pCmd->pszCmd);
704 if (RT_FAILURE(pDbgc->rcOutput))
705 return pDbgc->rcOutput;
706 RTStrFormatV(dbgcFormatOutput, pDbgc, dbgcStringFormatter, pDbgc, pszFormat, va);
707 if (RT_FAILURE(pDbgc->rcOutput))
708 return pDbgc->rcOutput;
709
710 /** @todo DBGC: Implement failure / success on command level. */
711 return VINF_SUCCESS;
712}
713
714
715/**
716 * Converts a DBGC variable to a DBGF address structure.
717 *
718 * @returns VBox status code.
719 * @param pCmdHlp Pointer to the command callback structure.
720 * @param pVar The variable to convert.
721 * @param pAddress The target address.
722 */
723static DECLCALLBACK(int) dbgcHlpVarToDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
724{
725 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
726 return dbgcVarToDbgfAddr(pDbgc, pVar, pAddress);
727}
728
729
730/**
731 * Converts a DBGC variable to a boolean.
732 *
733 * @returns VBox status code.
734 * @param pCmdHlp Pointer to the command callback structure.
735 * @param pVar The variable to convert.
736 * @param pf Where to store the boolean.
737 */
738static DECLCALLBACK(int) dbgcHlpVarToBool(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf)
739{
740 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
741 NOREF(pDbgc);
742
743 switch (pVar->enmType)
744 {
745 case DBGCVAR_TYPE_STRING:
746 /** @todo add strcasecmp / stricmp wrappers to iprt/string.h. */
747 if ( !strcmp(pVar->u.pszString, "true")
748 || !strcmp(pVar->u.pszString, "True")
749 || !strcmp(pVar->u.pszString, "TRUE")
750 || !strcmp(pVar->u.pszString, "on")
751 || !strcmp(pVar->u.pszString, "On")
752 || !strcmp(pVar->u.pszString, "oN")
753 || !strcmp(pVar->u.pszString, "ON")
754 || !strcmp(pVar->u.pszString, "enabled")
755 || !strcmp(pVar->u.pszString, "Enabled")
756 || !strcmp(pVar->u.pszString, "DISABLED"))
757 {
758 *pf = true;
759 return VINF_SUCCESS;
760 }
761 if ( !strcmp(pVar->u.pszString, "false")
762 || !strcmp(pVar->u.pszString, "False")
763 || !strcmp(pVar->u.pszString, "FALSE")
764 || !strcmp(pVar->u.pszString, "off")
765 || !strcmp(pVar->u.pszString, "Off")
766 || !strcmp(pVar->u.pszString, "OFF")
767 || !strcmp(pVar->u.pszString, "disabled")
768 || !strcmp(pVar->u.pszString, "Disabled")
769 || !strcmp(pVar->u.pszString, "DISABLED"))
770 {
771 *pf = false;
772 return VINF_SUCCESS;
773 }
774 return VERR_PARSE_INCORRECT_ARG_TYPE; /** @todo better error code! */
775
776 case DBGCVAR_TYPE_GC_FLAT:
777 case DBGCVAR_TYPE_GC_PHYS:
778 case DBGCVAR_TYPE_HC_FLAT:
779 case DBGCVAR_TYPE_HC_PHYS:
780 case DBGCVAR_TYPE_NUMBER:
781 *pf = pVar->u.u64Number != 0;
782 return VINF_SUCCESS;
783
784 case DBGCVAR_TYPE_HC_FAR:
785 case DBGCVAR_TYPE_GC_FAR:
786 case DBGCVAR_TYPE_SYMBOL:
787 default:
788 return VERR_PARSE_INCORRECT_ARG_TYPE;
789 }
790}
791
792
793/**
794 * @interface_method_impl{DBGCCMDHLP,pfnVarGetRange}
795 */
796static DECLCALLBACK(int) dbgcHlpVarGetRange(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, uint64_t cbElement, uint64_t cbDefault,
797 uint64_t *pcbRange)
798{
799/** @todo implement this properly, strings/symbols are not resolved now. */
800 switch (pVar->enmRangeType)
801 {
802 default:
803 case DBGCVAR_RANGE_NONE:
804 *pcbRange = cbDefault;
805 break;
806 case DBGCVAR_RANGE_BYTES:
807 *pcbRange = pVar->u64Range;
808 break;
809 case DBGCVAR_RANGE_ELEMENTS:
810 *pcbRange = pVar->u64Range * cbElement;
811 break;
812 }
813 return VINF_SUCCESS;
814}
815
816
817/**
818 * Info helper callback wrapper - print formatted string.
819 *
820 * @param pHlp Pointer to this structure.
821 * @param pszFormat The format string.
822 * @param ... Arguments.
823 */
824static DECLCALLBACK(void) dbgcHlpGetDbgfOutputHlp_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
825{
826 PDBGC pDbgc = RT_FROM_MEMBER(pHlp, DBGC, DbgfOutputHlp);
827 va_list va;
828 va_start(va, pszFormat);
829 pDbgc->CmdHlp.pfnPrintfV(&pDbgc->CmdHlp, NULL, pszFormat, va);
830 va_end(va);
831}
832
833
834/**
835 * Info helper callback wrapper - print formatted string.
836 *
837 * @param pHlp Pointer to this structure.
838 * @param pszFormat The format string.
839 * @param args Argument list.
840 */
841static DECLCALLBACK(void) dbgcHlpGetDbgfOutputHlp_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
842{
843 PDBGC pDbgc = RT_FROM_MEMBER(pHlp, DBGC, DbgfOutputHlp);
844 pDbgc->CmdHlp.pfnPrintfV(&pDbgc->CmdHlp, NULL, pszFormat, args);
845}
846
847
848/**
849 * @interface_method_impl{DBGCCMDHLP,pfnGetDbgfOutputHlp}
850 */
851static DECLCALLBACK(PCDBGFINFOHLP) dbgcHlpGetDbgfOutputHlp(PDBGCCMDHLP pCmdHlp)
852{
853 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
854
855 /* Lazy init */
856 if (!pDbgc->DbgfOutputHlp.pfnPrintf)
857 {
858 pDbgc->DbgfOutputHlp.pfnPrintf = dbgcHlpGetDbgfOutputHlp_Printf;
859 pDbgc->DbgfOutputHlp.pfnPrintfV = dbgcHlpGetDbgfOutputHlp_PrintfV;
860 }
861
862 return &pDbgc->DbgfOutputHlp;
863}
864
865
866/**
867 * Initializes the Command Helpers for a DBGC instance.
868 *
869 * @param pDbgc Pointer to the DBGC instance.
870 */
871void dbgcInitCmdHlp(PDBGC pDbgc)
872{
873 pDbgc->CmdHlp.pfnWrite = dbgcHlpWrite;
874 pDbgc->CmdHlp.pfnPrintfV = dbgcHlpPrintfV;
875 pDbgc->CmdHlp.pfnPrintf = dbgcHlpPrintf;
876 pDbgc->CmdHlp.pfnVBoxErrorV = dbgcHlpVBoxErrorV;
877 pDbgc->CmdHlp.pfnVBoxError = dbgcHlpVBoxError;
878 pDbgc->CmdHlp.pfnMemRead = dbgcHlpMemRead;
879 pDbgc->CmdHlp.pfnMemWrite = dbgcHlpMemWrite;
880 pDbgc->CmdHlp.pfnEvalV = dbgcHlpEvalV;
881 pDbgc->CmdHlp.pfnExec = dbgcHlpExec;
882 pDbgc->CmdHlp.pfnFailV = dbgcHlpFailV;
883 pDbgc->CmdHlp.pfnVarToDbgfAddr = dbgcHlpVarToDbgfAddr;
884 pDbgc->CmdHlp.pfnVarToBool = dbgcHlpVarToBool;
885 pDbgc->CmdHlp.pfnVarGetRange = dbgcHlpVarGetRange;
886 pDbgc->CmdHlp.pfnGetDbgfOutputHlp = dbgcHlpGetDbgfOutputHlp;
887}
888
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