VirtualBox

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

Last change on this file since 31512 was 31510, checked in by vboxsync, 14 years ago

The debugger is back in the OSE.

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