VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFReg.cpp@ 35590

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

DBGFReg.cpp: formatting fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.7 KB
Line 
1/* $Id: DBGFReg.cpp 35590 2011-01-17 15:29:46Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Register Methods.
4 */
5
6/*
7 * Copyright (C) 2010-2011 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/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_DBGF
23#include <VBox/vmm/dbgf.h>
24#include "DBGFInternal.h"
25#include <VBox/vmm/mm.h>
26#include <VBox/vmm/vm.h>
27#include <VBox/param.h>
28#include <VBox/err.h>
29#include <VBox/log.h>
30#include <iprt/ctype.h>
31#include <iprt/string.h>
32#include <iprt/uint128.h>
33
34
35/*******************************************************************************
36* Defined Constants And Macros *
37*******************************************************************************/
38/** Locks the register database for writing. */
39#define DBGF_REG_DB_LOCK_WRITE(pVM) \
40 do { \
41 int rcSem = RTSemRWRequestWrite((pVM)->dbgf.s.hRegDbLock, RT_INDEFINITE_WAIT); \
42 AssertRC(rcSem); \
43 } while (0)
44
45/** Unlocks the register database after writing. */
46#define DBGF_REG_DB_UNLOCK_WRITE(pVM) \
47 do { \
48 int rcSem = RTSemRWReleaseWrite((pVM)->dbgf.s.hRegDbLock); \
49 AssertRC(rcSem); \
50 } while (0)
51
52/** Locks the register database for reading. */
53#define DBGF_REG_DB_LOCK_READ(pVM) \
54 do { \
55 int rcSem = RTSemRWRequestRead((pVM)->dbgf.s.hRegDbLock, RT_INDEFINITE_WAIT); \
56 AssertRC(rcSem); \
57 } while (0)
58
59/** Unlocks the register database after reading. */
60#define DBGF_REG_DB_UNLOCK_READ(pVM) \
61 do { \
62 int rcSem = RTSemRWReleaseRead((pVM)->dbgf.s.hRegDbLock); \
63 AssertRC(rcSem); \
64 } while (0)
65
66
67/** The max length of a set, register or sub-field name. */
68#define DBGF_REG_MAX_NAME 40
69
70
71/*******************************************************************************
72* Structures and Typedefs *
73*******************************************************************************/
74/**
75 * Register set registration record type.
76 */
77typedef enum DBGFREGSETTYPE
78{
79 /** Invalid zero value. */
80 DBGFREGSETTYPE_INVALID = 0,
81 /** CPU record. */
82 DBGFREGSETTYPE_CPU,
83 /** Device record. */
84 DBGFREGSETTYPE_DEVICE,
85 /** End of valid record types. */
86 DBGFREGSETTYPE_END
87} DBGFREGSETTYPE;
88
89
90/**
91 * Register set registration record.
92 */
93typedef struct DBGFREGSET
94{
95 /** String space core. */
96 RTSTRSPACECORE Core;
97 /** The registration record type. */
98 DBGFREGSETTYPE enmType;
99 /** The user argument for the callbacks. */
100 union
101 {
102 /** The CPU view. */
103 PVMCPU pVCpu;
104 /** The device view. */
105 PPDMDEVINS pDevIns;
106 /** The general view. */
107 void *pv;
108 } uUserArg;
109
110 /** The register descriptors. */
111 PCDBGFREGDESC paDescs;
112 /** The number of register descriptors. */
113 uint32_t cDescs;
114
115 /** Array of lookup records.
116 * The first part of the array runs parallel to paDescs, the rest are
117 * covering for aliases and bitfield variations. It's done this way to
118 * simplify the query all operations. */
119 struct DBGFREGLOOKUP *paLookupRecs;
120 /** The number of lookup records. */
121 uint32_t cLookupRecs;
122
123 /** The register name prefix. */
124 char szPrefix[1];
125} DBGFREGSET;
126/** Pointer to a register registration record. */
127typedef DBGFREGSET *PDBGFREGSET;
128/** Pointer to a const register registration record. */
129typedef DBGFREGSET const *PCDBGFREGSET;
130
131
132/**
133 * Register lookup record.
134 */
135typedef struct DBGFREGLOOKUP
136{
137 /** The string space core. */
138 RTSTRSPACECORE Core;
139 /** Pointer to the set. */
140 PCDBGFREGSET pSet;
141 /** Pointer to the register descriptor. */
142 PCDBGFREGDESC pDesc;
143 /** If an alias this points to the alias descriptor, NULL if not. */
144 PCDBGFREGALIAS pAlias;
145 /** If a sub-field this points to the sub-field descriptor, NULL if not. */
146 PCDBGFREGSUBFIELD pSubField;
147} DBGFREGLOOKUP;
148/** Pointer to a register lookup record. */
149typedef DBGFREGLOOKUP *PDBGFREGLOOKUP;
150/** Pointer to a const register lookup record. */
151typedef DBGFREGLOOKUP const *PCDBGFREGLOOKUP;
152
153
154/**
155 * Argument packet from DBGFR3RegNmQueryAll to dbgfR3RegNmQueryAllWorker.
156 */
157typedef struct DBGFR3REGNMQUERYALLARGS
158{
159 /** The output register array. */
160 PDBGFREGENTRYNM paRegs;
161 /** The number of entries in the output array. */
162 size_t cRegs;
163 /** The current register number when enumerating the string space. */
164 size_t iReg;
165} DBGFR3REGNMQUERYALLARGS;
166/** Pointer to a dbgfR3RegNmQueryAllWorker argument packet. */
167typedef DBGFR3REGNMQUERYALLARGS *PDBGFR3REGNMQUERYALLARGS;
168
169
170/**
171 * Argument packet passed by DBGFR3RegNmPrintfV to dbgfR3RegNmPrintfCbOutput
172 * and dbgfR3RegNmPrintfCbFormat.
173 */
174typedef struct DBGFR3REGNMPRINTFARGS
175{
176 /** The VM handle. */
177 PVM pVM;
178 /** The target CPU. */
179 VMCPUID idCpu;
180 /** The output buffer. */
181 char *pszBuf;
182 /** The format string. */
183 const char *pszFormat;
184 /** The va list with format arguments. */
185 va_list va;
186
187 /** The current buffer offset. */
188 size_t offBuf;
189 /** The amount of buffer space left, not counting the terminator char. */
190 size_t cchLeftBuf;
191 /** The status code of the whole operation. First error is return,
192 * subsequent ones are suppressed. */
193 int rc;
194} DBGFR3REGNMPRINTFARGS;
195/** Pointer to a DBGFR3RegNmPrintfV argument packet. */
196typedef DBGFR3REGNMPRINTFARGS *PDBGFR3REGNMPRINTFARGS;
197
198
199
200/**
201 * Initializes the register database.
202 *
203 * @returns VBox status code.
204 * @param pVM The VM handle.
205 */
206int dbgfR3RegInit(PVM pVM)
207{
208 int rc = VINF_SUCCESS;
209 if (!pVM->dbgf.s.fRegDbInitialized)
210 {
211 rc = RTSemRWCreate(&pVM->dbgf.s.hRegDbLock);
212 pVM->dbgf.s.fRegDbInitialized = RT_SUCCESS(rc);
213 }
214 return rc;
215}
216
217
218/**
219 * Terminates the register database.
220 *
221 * @param pVM The VM handle.
222 */
223void dbgfR3RegTerm(PVM pVM)
224{
225 RTSemRWDestroy(pVM->dbgf.s.hRegDbLock);
226 pVM->dbgf.s.hRegDbLock = NIL_RTSEMRW;
227 pVM->dbgf.s.fRegDbInitialized = false;
228}
229
230
231/**
232 * Validates a register name.
233 *
234 * This is used for prefixes, aliases and field names.
235 *
236 * @returns true if valid, false if not.
237 * @param pszName The register name to validate.
238 * @param chDot Set to '.' if accepted, otherwise 0.
239 */
240static bool dbgfR3RegIsNameValid(const char *pszName, char chDot)
241{
242 const char *psz = pszName;
243 if (!RT_C_IS_ALPHA(*psz))
244 return false;
245 char ch;
246 while ((ch = *++psz))
247 if ( !RT_C_IS_LOWER(ch)
248 && !RT_C_IS_DIGIT(ch)
249 && ch != '_'
250 && ch != chDot)
251 return false;
252 if (psz - pszName > DBGF_REG_MAX_NAME)
253 return false;
254 return true;
255}
256
257
258/**
259 * Common worker for registering a register set.
260 *
261 * @returns VBox status code.
262 * @param pVM The VM handle.
263 * @param paRegisters The register descriptors.
264 * @param enmType The set type.
265 * @param pvUserArg The user argument for the callbacks.
266 * @param pszPrefix The name prefix.
267 * @param iInstance The instance number to be appended to @a
268 * pszPrefix when creating the set name.
269 */
270static int dbgfR3RegRegisterCommon(PVM pVM, PCDBGFREGDESC paRegisters, DBGFREGSETTYPE enmType, void *pvUserArg, const char *pszPrefix, uint32_t iInstance)
271{
272 /*
273 * Validate input.
274 */
275 /* The name components. */
276 AssertMsgReturn(dbgfR3RegIsNameValid(pszPrefix, 0), ("%s\n", pszPrefix), VERR_INVALID_NAME);
277 const char *psz = RTStrEnd(pszPrefix, RTSTR_MAX);
278 bool const fNeedUnderscore = RT_C_IS_DIGIT(psz[-1]);
279 size_t const cchPrefix = psz - pszPrefix + fNeedUnderscore;
280 AssertMsgReturn(cchPrefix < RT_SIZEOFMEMB(DBGFREGSET, szPrefix) - 4 - 1, ("%s\n", pszPrefix), VERR_INVALID_NAME);
281
282 AssertMsgReturn(iInstance <= 9999, ("%d\n", iInstance), VERR_INVALID_NAME);
283
284 /* The descriptors. */
285 uint32_t cLookupRecs = 0;
286 uint32_t iDesc;
287 for (iDesc = 0; paRegisters[iDesc].pszName != NULL; iDesc++)
288 {
289 AssertMsgReturn(dbgfR3RegIsNameValid(paRegisters[iDesc].pszName, 0), ("%s (#%u)\n", paRegisters[iDesc].pszName, iDesc), VERR_INVALID_NAME);
290
291 if (enmType == DBGFREGSETTYPE_CPU)
292 AssertMsgReturn((unsigned)paRegisters[iDesc].enmReg == iDesc && iDesc < (unsigned)DBGFREG_END,
293 ("%d iDesc=%d\n", paRegisters[iDesc].enmReg, iDesc),
294 VERR_INVALID_PARAMETER);
295 else
296 AssertReturn(paRegisters[iDesc].enmReg == DBGFREG_END, VERR_INVALID_PARAMETER);
297 AssertReturn( paRegisters[iDesc].enmType > DBGFREGVALTYPE_INVALID
298 && paRegisters[iDesc].enmType < DBGFREGVALTYPE_END, VERR_INVALID_PARAMETER);
299 AssertMsgReturn(!(paRegisters[iDesc].fFlags & ~DBGFREG_FLAGS_READ_ONLY),
300 ("%#x (#%u)\n", paRegisters[iDesc].fFlags, iDesc),
301 VERR_INVALID_PARAMETER);
302 AssertPtrReturn(paRegisters[iDesc].pfnGet, VERR_INVALID_PARAMETER);
303 AssertPtrReturn(paRegisters[iDesc].pfnSet, VERR_INVALID_PARAMETER);
304
305 uint32_t iAlias = 0;
306 PCDBGFREGALIAS paAliases = paRegisters[iDesc].paAliases;
307 if (paAliases)
308 {
309 AssertPtrReturn(paAliases, VERR_INVALID_PARAMETER);
310 for (; paAliases[iAlias].pszName; iAlias++)
311 {
312 AssertMsgReturn(dbgfR3RegIsNameValid(paAliases[iAlias].pszName, 0), ("%s (%s)\n", paAliases[iAlias].pszName, paRegisters[iDesc].pszName), VERR_INVALID_NAME);
313 AssertReturn( paAliases[iAlias].enmType > DBGFREGVALTYPE_INVALID
314 && paAliases[iAlias].enmType < DBGFREGVALTYPE_END, VERR_INVALID_PARAMETER);
315 }
316 }
317
318 uint32_t iSubField = 0;
319 PCDBGFREGSUBFIELD paSubFields = paRegisters[iDesc].paSubFields;
320 if (paSubFields)
321 {
322 AssertPtrReturn(paSubFields, VERR_INVALID_PARAMETER);
323 for (; paSubFields[iSubField].pszName; iSubField++)
324 {
325 AssertMsgReturn(dbgfR3RegIsNameValid(paSubFields[iSubField].pszName, '.'), ("%s (%s)\n", paSubFields[iSubField].pszName, paRegisters[iDesc].pszName), VERR_INVALID_NAME);
326 AssertReturn(paSubFields[iSubField].iFirstBit + paSubFields[iSubField].cBits <= 128, VERR_INVALID_PARAMETER);
327 AssertReturn(paSubFields[iSubField].cBits + paSubFields[iSubField].cShift <= 128, VERR_INVALID_PARAMETER);
328 AssertPtrNullReturn(paSubFields[iSubField].pfnGet, VERR_INVALID_POINTER);
329 AssertPtrNullReturn(paSubFields[iSubField].pfnSet, VERR_INVALID_POINTER);
330 }
331 }
332
333 cLookupRecs += (1 + iAlias) * (1 + iSubField);
334 }
335
336 /* Check the instance number of the CPUs. */
337 AssertReturn(enmType != DBGFREGSETTYPE_CPU || iInstance < pVM->cCpus, VERR_INVALID_CPU_ID);
338
339 /*
340 * Allocate a new record and all associated lookup records.
341 */
342 size_t cbRegSet = RT_OFFSETOF(DBGFREGSET, szPrefix[cchPrefix + 4 + 1]);
343 cbRegSet = RT_ALIGN_Z(cbRegSet, 32);
344 size_t const offLookupRecArray = cbRegSet;
345 cbRegSet += cLookupRecs * sizeof(DBGFREGLOOKUP);
346
347 PDBGFREGSET pRegSet = (PDBGFREGSET)MMR3HeapAllocZ(pVM, MM_TAG_DBGF_REG, cbRegSet);
348 if (!pRegSet)
349 return VERR_NO_MEMORY;
350
351 /*
352 * Initialize the new record.
353 */
354 pRegSet->Core.pszString = pRegSet->szPrefix;
355 pRegSet->enmType = enmType;
356 pRegSet->uUserArg.pv = pvUserArg;
357 pRegSet->paDescs = paRegisters;
358 pRegSet->cDescs = iDesc;
359 pRegSet->cLookupRecs = cLookupRecs;
360 pRegSet->paLookupRecs = (PDBGFREGLOOKUP)((uintptr_t)pRegSet + offLookupRecArray);
361 if (fNeedUnderscore)
362 RTStrPrintf(pRegSet->szPrefix, cchPrefix + 4 + 1, "%s_%u", pszPrefix, iInstance);
363 else
364 RTStrPrintf(pRegSet->szPrefix, cchPrefix + 4 + 1, "%s%u", pszPrefix, iInstance);
365
366
367 /*
368 * Initialize the lookup records. See DBGFREGSET::paLookupRecs.
369 */
370 char szName[DBGF_REG_MAX_NAME * 3 + 16];
371 strcpy(szName, pRegSet->szPrefix);
372 char *pszReg = strchr(szName, '\0');
373 *pszReg++ = '.';
374
375 /* Array parallel to the descriptors. */
376 int rc = VINF_SUCCESS;
377 PDBGFREGLOOKUP pLookupRec = &pRegSet->paLookupRecs[0];
378 for (iDesc = 0; paRegisters[iDesc].pszName != NULL && RT_SUCCESS(rc); iDesc++)
379 {
380 strcpy(pszReg, paRegisters[iDesc].pszName);
381 pLookupRec->Core.pszString = MMR3HeapStrDup(pVM, MM_TAG_DBGF_REG, szName);
382 if (!pLookupRec->Core.pszString)
383 rc = VERR_NO_STR_MEMORY;
384 pLookupRec->pSet = pRegSet;
385 pLookupRec->pDesc = &paRegisters[iDesc];
386 pLookupRec->pAlias = NULL;
387 pLookupRec->pSubField = NULL;
388 pLookupRec++;
389 }
390
391 /* Aliases and sub-fields. */
392 for (iDesc = 0; paRegisters[iDesc].pszName != NULL && RT_SUCCESS(rc); iDesc++)
393 {
394 PCDBGFREGALIAS pCurAlias = NULL; /* first time we add sub-fields for the real name. */
395 PCDBGFREGALIAS pNextAlias = paRegisters[iDesc].paAliases;
396 const char *pszRegName = paRegisters[iDesc].pszName;
397 while (RT_SUCCESS(rc))
398 {
399 /* Add sub-field records. */
400 PCDBGFREGSUBFIELD paSubFields = paRegisters[iDesc].paSubFields;
401 if (paSubFields)
402 {
403 size_t cchReg = strlen(pszRegName);
404 memcpy(pszReg, pszRegName, cchReg);
405 char *pszSub = &pszReg[cchReg];
406 *pszSub++ = '.';
407 for (uint32_t iSubField = 0; paSubFields[iSubField].pszName && RT_SUCCESS(rc); iSubField++)
408 {
409 strcpy(pszSub, paSubFields[iSubField].pszName);
410 pLookupRec->Core.pszString = MMR3HeapStrDup(pVM, MM_TAG_DBGF_REG, szName);
411 if (!pLookupRec->Core.pszString)
412 rc = VERR_NO_STR_MEMORY;
413 pLookupRec->pSet = pRegSet;
414 pLookupRec->pDesc = &paRegisters[iDesc];
415 pLookupRec->pAlias = pCurAlias;
416 pLookupRec->pSubField = &paSubFields[iSubField];
417 pLookupRec++;
418 }
419 }
420
421 /* Advance to the next alias. */
422 pCurAlias = pNextAlias++;
423 if (!pCurAlias)
424 break;
425 pszRegName = pCurAlias->pszName;
426 if (!pszRegName)
427 break;
428
429 /* The alias record. */
430 strcpy(pszReg, pszRegName);
431 pLookupRec->Core.pszString = MMR3HeapStrDup(pVM, MM_TAG_DBGF_REG, szName);
432 if (!pLookupRec->Core.pszString)
433 rc = VERR_NO_STR_MEMORY;
434 pLookupRec->pSet = pRegSet;
435 pLookupRec->pDesc = &paRegisters[iDesc];
436 pLookupRec->pAlias = pCurAlias;
437 pLookupRec->pSubField = NULL;
438 pLookupRec++;
439 }
440 }
441 Assert(pLookupRec == &pRegSet->paLookupRecs[pRegSet->cLookupRecs]);
442
443 if (RT_SUCCESS(rc))
444 {
445 /*
446 * Insert the record into the register set string space and optionally into
447 * the CPU register set cache.
448 */
449 DBGF_REG_DB_LOCK_WRITE(pVM);
450
451 bool fInserted = RTStrSpaceInsert(&pVM->dbgf.s.RegSetSpace, &pRegSet->Core);
452 if (fInserted)
453 {
454 pVM->dbgf.s.cRegs += pRegSet->cDescs;
455 if (enmType == DBGFREGSETTYPE_CPU)
456 {
457 if (pRegSet->cDescs > DBGFREG_ALL_COUNT)
458 pVM->dbgf.s.cRegs -= pRegSet->cDescs - DBGFREG_ALL_COUNT;
459 pVM->aCpus[iInstance].dbgf.s.pRegSet = pRegSet;
460 }
461
462 PDBGFREGLOOKUP paLookupRecs = pRegSet->paLookupRecs;
463 uint32_t iLookupRec = pRegSet->cLookupRecs;
464 while (iLookupRec-- > 0)
465 {
466 bool fInserted2 = RTStrSpaceInsert(&pVM->dbgf.s.RegSpace, &paLookupRecs[iLookupRec].Core);
467 AssertMsg(fInserted2, ("'%s'", paLookupRecs[iLookupRec].Core.pszString));
468 }
469
470 DBGF_REG_DB_UNLOCK_WRITE(pVM);
471 return VINF_SUCCESS;
472 }
473
474 DBGF_REG_DB_UNLOCK_WRITE(pVM);
475 rc = VERR_DUPLICATE;
476 }
477
478 /*
479 * Bail out.
480 */
481 for (uint32_t i = 0; i < pRegSet->cLookupRecs; i++)
482 MMR3HeapFree((char *)pRegSet->paLookupRecs[i].Core.pszString);
483 MMR3HeapFree(pRegSet);
484
485 return rc;
486}
487
488
489/**
490 * Registers a set of registers for a CPU.
491 *
492 * @returns VBox status code.
493 * @param pVM The VM handle.
494 * @param pVCpu The virtual CPU handle.
495 * @param paRegisters The register descriptors.
496 */
497VMMR3_INT_DECL(int) DBGFR3RegRegisterCpu(PVM pVM, PVMCPU pVCpu, PCDBGFREGDESC paRegisters)
498{
499 if (!pVM->dbgf.s.fRegDbInitialized)
500 {
501 int rc = dbgfR3RegInit(pVM);
502 if (RT_FAILURE(rc))
503 return rc;
504 }
505
506 return dbgfR3RegRegisterCommon(pVM, paRegisters, DBGFREGSETTYPE_CPU, pVCpu, "cpu", pVCpu->idCpu);
507}
508
509
510/**
511 * Registers a set of registers for a device.
512 *
513 * @returns VBox status code.
514 * @param enmReg The register identifier.
515 * @param enmType The register type. This is for sort out
516 * aliases. Pass DBGFREGVALTYPE_INVALID to get
517 * the standard name.
518 */
519VMMR3DECL(int) DBGFR3RegRegisterDevice(PVM pVM, PCDBGFREGDESC paRegisters, PPDMDEVINS pDevIns, const char *pszPrefix, uint32_t iInstance)
520{
521 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
522 AssertPtrReturn(paRegisters, VERR_INVALID_POINTER);
523 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
524 AssertPtrReturn(pszPrefix, VERR_INVALID_POINTER);
525
526 return dbgfR3RegRegisterCommon(pVM, paRegisters, DBGFREGSETTYPE_DEVICE, pDevIns, pszPrefix, iInstance);
527}
528
529
530/**
531 * Clears the register value variable.
532 *
533 * @param pValue The variable to clear.
534 */
535DECLINLINE(void) dbgfR3RegValClear(PDBGFREGVAL pValue)
536{
537 pValue->au64[0] = 0;
538 pValue->au64[1] = 0;
539}
540
541
542/**
543 * Sets a 80-bit floating point variable to a 64-bit unsigned interger value.
544 *
545 * @param pValue The value.
546 * @param u64 The integer value.
547 */
548DECLINLINE(void) dbgfR3RegValR80SetU64(PDBGFREGVAL pValue, uint64_t u64)
549{
550 /** @todo fixme */
551 pValue->r80.s.fSign = 0;
552 pValue->r80.s.uExponent = 16383;
553 pValue->r80.s.u64Mantissa = u64;
554}
555
556
557/**
558 * Sets a 80-bit floating point variable to a 64-bit unsigned interger value.
559 *
560 * @param pValue The value.
561 * @param u128 The integer value.
562 */
563DECLINLINE(void) dbgfR3RegValR80SetU128(PDBGFREGVAL pValue, RTUINT128U u128)
564{
565 /** @todo fixme */
566 pValue->r80.s.fSign = 0;
567 pValue->r80.s.uExponent = 16383;
568 pValue->r80.s.u64Mantissa = u128.s.Lo;
569}
570
571
572/**
573 * Get a 80-bit floating point variable as a 64-bit unsigned integer.
574 *
575 * @returns 64-bit unsigned integer.
576 * @param pValue The value.
577 */
578DECLINLINE(uint64_t) dbgfR3RegValR80GetU64(PCDBGFREGVAL pValue)
579{
580 /** @todo stupid, stupid MSC. */
581 return pValue->r80.s.u64Mantissa;
582}
583
584
585/**
586 * Get a 80-bit floating point variable as a 128-bit unsigned integer.
587 *
588 * @returns 128-bit unsigned integer.
589 * @param pValue The value.
590 */
591DECLINLINE(RTUINT128U) dbgfR3RegValR80GetU128(PCDBGFREGVAL pValue)
592{
593 /** @todo stupid, stupid MSC. */
594 RTUINT128U uRet;
595#if 0
596 uRet.s.Lo = (uint64_t)InVal.lrd;
597 uRet.s.Hi = (uint64_t)InVal.lrd / _4G / _4G;
598#else
599 uRet.s.Lo = pValue->r80.s.u64Mantissa;
600 uRet.s.Hi = 0;
601#endif
602 return uRet;
603}
604
605
606/**
607 * Performs a cast between register value types.
608 *
609 * @retval VINF_SUCCESS
610 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
611 * @retval VINF_DBGF_TRUNCATED_REGISTER
612 * @retval VERR_DBGF_UNSUPPORTED_CAST
613 *
614 * @param pValue The value to cast (input + output).
615 * @param enmFromType The input value.
616 * @param enmToType The desired output value.
617 */
618static int dbgfR3RegValCast(PDBGFREGVAL pValue, DBGFREGVALTYPE enmFromType, DBGFREGVALTYPE enmToType)
619{
620 DBGFREGVAL const InVal = *pValue;
621 dbgfR3RegValClear(pValue);
622
623 /* Note! No default cases here as gcc warnings about missing enum values
624 are desired. */
625 switch (enmFromType)
626 {
627 case DBGFREGVALTYPE_U8:
628 switch (enmToType)
629 {
630 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u8; return VINF_SUCCESS;
631 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
632 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
633 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
634 case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
635 case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.u8); return VINF_DBGF_ZERO_EXTENDED_REGISTER;
636 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
637
638 case DBGFREGVALTYPE_32BIT_HACK:
639 case DBGFREGVALTYPE_END:
640 case DBGFREGVALTYPE_INVALID:
641 break;
642 }
643 break;
644
645 case DBGFREGVALTYPE_U16:
646 switch (enmToType)
647 {
648 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u16; return VINF_DBGF_TRUNCATED_REGISTER;
649 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u16; return VINF_SUCCESS;
650 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u16; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
651 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u16; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
652 case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.u16; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
653 case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.u16); return VINF_DBGF_ZERO_EXTENDED_REGISTER;
654 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
655
656 case DBGFREGVALTYPE_32BIT_HACK:
657 case DBGFREGVALTYPE_END:
658 case DBGFREGVALTYPE_INVALID:
659 break;
660 }
661 break;
662
663 case DBGFREGVALTYPE_U32:
664 switch (enmToType)
665 {
666 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u32; return VINF_DBGF_TRUNCATED_REGISTER;
667 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u32; return VINF_DBGF_TRUNCATED_REGISTER;
668 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u32; return VINF_SUCCESS;
669 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u32; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
670 case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.u32; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
671 case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.u32); return VINF_DBGF_ZERO_EXTENDED_REGISTER;
672 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
673
674 case DBGFREGVALTYPE_32BIT_HACK:
675 case DBGFREGVALTYPE_END:
676 case DBGFREGVALTYPE_INVALID:
677 break;
678 }
679 break;
680
681 case DBGFREGVALTYPE_U64:
682 switch (enmToType)
683 {
684 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
685 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
686 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
687 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u64; return VINF_SUCCESS;
688 case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
689 case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.u64); return VINF_DBGF_TRUNCATED_REGISTER;
690 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
691
692 case DBGFREGVALTYPE_32BIT_HACK:
693 case DBGFREGVALTYPE_END:
694 case DBGFREGVALTYPE_INVALID:
695 break;
696 }
697 break;
698
699 case DBGFREGVALTYPE_U128:
700 switch (enmToType)
701 {
702 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u128.s.Lo; return VINF_DBGF_TRUNCATED_REGISTER;
703 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u128.s.Lo; return VINF_DBGF_TRUNCATED_REGISTER;
704 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u128.s.Lo; return VINF_DBGF_TRUNCATED_REGISTER;
705 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u128.s.Lo; return VINF_DBGF_TRUNCATED_REGISTER;
706 case DBGFREGVALTYPE_U128: pValue->u128 = InVal.u128; return VINF_SUCCESS;
707 case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU128(pValue, InVal.u128); return VINF_DBGF_TRUNCATED_REGISTER;
708 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
709
710 case DBGFREGVALTYPE_32BIT_HACK:
711 case DBGFREGVALTYPE_END:
712 case DBGFREGVALTYPE_INVALID:
713 break;
714 }
715 break;
716
717 case DBGFREGVALTYPE_R80:
718 switch (enmToType)
719 {
720 case DBGFREGVALTYPE_U8: pValue->u8 = (uint8_t )dbgfR3RegValR80GetU64(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
721 case DBGFREGVALTYPE_U16: pValue->u16 = (uint16_t)dbgfR3RegValR80GetU64(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
722 case DBGFREGVALTYPE_U32: pValue->u32 = (uint32_t)dbgfR3RegValR80GetU64(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
723 case DBGFREGVALTYPE_U64: pValue->u64 = (uint64_t)dbgfR3RegValR80GetU64(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
724 case DBGFREGVALTYPE_U128: pValue->u128 = dbgfR3RegValR80GetU128(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
725 case DBGFREGVALTYPE_R80: pValue->r80 = InVal.r80; return VINF_SUCCESS;
726 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
727
728 case DBGFREGVALTYPE_32BIT_HACK:
729 case DBGFREGVALTYPE_END:
730 case DBGFREGVALTYPE_INVALID:
731 break;
732 }
733 break;
734
735 case DBGFREGVALTYPE_DTR:
736 switch (enmToType)
737 {
738 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
739 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
740 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
741 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
742 case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
743 case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.dtr.u64Base); return VINF_DBGF_TRUNCATED_REGISTER;
744 case DBGFREGVALTYPE_DTR: pValue->dtr = InVal.dtr; return VINF_SUCCESS;
745
746 case DBGFREGVALTYPE_32BIT_HACK:
747 case DBGFREGVALTYPE_END:
748 case DBGFREGVALTYPE_INVALID:
749 break;
750 }
751 break;
752
753 case DBGFREGVALTYPE_INVALID:
754 case DBGFREGVALTYPE_END:
755 case DBGFREGVALTYPE_32BIT_HACK:
756 break;
757 }
758
759 AssertMsgFailed(("%d / %d\n", enmFromType, enmToType));
760 return VERR_DBGF_UNSUPPORTED_CAST;
761}
762
763
764/**
765 * Worker for the CPU register queries.
766 *
767 * @returns VBox status code.
768 * @retval VINF_SUCCESS
769 * @retval VERR_INVALID_VM_HANDLE
770 * @retval VERR_INVALID_CPU_ID
771 * @retval VERR_DBGF_REGISTER_NOT_FOUND
772 * @retval VERR_DBGF_UNSUPPORTED_CAST
773 * @retval VINF_DBGF_TRUNCATED_REGISTER
774 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
775 *
776 * @param pVM The VM handle.
777 * @param idCpu The virtual CPU ID.
778 * @param enmReg The register to query.
779 * @param enmType The desired return type.
780 * @param pValue Where to return the register value.
781 */
782static DECLCALLBACK(int) dbgfR3RegCpuQueryWorker(PVM pVM, VMCPUID idCpu, DBGFREG enmReg, DBGFREGVALTYPE enmType, PDBGFREGVAL pValue)
783{
784 int rc = VINF_SUCCESS;
785 DBGF_REG_DB_LOCK_READ(pVM);
786
787 /*
788 * Look up the register set of the specified CPU.
789 */
790 PDBGFREGSET pSet = pVM->aCpus[idCpu].dbgf.s.pRegSet;
791 if (RT_LIKELY(pSet))
792 {
793 /*
794 * Look up the register and get the register value.
795 */
796 if (RT_LIKELY(pSet->cDescs > (size_t)enmReg))
797 {
798 PCDBGFREGDESC pDesc = &pSet->paDescs[enmReg];
799
800 pValue->au64[0] = pValue->au64[1] = 0;
801 rc = pDesc->pfnGet(pSet->uUserArg.pv, pDesc, pValue);
802 if (RT_SUCCESS(rc))
803 {
804 /*
805 * Do the cast if the desired return type doesn't match what
806 * the getter returned.
807 */
808 if (pDesc->enmType == enmType)
809 rc = VINF_SUCCESS;
810 else
811 rc = dbgfR3RegValCast(pValue, pDesc->enmType, enmType);
812 }
813 }
814 else
815 rc = VERR_DBGF_REGISTER_NOT_FOUND;
816 }
817 else
818 rc = VERR_INVALID_CPU_ID;
819
820 DBGF_REG_DB_UNLOCK_READ(pVM);
821 return rc;
822}
823
824
825/**
826 * Queries a 8-bit CPU register value.
827 *
828 * @retval VINF_SUCCESS
829 * @retval VERR_INVALID_VM_HANDLE
830 * @retval VERR_INVALID_CPU_ID
831 * @retval VERR_DBGF_REGISTER_NOT_FOUND
832 * @retval VERR_DBGF_UNSUPPORTED_CAST
833 * @retval VINF_DBGF_TRUNCATED_REGISTER
834 *
835 * @param pVM The VM handle.
836 * @param idCpu The target CPU ID.
837 * @param enmReg The register that's being queried.
838 * @param pu8 Where to store the register value.
839 */
840VMMR3DECL(int) DBGFR3RegCpuQueryU8(PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint8_t *pu8)
841{
842 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
843 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
844
845 DBGFREGVAL Value;
846 int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryWorker, 5, pVM, idCpu, enmReg, DBGFREGVALTYPE_U8, &Value);
847 if (RT_SUCCESS(rc))
848 *pu8 = Value.u8;
849 else
850 *pu8 = 0;
851
852 return rc;
853}
854
855
856/**
857 * Queries a 16-bit CPU register value.
858 *
859 * @retval VINF_SUCCESS
860 * @retval VERR_INVALID_VM_HANDLE
861 * @retval VERR_INVALID_CPU_ID
862 * @retval VERR_DBGF_REGISTER_NOT_FOUND
863 * @retval VERR_DBGF_UNSUPPORTED_CAST
864 * @retval VINF_DBGF_TRUNCATED_REGISTER
865 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
866 *
867 * @param pVM The VM handle.
868 * @param idCpu The target CPU ID.
869 * @param enmReg The register that's being queried.
870 * @param pu16 Where to store the register value.
871 */
872VMMR3DECL(int) DBGFR3RegCpuQueryU16(PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint16_t *pu16)
873{
874 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
875 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
876
877 DBGFREGVAL Value;
878 int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryWorker, 5, pVM, idCpu, enmReg, DBGFREGVALTYPE_U16, &Value);
879 if (RT_SUCCESS(rc))
880 *pu16 = Value.u16;
881 else
882 *pu16 = 0;
883
884 return rc;
885}
886
887
888/**
889 * Queries a 32-bit CPU register value.
890 *
891 * @retval VINF_SUCCESS
892 * @retval VERR_INVALID_VM_HANDLE
893 * @retval VERR_INVALID_CPU_ID
894 * @retval VERR_DBGF_REGISTER_NOT_FOUND
895 * @retval VERR_DBGF_UNSUPPORTED_CAST
896 * @retval VINF_DBGF_TRUNCATED_REGISTER
897 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
898 *
899 * @param pVM The VM handle.
900 * @param idCpu The target CPU ID.
901 * @param enmReg The register that's being queried.
902 * @param pu32 Where to store the register value.
903 */
904VMMR3DECL(int) DBGFR3RegCpuQueryU32(PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint32_t *pu32)
905{
906 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
907 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
908
909 DBGFREGVAL Value;
910 int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryWorker, 5, pVM, idCpu, enmReg, DBGFREGVALTYPE_U32, &Value);
911 if (RT_SUCCESS(rc))
912 *pu32 = Value.u32;
913 else
914 *pu32 = 0;
915
916 return rc;
917}
918
919
920/**
921 * Queries a 64-bit CPU register value.
922 *
923 * @retval VINF_SUCCESS
924 * @retval VERR_INVALID_VM_HANDLE
925 * @retval VERR_INVALID_CPU_ID
926 * @retval VERR_DBGF_REGISTER_NOT_FOUND
927 * @retval VERR_DBGF_UNSUPPORTED_CAST
928 * @retval VINF_DBGF_TRUNCATED_REGISTER
929 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
930 *
931 * @param pVM The VM handle.
932 * @param idCpu The target CPU ID.
933 * @param enmReg The register that's being queried.
934 * @param pu64 Where to store the register value.
935 */
936VMMR3DECL(int) DBGFR3RegCpuQueryU64(PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint64_t *pu64)
937{
938 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
939 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
940
941 DBGFREGVAL Value;
942 int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryWorker, 5, pVM, idCpu, enmReg, DBGFREGVALTYPE_U64, &Value);
943 if (RT_SUCCESS(rc))
944 *pu64 = Value.u64;
945 else
946 *pu64 = 0;
947
948 return rc;
949}
950
951
952/**
953 * Wrapper around CPUMQueryGuestMsr for dbgfR3RegCpuQueryBatchWorker.
954 *
955 * @retval VINF_SUCCESS
956 * @retval VERR_DBGF_REGISTER_NOT_FOUND
957 *
958 * @param pVCpu The current CPU.
959 * @param pReg The where to store the register value and
960 * size.
961 * @param idMsr The MSR to get.
962 */
963static void dbgfR3RegGetMsrBatch(PVMCPU pVCpu, PDBGFREGENTRY pReg, uint32_t idMsr)
964{
965 pReg->enmType = DBGFREGVALTYPE_U64;
966 int rc = CPUMQueryGuestMsr(pVCpu, idMsr, &pReg->Val.u64);
967 if (RT_FAILURE(rc))
968 {
969 AssertMsg(rc == VERR_CPUM_RAISE_GP_0, ("%Rrc\n", rc));
970 pReg->Val.u64 = 0;
971 }
972}
973
974
975static DECLCALLBACK(int) dbgfR3RegCpuQueryBatchWorker(PVM pVM, VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs)
976{
977#if 0
978 PVMCPU pVCpu = &pVM->aCpus[idCpu];
979 PCCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
980
981 PDBGFREGENTRY pReg = paRegs - 1;
982 while (cRegs-- > 0)
983 {
984 pReg++;
985 pReg->Val.au64[0] = 0;
986 pReg->Val.au64[1] = 0;
987
988 DBGFREG const enmReg = pReg->enmReg;
989 AssertMsgReturn(enmReg >= 0 && enmReg <= DBGFREG_END, ("%d (%#x)\n", enmReg, enmReg), VERR_DBGF_REGISTER_NOT_FOUND);
990 if (enmReg != DBGFREG_END)
991 {
992 PCDBGFREGDESC pDesc = &g_aDbgfRegDescs[enmReg];
993 if (!pDesc->pfnGet)
994 {
995 PCRTUINT128U pu = (PCRTUINT128U)((uintptr_t)pCtx + pDesc->offCtx);
996 pReg->enmType = pDesc->enmType;
997 switch (pDesc->enmType)
998 {
999 case DBGFREGVALTYPE_U8: pReg->Val.u8 = pu->au8[0]; break;
1000 case DBGFREGVALTYPE_U16: pReg->Val.u16 = pu->au16[0]; break;
1001 case DBGFREGVALTYPE_U32: pReg->Val.u32 = pu->au32[0]; break;
1002 case DBGFREGVALTYPE_U64: pReg->Val.u64 = pu->au64[0]; break;
1003 case DBGFREGVALTYPE_U128:
1004 pReg->Val.au64[0] = pu->au64[0];
1005 pReg->Val.au64[1] = pu->au64[1];
1006 break;
1007 case DBGFREGVALTYPE_R80:
1008 pReg->Val.au64[0] = pu->au64[0];
1009 pReg->Val.au16[5] = pu->au16[5];
1010 break;
1011 default:
1012 AssertMsgFailedReturn(("%s %d\n", pDesc->pszName, pDesc->enmType), VERR_INTERNAL_ERROR_3);
1013 }
1014 }
1015 else
1016 {
1017 int rc = pDesc->pfnGet(pVCpu, pDesc, pCtx, &pReg->Val.u);
1018 if (RT_FAILURE(rc))
1019 return rc;
1020 }
1021 }
1022 }
1023 return VINF_SUCCESS;
1024#else
1025 return VERR_NOT_IMPLEMENTED;
1026#endif
1027}
1028
1029
1030/**
1031 * Query a batch of registers.
1032 *
1033 * @retval VINF_SUCCESS
1034 * @retval VERR_INVALID_VM_HANDLE
1035 * @retval VERR_INVALID_CPU_ID
1036 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1037 *
1038 * @param pVM The VM handle.
1039 * @param idCpu The target CPU ID.
1040 * @param paRegs Pointer to an array of @a cRegs elements. On
1041 * input the enmReg members indicates which
1042 * registers to query. On successful return the
1043 * other members are set. DBGFREG_END can be used
1044 * as a filler.
1045 * @param cRegs The number of entries in @a paRegs.
1046 */
1047VMMR3DECL(int) DBGFR3RegCpuQueryBatch(PVM pVM, VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs)
1048{
1049 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1050 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
1051 if (!cRegs)
1052 return VINF_SUCCESS;
1053 AssertReturn(cRegs < _1M, VERR_OUT_OF_RANGE);
1054 AssertPtrReturn(paRegs, VERR_INVALID_POINTER);
1055 size_t iReg = cRegs;
1056 while (iReg-- > 0)
1057 {
1058 DBGFREG enmReg = paRegs[iReg].enmReg;
1059 AssertMsgReturn(enmReg < DBGFREG_END && enmReg >= DBGFREG_AL, ("%d (%#x)", enmReg, enmReg), VERR_DBGF_REGISTER_NOT_FOUND);
1060 }
1061
1062 return VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryBatchWorker, 4, pVM, idCpu, paRegs, cRegs);
1063}
1064
1065
1066/**
1067 * Query a all registers for a Virtual CPU.
1068 *
1069 * @retval VINF_SUCCESS
1070 * @retval VERR_INVALID_VM_HANDLE
1071 * @retval VERR_INVALID_CPU_ID
1072 *
1073 * @param pVM The VM handle.
1074 * @param idCpu The target CPU ID.
1075 * @param paRegs Pointer to an array of @a cRegs elements.
1076 * These will be filled with the CPU register
1077 * values. Overflowing entries will be set to
1078 * DBGFREG_END. The returned registers can be
1079 * accessed by using the DBGFREG values as index.
1080 * @param cRegs The number of entries in @a paRegs. The
1081 * recommended value is DBGFREG_ALL_COUNT.
1082 */
1083VMMR3DECL(int) DBGFR3RegCpuQueryAll(PVM pVM, VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs)
1084{
1085 /*
1086 * Validate input.
1087 */
1088 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1089 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
1090 if (!cRegs)
1091 return VINF_SUCCESS;
1092 AssertReturn(cRegs < _1M, VERR_OUT_OF_RANGE);
1093 AssertPtrReturn(paRegs, VERR_INVALID_POINTER);
1094
1095 /*
1096 * Convert it into a batch query (lazy bird).
1097 */
1098 unsigned iReg = 0;
1099 while (iReg < cRegs && iReg < DBGFREG_ALL_COUNT)
1100 {
1101 paRegs[iReg].enmReg = (DBGFREG)iReg;
1102 iReg++;
1103 }
1104 while (iReg < cRegs)
1105 paRegs[iReg++].enmReg = DBGFREG_END;
1106
1107 return VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryBatchWorker, 4, pVM, idCpu, paRegs, cRegs);
1108}
1109
1110
1111
1112/**
1113 * Gets the name of a register.
1114 *
1115 * @returns Pointer to read-only register name (lower case). NULL if the
1116 * parameters are invalid.
1117 *
1118 * @param pVM The VM handle.
1119 * @param enmReg The register identifier.
1120 * @param enmType The register type. This is for sort out
1121 * aliases. Pass DBGFREGVALTYPE_INVALID to get
1122 * the standard name.
1123 */
1124VMMR3DECL(const char *) DBGFR3RegCpuName(PVM pVM, DBGFREG enmReg, DBGFREGVALTYPE enmType)
1125{
1126 AssertReturn(enmReg >= DBGFREG_AL && enmReg < DBGFREG_END, NULL);
1127 AssertReturn(enmType >= DBGFREGVALTYPE_INVALID && enmType < DBGFREGVALTYPE_END, NULL);
1128 VM_ASSERT_VALID_EXT_RETURN(pVM, NULL);
1129
1130 PCDBGFREGSET pSet = pVM->aCpus[0].dbgf.s.pRegSet;
1131 if (RT_UNLIKELY(!pSet))
1132 return NULL;
1133
1134 PCDBGFREGDESC pDesc = &pSet->paDescs[enmReg];
1135 PCDBGFREGALIAS pAlias = pDesc->paAliases;
1136 if ( pAlias
1137 && pDesc->enmType != enmType
1138 && enmType != DBGFREGVALTYPE_INVALID)
1139 {
1140 while (pAlias->pszName)
1141 {
1142 if (pAlias->enmType == enmType)
1143 return pAlias->pszName;
1144 pAlias++;
1145 }
1146 }
1147
1148 return pDesc->pszName;
1149}
1150
1151
1152/**
1153 * Fold the string to lower case and copy it into the destination buffer.
1154 *
1155 * @returns Number of folder characters, -1 on overflow.
1156 * @param pszSrc The source string.
1157 * @param cchSrc How much to fold and copy.
1158 * @param pszDst The output buffer.
1159 * @param cbDst The size of the output buffer.
1160 */
1161static ssize_t dbgfR3RegCopyToLower(const char *pszSrc, size_t cchSrc, char *pszDst, size_t cbDst)
1162{
1163 ssize_t cchFolded = 0;
1164 char ch;
1165 while (cchSrc-- > 0 && (ch = *pszSrc++))
1166 {
1167 if (RT_UNLIKELY(cbDst <= 1))
1168 return -1;
1169 cbDst--;
1170
1171 char chLower = RT_C_TO_LOWER(ch);
1172 cchFolded += chLower != ch;
1173 *pszDst++ = chLower;
1174 }
1175 if (RT_UNLIKELY(!cbDst))
1176 return -1;
1177 *pszDst = '\0';
1178 return cchFolded;
1179}
1180
1181
1182/**
1183 * Resolves the register name.
1184 *
1185 * @returns Lookup record.
1186 * @param pVM The VM handle.
1187 * @param idDefCpu The default CPU ID set.
1188 * @param pszReg The register name.
1189 */
1190static PCDBGFREGLOOKUP dbgfR3RegResolve(PVM pVM, VMCPUID idDefCpu, const char *pszReg)
1191{
1192 DBGF_REG_DB_LOCK_READ(pVM);
1193
1194 /* Try looking up the name without any case folding or cpu prefixing. */
1195 PCDBGFREGLOOKUP pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(&pVM->dbgf.s.RegSpace, pszReg);
1196 if (!pLookupRec)
1197 {
1198 char szName[DBGF_REG_MAX_NAME * 4 + 16];
1199
1200 /* Lower case it and try again. */
1201 ssize_t cchFolded = dbgfR3RegCopyToLower(pszReg, RTSTR_MAX, szName, sizeof(szName) - DBGF_REG_MAX_NAME);
1202 if (cchFolded > 0)
1203 pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(&pVM->dbgf.s.RegSpace, szName);
1204 if ( !pLookupRec
1205 && cchFolded >= 0
1206 && idDefCpu != VMCPUID_ANY)
1207 {
1208 /* Prefix it with the specified CPU set. */
1209 size_t cchCpuSet = RTStrPrintf(szName, sizeof(szName), "cpu%u.", idDefCpu);
1210 dbgfR3RegCopyToLower(pszReg, RTSTR_MAX, &szName[cchCpuSet], sizeof(szName) - cchCpuSet);
1211 pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(&pVM->dbgf.s.RegSpace, szName);
1212 }
1213 }
1214
1215 DBGF_REG_DB_UNLOCK_READ(pVM);
1216 return pLookupRec;
1217}
1218
1219
1220/**
1221 * On CPU worker for the register queries, used by dbgfR3RegNmQueryWorker and
1222 * dbgfR3RegNmPrintfCbFormatNormal.
1223 *
1224 * @returns VBox status code.
1225 *
1226 * @param pVM The VM handle.
1227 * @param pLookupRec The register lookup record.
1228 * @param enmType The desired return type.
1229 * @param pValue Where to return the register value.
1230 * @param penmType Where to store the register value type.
1231 * Optional.
1232 */
1233static DECLCALLBACK(int) dbgfR3RegNmQueryWorkerOnCpu(PVM pVM, PCDBGFREGLOOKUP pLookupRec, DBGFREGVALTYPE enmType,
1234 PDBGFREGVAL pValue, PDBGFREGVALTYPE penmType)
1235{
1236 PCDBGFREGDESC pDesc = pLookupRec->pDesc;
1237 PCDBGFREGSET pSet = pLookupRec->pSet;
1238 PCDBGFREGSUBFIELD pSubField = pLookupRec->pSubField;
1239 DBGFREGVALTYPE enmValueType = pDesc->enmType;
1240 int rc;
1241
1242 /*
1243 * Get the register or sub-field value.
1244 */
1245 dbgfR3RegValClear(pValue);
1246 if (!pSubField)
1247 {
1248 rc = pDesc->pfnGet(pSet->uUserArg.pv, pDesc, pValue);
1249 if ( pLookupRec->pAlias
1250 && pLookupRec->pAlias->enmType != enmValueType
1251 && RT_SUCCESS(rc))
1252 {
1253 rc = dbgfR3RegValCast(pValue, enmValueType, pLookupRec->pAlias->enmType);
1254 enmValueType = pLookupRec->pAlias->enmType;
1255 }
1256 }
1257 else
1258 {
1259 if (pSubField->pfnGet)
1260 {
1261 rc = pSubField->pfnGet(pSet->uUserArg.pv, pSubField, &pValue->u128);
1262 enmValueType = DBGFREGVALTYPE_U128;
1263 }
1264 else
1265 {
1266 rc = pDesc->pfnGet(pSet->uUserArg.pv, pDesc, pValue);
1267 if ( pLookupRec->pAlias
1268 && pLookupRec->pAlias->enmType != enmValueType
1269 && RT_SUCCESS(rc))
1270 {
1271 rc = dbgfR3RegValCast(pValue, enmValueType, pLookupRec->pAlias->enmType);
1272 enmValueType = pLookupRec->pAlias->enmType;
1273 }
1274 if (RT_SUCCESS(rc))
1275 {
1276 rc = dbgfR3RegValCast(pValue, enmValueType, DBGFREGVALTYPE_U128);
1277 if (RT_SUCCESS(rc))
1278 {
1279 RTUInt128AssignShiftLeft(&pValue->u128, -pSubField->iFirstBit);
1280 RTUInt128AssignAndNFirstBits(&pValue->u128, pSubField->cBits);
1281 if (pSubField->cShift)
1282 RTUInt128AssignShiftLeft(&pValue->u128, pSubField->cShift);
1283 }
1284 }
1285 }
1286 if (RT_SUCCESS(rc))
1287 {
1288 unsigned const cBits = pSubField->cBits + pSubField->cShift;
1289 if (cBits <= 8)
1290 enmValueType = DBGFREGVALTYPE_U8;
1291 else if (cBits <= 16)
1292 enmValueType = DBGFREGVALTYPE_U16;
1293 else if (cBits <= 32)
1294 enmValueType = DBGFREGVALTYPE_U32;
1295 else if (cBits <= 64)
1296 enmValueType = DBGFREGVALTYPE_U64;
1297 else
1298 enmValueType = DBGFREGVALTYPE_U128;
1299 rc = dbgfR3RegValCast(pValue, DBGFREGVALTYPE_U128, enmValueType);
1300 }
1301 }
1302 if (RT_SUCCESS(rc))
1303 {
1304 /*
1305 * Do the cast if the desired return type doesn't match what
1306 * the getter returned.
1307 */
1308 if ( enmValueType == enmType
1309 || enmType == DBGFREGVALTYPE_END)
1310 {
1311 rc = VINF_SUCCESS;
1312 if (penmType)
1313 *penmType = enmValueType;
1314 }
1315 else
1316 {
1317 rc = dbgfR3RegValCast(pValue, enmValueType, enmType);
1318 if (penmType)
1319 *penmType = RT_SUCCESS(rc) ? enmType : enmValueType;
1320 }
1321 }
1322
1323 return rc;
1324}
1325
1326
1327/**
1328 * Worker for the register queries.
1329 *
1330 * @returns VBox status code.
1331 * @retval VINF_SUCCESS
1332 * @retval VERR_INVALID_VM_HANDLE
1333 * @retval VERR_INVALID_CPU_ID
1334 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1335 * @retval VERR_DBGF_UNSUPPORTED_CAST
1336 * @retval VINF_DBGF_TRUNCATED_REGISTER
1337 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1338 *
1339 * @param pVM The VM handle.
1340 * @param idDefCpu The virtual CPU ID for the default CPU register
1341 * set.
1342 * @param pszReg The register to query.
1343 * @param enmType The desired return type.
1344 * @param pValue Where to return the register value.
1345 * @param penmType Where to store the register value type.
1346 * Optional.
1347 */
1348static int dbgfR3RegNmQueryWorker(PVM pVM, VMCPUID idDefCpu, const char *pszReg, DBGFREGVALTYPE enmType,
1349 PDBGFREGVAL pValue, PDBGFREGVALTYPE penmType)
1350{
1351 /*
1352 * Validate input.
1353 */
1354 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1355 AssertReturn(idDefCpu < pVM->cCpus || idDefCpu == VMCPUID_ANY, VERR_INVALID_CPU_ID);
1356 AssertPtrReturn(pszReg, VERR_INVALID_POINTER);
1357
1358 Assert(enmType > DBGFREGVALTYPE_INVALID && enmType <= DBGFREGVALTYPE_END);
1359 AssertPtr(pValue);
1360
1361 /*
1362 * Resolve the register and call the getter on the relevant CPU.
1363 */
1364 PCDBGFREGLOOKUP pLookupRec = dbgfR3RegResolve(pVM, idDefCpu, pszReg);
1365 if (pLookupRec)
1366 {
1367 if (pLookupRec->pSet->enmType == DBGFREGSETTYPE_CPU)
1368 idDefCpu = pLookupRec->pSet->uUserArg.pVCpu->idCpu;
1369 return VMR3ReqCallWait(pVM, idDefCpu, (PFNRT)dbgfR3RegNmQueryWorkerOnCpu, 5, pVM, pLookupRec, enmType, pValue, penmType);
1370 }
1371 return VERR_DBGF_REGISTER_NOT_FOUND;
1372}
1373
1374
1375/**
1376 * Queries a descriptor table register value.
1377 *
1378 * @retval VINF_SUCCESS
1379 * @retval VERR_INVALID_VM_HANDLE
1380 * @retval VERR_INVALID_CPU_ID
1381 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1382 *
1383 * @param pVM The VM handle.
1384 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
1385 * applicable.
1386 * @param pszReg The register that's being queried. Except for
1387 * CPU registers, this must be on the form
1388 * "set.reg[.sub]".
1389 * @param pValue Where to store the register value.
1390 * @param penmType Where to store the register value type.
1391 */
1392VMMR3DECL(int) DBGFR3RegNmQuery(PVM pVM, VMCPUID idDefCpu, const char *pszReg, PDBGFREGVAL pValue, PDBGFREGVALTYPE penmType)
1393{
1394 return dbgfR3RegNmQueryWorker(pVM, idDefCpu, pszReg, DBGFREGVALTYPE_END, pValue, penmType);
1395}
1396
1397
1398/**
1399 * Queries a 8-bit register value.
1400 *
1401 * @retval VINF_SUCCESS
1402 * @retval VERR_INVALID_VM_HANDLE
1403 * @retval VERR_INVALID_CPU_ID
1404 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1405 * @retval VERR_DBGF_UNSUPPORTED_CAST
1406 * @retval VINF_DBGF_TRUNCATED_REGISTER
1407 *
1408 * @param pVM The VM handle.
1409 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
1410 * applicable.
1411 * @param pszReg The register that's being queried. Except for
1412 * CPU registers, this must be on the form
1413 * "set.reg[.sub]".
1414 * @param pu8 Where to store the register value.
1415 */
1416VMMR3DECL(int) DBGFR3RegNmQueryU8(PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint8_t *pu8)
1417{
1418 DBGFREGVAL Value;
1419 int rc = dbgfR3RegNmQueryWorker(pVM, idDefCpu, pszReg, DBGFREGVALTYPE_U8, &Value, NULL);
1420 if (RT_SUCCESS(rc))
1421 *pu8 = Value.u8;
1422 else
1423 *pu8 = 0;
1424 return rc;
1425}
1426
1427
1428/**
1429 * Queries a 16-bit register value.
1430 *
1431 * @retval VINF_SUCCESS
1432 * @retval VERR_INVALID_VM_HANDLE
1433 * @retval VERR_INVALID_CPU_ID
1434 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1435 * @retval VERR_DBGF_UNSUPPORTED_CAST
1436 * @retval VINF_DBGF_TRUNCATED_REGISTER
1437 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1438 *
1439 * @param pVM The VM handle.
1440 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
1441 * applicable.
1442 * @param pszReg The register that's being queried. Except for
1443 * CPU registers, this must be on the form
1444 * "set.reg[.sub]".
1445 * @param pu16 Where to store the register value.
1446 */
1447VMMR3DECL(int) DBGFR3RegNmQueryU16(PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint16_t *pu16)
1448{
1449 DBGFREGVAL Value;
1450 int rc = dbgfR3RegNmQueryWorker(pVM, idDefCpu, pszReg, DBGFREGVALTYPE_U16, &Value, NULL);
1451 if (RT_SUCCESS(rc))
1452 *pu16 = Value.u16;
1453 else
1454 *pu16 = 0;
1455 return rc;
1456}
1457
1458
1459/**
1460 * Queries a 32-bit register value.
1461 *
1462 * @retval VINF_SUCCESS
1463 * @retval VERR_INVALID_VM_HANDLE
1464 * @retval VERR_INVALID_CPU_ID
1465 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1466 * @retval VERR_DBGF_UNSUPPORTED_CAST
1467 * @retval VINF_DBGF_TRUNCATED_REGISTER
1468 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1469 *
1470 * @param pVM The VM handle.
1471 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
1472 * applicable.
1473 * @param pszReg The register that's being queried. Except for
1474 * CPU registers, this must be on the form
1475 * "set.reg[.sub]".
1476 * @param pu32 Where to store the register value.
1477 */
1478VMMR3DECL(int) DBGFR3RegNmQueryU32(PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint32_t *pu32)
1479{
1480 DBGFREGVAL Value;
1481 int rc = dbgfR3RegNmQueryWorker(pVM, idDefCpu, pszReg, DBGFREGVALTYPE_U32, &Value, NULL);
1482 if (RT_SUCCESS(rc))
1483 *pu32 = Value.u32;
1484 else
1485 *pu32 = 0;
1486 return rc;
1487}
1488
1489
1490/**
1491 * Queries a 64-bit register value.
1492 *
1493 * @retval VINF_SUCCESS
1494 * @retval VERR_INVALID_VM_HANDLE
1495 * @retval VERR_INVALID_CPU_ID
1496 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1497 * @retval VERR_DBGF_UNSUPPORTED_CAST
1498 * @retval VINF_DBGF_TRUNCATED_REGISTER
1499 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1500 *
1501 * @param pVM The VM handle.
1502 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
1503 * applicable.
1504 * @param pszReg The register that's being queried. Except for
1505 * CPU registers, this must be on the form
1506 * "set.reg[.sub]".
1507 * @param pu64 Where to store the register value.
1508 */
1509VMMR3DECL(int) DBGFR3RegNmQueryU64(PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64)
1510{
1511 DBGFREGVAL Value;
1512 int rc = dbgfR3RegNmQueryWorker(pVM, idDefCpu, pszReg, DBGFREGVALTYPE_U64, &Value, NULL);
1513 if (RT_SUCCESS(rc))
1514 *pu64 = Value.u64;
1515 else
1516 *pu64 = 0;
1517 return rc;
1518}
1519
1520
1521/**
1522 * Queries a 128-bit register value.
1523 *
1524 * @retval VINF_SUCCESS
1525 * @retval VERR_INVALID_VM_HANDLE
1526 * @retval VERR_INVALID_CPU_ID
1527 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1528 * @retval VERR_DBGF_UNSUPPORTED_CAST
1529 * @retval VINF_DBGF_TRUNCATED_REGISTER
1530 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1531 *
1532 * @param pVM The VM handle.
1533 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
1534 * applicable.
1535 * @param pszReg The register that's being queried. Except for
1536 * CPU registers, this must be on the form
1537 * "set.reg[.sub]".
1538 * @param pu128 Where to store the register value.
1539 */
1540VMMR3DECL(int) DBGFR3RegNmQueryU128(PVM pVM, VMCPUID idDefCpu, const char *pszReg, PRTUINT128U pu128)
1541{
1542 DBGFREGVAL Value;
1543 int rc = dbgfR3RegNmQueryWorker(pVM, idDefCpu, pszReg, DBGFREGVALTYPE_U128, &Value, NULL);
1544 if (RT_SUCCESS(rc))
1545 *pu128 = Value.u128;
1546 else
1547 pu128->s.Hi = pu128->s.Lo = 0;
1548 return rc;
1549}
1550
1551
1552#if 0
1553/**
1554 * Queries a long double register value.
1555 *
1556 * @retval VINF_SUCCESS
1557 * @retval VERR_INVALID_VM_HANDLE
1558 * @retval VERR_INVALID_CPU_ID
1559 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1560 * @retval VERR_DBGF_UNSUPPORTED_CAST
1561 * @retval VINF_DBGF_TRUNCATED_REGISTER
1562 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1563 *
1564 * @param pVM The VM handle.
1565 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
1566 * applicable.
1567 * @param pszReg The register that's being queried. Except for
1568 * CPU registers, this must be on the form
1569 * "set.reg[.sub]".
1570 * @param plrd Where to store the register value.
1571 */
1572VMMR3DECL(int) DBGFR3RegNmQueryLrd(PVM pVM, VMCPUID idDefCpu, const char *pszReg, long double *plrd)
1573{
1574 DBGFREGVAL Value;
1575 int rc = dbgfR3RegNmQueryWorker(pVM, idDefCpu, pszReg, DBGFREGVALTYPE_R80, &Value, NULL);
1576 if (RT_SUCCESS(rc))
1577 *plrd = Value.lrd;
1578 else
1579 *plrd = 0;
1580 return rc;
1581}
1582#endif
1583
1584
1585/**
1586 * Queries a descriptor table register value.
1587 *
1588 * @retval VINF_SUCCESS
1589 * @retval VERR_INVALID_VM_HANDLE
1590 * @retval VERR_INVALID_CPU_ID
1591 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1592 * @retval VERR_DBGF_UNSUPPORTED_CAST
1593 * @retval VINF_DBGF_TRUNCATED_REGISTER
1594 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1595 *
1596 * @param pVM The VM handle.
1597 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
1598 * applicable.
1599 * @param pszReg The register that's being queried. Except for
1600 * CPU registers, this must be on the form
1601 * "set.reg[.sub]".
1602 * @param pu64Base Where to store the register base value.
1603 * @param pu32Limit Where to store the register limit value.
1604 */
1605VMMR3DECL(int) DBGFR3RegNmQueryXdtr(PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64Base, uint32_t *pu32Limit)
1606{
1607 DBGFREGVAL Value;
1608 int rc = dbgfR3RegNmQueryWorker(pVM, idDefCpu, pszReg, DBGFREGVALTYPE_DTR, &Value, NULL);
1609 if (RT_SUCCESS(rc))
1610 {
1611 *pu64Base = Value.dtr.u64Base;
1612 *pu32Limit = Value.dtr.u32Limit;
1613 }
1614 else
1615 {
1616 *pu64Base = 0;
1617 *pu32Limit = 0;
1618 }
1619 return rc;
1620}
1621
1622
1623/// @todo VMMR3DECL(int) DBGFR3RegNmQueryBatch(PVM pVM,VMCPUID idDefCpu, DBGFREGENTRYNM paRegs, size_t cRegs);
1624
1625
1626/**
1627 * Gets the number of registers returned by DBGFR3RegNmQueryAll.
1628 *
1629 * @returns VBox status code.
1630 * @param pVM The VM handle.
1631 * @param pcRegs Where to return the register count.
1632 */
1633VMMR3DECL(int) DBGFR3RegNmQueryAllCount(PVM pVM, size_t *pcRegs)
1634{
1635 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1636 *pcRegs = pVM->dbgf.s.cRegs;
1637 return VINF_SUCCESS;
1638}
1639
1640
1641/**
1642 * Pad register entries.
1643 *
1644 * @param paRegs The output array.
1645 * @param cRegs The size of the output array.
1646 * @param iReg The first register to pad.
1647 * @param cRegsToPad The number of registers to pad.
1648 */
1649static void dbgfR3RegNmQueryAllPadEntries(PDBGFREGENTRYNM paRegs, size_t cRegs, size_t iReg, size_t cRegsToPad)
1650{
1651 if (iReg < cRegs)
1652 {
1653 size_t iEndReg = iReg + cRegsToPad;
1654 if (iEndReg > cRegs)
1655 iEndReg = cRegs;
1656 while (iReg < iEndReg)
1657 {
1658 paRegs[iReg].pszName = NULL;
1659 paRegs[iReg].enmType = DBGFREGVALTYPE_END;
1660 dbgfR3RegValClear(&paRegs[iReg].Val);
1661 iReg++;
1662 }
1663 }
1664}
1665
1666
1667/**
1668 * Query all registers in a set.
1669 *
1670 * @param pSet The set.
1671 * @param cRegsToQuery The number of registers to query.
1672 * @param paRegs The output array.
1673 * @param cRegs The size of the output array.
1674 */
1675static void dbgfR3RegNmQueryAllInSet(PCDBGFREGSET pSet, size_t cRegsToQuery, PDBGFREGENTRYNM paRegs, size_t cRegs)
1676{
1677 int rc = VINF_SUCCESS;
1678
1679 if (cRegsToQuery > pSet->cDescs)
1680 cRegsToQuery = pSet->cDescs;
1681 if (cRegsToQuery > cRegs)
1682 cRegsToQuery = cRegs;
1683
1684 for (size_t iReg = 0; iReg < cRegsToQuery; iReg++)
1685 {
1686 paRegs[iReg].enmType = pSet->paDescs[iReg].enmType;
1687 paRegs[iReg].pszName = pSet->paLookupRecs[iReg].Core.pszString;
1688 dbgfR3RegValClear(&paRegs[iReg].Val);
1689 int rc2 = pSet->paDescs[iReg].pfnGet(pSet->uUserArg.pv, &pSet->paDescs[iReg], &paRegs[iReg].Val);
1690 AssertRCSuccess(rc2);
1691 if (RT_FAILURE(rc2))
1692 dbgfR3RegValClear(&paRegs[iReg].Val);
1693 }
1694}
1695
1696
1697/**
1698 * @callback_method_impl{FNRTSTRSPACECALLBACK, Worker used by
1699 * dbgfR3RegNmQueryAllWorker}
1700 */
1701static DECLCALLBACK(int) dbgfR3RegNmQueryAllEnum(PRTSTRSPACECORE pStr, void *pvUser)
1702{
1703 PCDBGFREGSET pSet = (PCDBGFREGSET)pStr;
1704 if (pSet->enmType != DBGFREGSETTYPE_CPU)
1705 {
1706 PDBGFR3REGNMQUERYALLARGS pArgs = (PDBGFR3REGNMQUERYALLARGS)pvUser;
1707 if (pArgs->iReg < pArgs->cRegs)
1708 dbgfR3RegNmQueryAllInSet(pSet, pSet->cDescs, &pArgs->paRegs[pArgs->iReg], pArgs->cRegs - pArgs->iReg);
1709 pArgs->iReg += pSet->cDescs;
1710 }
1711
1712 return 0;
1713}
1714
1715
1716/**
1717 * @callback_method_impl{FNVMMEMTRENDEZVOUS, Worker used by DBGFR3RegNmQueryAll}
1718 */
1719static DECLCALLBACK(VBOXSTRICTRC) dbgfR3RegNmQueryAllWorker(PVM pVM, PVMCPU pVCpu, void *pvUser)
1720{
1721 PDBGFR3REGNMQUERYALLARGS pArgs = (PDBGFR3REGNMQUERYALLARGS)pvUser;
1722 PDBGFREGENTRYNM paRegs = pArgs->paRegs;
1723 size_t const cRegs = pArgs->cRegs;
1724
1725 DBGF_REG_DB_LOCK_READ(pVM);
1726
1727 /*
1728 * My CPU registers.
1729 */
1730 size_t iCpuReg = pVCpu->idCpu * DBGFREG_ALL_COUNT;
1731 if (pVCpu->dbgf.s.pRegSet)
1732 {
1733 if (iCpuReg < cRegs)
1734 dbgfR3RegNmQueryAllInSet(pVCpu->dbgf.s.pRegSet, DBGFREG_ALL_COUNT, &paRegs[iCpuReg], cRegs - iCpuReg);
1735 }
1736 else
1737 dbgfR3RegNmQueryAllPadEntries(paRegs, cRegs, iCpuReg, DBGFREG_ALL_COUNT);
1738
1739 /*
1740 * The primary CPU does all the other registers.
1741 */
1742 if (pVCpu->idCpu == 0)
1743 {
1744 pArgs->iReg = pVM->cCpus * DBGFREG_ALL_COUNT;
1745 RTStrSpaceEnumerate(&pVM->dbgf.s.RegSetSpace, dbgfR3RegNmQueryAllEnum, pArgs);
1746 dbgfR3RegNmQueryAllPadEntries(paRegs, cRegs, pArgs->iReg, cRegs);
1747 }
1748
1749 DBGF_REG_DB_UNLOCK_READ(pVM);
1750 return VINF_SUCCESS; /* Ignore errors. */
1751}
1752
1753
1754/**
1755 * Queries all register.
1756 *
1757 * @returns VBox status code.
1758 * @param pVM The VM handle.
1759 * @param paRegs The output register value array. The register
1760 * name string is read only and shall not be freed
1761 * or modified.
1762 * @param cRegs The number of entries in @a paRegs. The
1763 * correct size can be obtained by calling
1764 * DBGFR3RegNmQueryAllCount.
1765 */
1766VMMR3DECL(int) DBGFR3RegNmQueryAll(PVM pVM, PDBGFREGENTRYNM paRegs, size_t cRegs)
1767{
1768 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1769 AssertPtrReturn(paRegs, VERR_INVALID_POINTER);
1770 AssertReturn(cRegs > 0, VERR_OUT_OF_RANGE);
1771
1772 DBGFR3REGNMQUERYALLARGS Args;
1773 Args.paRegs = paRegs;
1774 Args.cRegs = cRegs;
1775
1776 return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3RegNmQueryAllWorker, &Args);
1777}
1778
1779
1780/**
1781 * Internal worker for DBGFR3RegFormatValue, cbTmp is sufficent.
1782 *
1783 * @copydoc DBGFR3RegFormatValue
1784 */
1785DECLINLINE(ssize_t) dbgfR3RegFormatValueInt(char *pszTmp, size_t cbTmp, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType,
1786 unsigned uBase, signed int cchWidth, signed int cchPrecision, uint32_t fFlags)
1787{
1788 switch (enmType)
1789 {
1790 case DBGFREGVALTYPE_U8:
1791 return RTStrFormatU8(pszTmp, cbTmp, pValue->u8, uBase, cchWidth, cchPrecision, fFlags);
1792 case DBGFREGVALTYPE_U16:
1793 return RTStrFormatU16(pszTmp, cbTmp, pValue->u16, uBase, cchWidth, cchPrecision, fFlags);
1794 case DBGFREGVALTYPE_U32:
1795 return RTStrFormatU32(pszTmp, cbTmp, pValue->u32, uBase, cchWidth, cchPrecision, fFlags);
1796 case DBGFREGVALTYPE_U64:
1797 return RTStrFormatU64(pszTmp, cbTmp, pValue->u64, uBase, cchWidth, cchPrecision, fFlags);
1798 case DBGFREGVALTYPE_U128:
1799 return RTStrFormatU128(pszTmp, cbTmp, &pValue->u128, uBase, cchWidth, cchPrecision, fFlags);
1800 case DBGFREGVALTYPE_R80:
1801 return RTStrFormatR80u2(pszTmp, cbTmp, &pValue->r80, cchWidth, cchPrecision, fFlags);
1802 case DBGFREGVALTYPE_DTR:
1803 {
1804 ssize_t cch = RTStrFormatU64(pszTmp, cbTmp, pValue->dtr.u64Base,
1805 16, 2+16, 0, RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD);
1806 AssertReturn(cch > 0, VERR_INTERNAL_ERROR_4);
1807 pszTmp[cch++] = ':';
1808 cch += RTStrFormatU64(&pszTmp[cch], cbTmp - cch, pValue->dtr.u32Limit,
1809 16, 4, 0, RTSTR_F_ZEROPAD | RTSTR_F_32BIT);
1810 return cch;
1811 }
1812
1813 case DBGFREGVALTYPE_32BIT_HACK:
1814 case DBGFREGVALTYPE_END:
1815 case DBGFREGVALTYPE_INVALID:
1816 break;
1817 /* no default, want gcc warnings */
1818 }
1819
1820 RTStrPrintf(pszTmp, cbTmp, "!enmType=%d!", enmType);
1821 return VERR_INTERNAL_ERROR_5;
1822}
1823
1824
1825
1826/**
1827 * Format a register value, extended version.
1828 *
1829 * @returns The number of bytes returned, VERR_BUFFER_OVERFLOW on failure.
1830 * @param pszBuf The output buffer.
1831 * @param cbBuf The size of the output buffer.
1832 * @param pValue The value to format.
1833 * @param enmType The value type.
1834 * @param uBase The base (ignored if not applicable).
1835 * @param cchWidth The width if RTSTR_F_WIDTH is set, otherwise
1836 * ignored.
1837 * @param cchPrecision The width if RTSTR_F_PRECISION is set, otherwise
1838 * ignored.
1839 * @param fFlags String formatting flags, RTSTR_F_XXX.
1840 */
1841VMMDECL(ssize_t) DBGFR3RegFormatValueEx(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType,
1842 unsigned uBase, signed int cchWidth, signed int cchPrecision, uint32_t fFlags)
1843{
1844 /*
1845 * Format to temporary buffer using worker shared with dbgfR3RegNmPrintfCbFormatNormal.
1846 */
1847 char szTmp[160];
1848 ssize_t cchOutput = dbgfR3RegFormatValueInt(szTmp, sizeof(szTmp), pValue, enmType, uBase, cchWidth, cchPrecision, fFlags);
1849 if (cchOutput > 0)
1850 {
1851 if ((size_t)cchOutput < cbBuf)
1852 memcpy(pszBuf, szTmp, cchOutput + 1);
1853 else
1854 {
1855 if (cbBuf)
1856 {
1857 memcpy(pszBuf, szTmp, cbBuf - 1);
1858 pszBuf[cbBuf - 1] = '\0';
1859 }
1860 cchOutput = VERR_BUFFER_OVERFLOW;
1861 }
1862 }
1863 return cchOutput;
1864}
1865
1866
1867/**
1868 * Format a register value as hexadecimal and with default width according to
1869 * the type.
1870 *
1871 * @returns The number of bytes returned, VERR_BUFFER_OVERFLOW on failure.
1872 * @param pszBuf The output buffer.
1873 * @param cbBuf The size of the output buffer.
1874 * @param pValue The value to format.
1875 * @param enmType The value type.
1876 * @param fSpecial Same as RTSTR_F_SPECIAL.
1877 */
1878VMMDECL(ssize_t) DBGFR3RegFormatValue(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType, bool fSpecial)
1879{
1880 int cchWidth = 0;
1881 switch (enmType)
1882 {
1883 case DBGFREGVALTYPE_U8: cchWidth = 2 + fSpecial*2; break;
1884 case DBGFREGVALTYPE_U16: cchWidth = 4 + fSpecial*2; break;
1885 case DBGFREGVALTYPE_U32: cchWidth = 8 + fSpecial*2; break;
1886 case DBGFREGVALTYPE_U64: cchWidth = 16 + fSpecial*2; break;
1887 case DBGFREGVALTYPE_U128: cchWidth = 32 + fSpecial*2; break;
1888 case DBGFREGVALTYPE_R80: cchWidth = 0; break;
1889 case DBGFREGVALTYPE_DTR: cchWidth = 16+1+4 + fSpecial*2; break;
1890
1891 case DBGFREGVALTYPE_32BIT_HACK:
1892 case DBGFREGVALTYPE_END:
1893 case DBGFREGVALTYPE_INVALID:
1894 break;
1895 /* no default, want gcc warnings */
1896 }
1897 uint32_t fFlags = RTSTR_F_ZEROPAD;
1898 if (fSpecial)
1899 fFlags |= RTSTR_F_SPECIAL;
1900 if (cchWidth != 0)
1901 fFlags |= RTSTR_F_WIDTH;
1902 return DBGFR3RegFormatValueEx(pszBuf, cbBuf, pValue, enmType, 16, cchWidth, 0, fFlags);
1903}
1904
1905
1906/**
1907 * Format a register using special hacks as well as sub-field specifications
1908 * (the latter isn't implemented yet).
1909 */
1910static size_t
1911dbgfR3RegNmPrintfCbFormatField(PDBGFR3REGNMPRINTFARGS pThis, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
1912 PCDBGFREGLOOKUP pLookupRec, int cchWidth, int cchPrecision, unsigned fFlags)
1913{
1914 char szTmp[160];
1915
1916 /*
1917 * Retrieve the register value.
1918 */
1919 DBGFREGVAL Value;
1920 DBGFREGVALTYPE enmType;
1921 int rc = dbgfR3RegNmQueryWorkerOnCpu(pThis->pVM, pLookupRec, DBGFREGVALTYPE_END, &Value, &enmType);
1922 if (RT_FAILURE(rc))
1923 {
1924 PCRTSTATUSMSG pErr = RTErrGet(rc);
1925 if (pErr)
1926 return pfnOutput(pvArgOutput, pErr->pszDefine, strlen(pErr->pszDefine));
1927 return pfnOutput(pvArgOutput, szTmp, RTStrPrintf(szTmp, sizeof(szTmp), "rc=%d", rc));
1928 }
1929
1930 char *psz = szTmp;
1931
1932 /*
1933 * Special case: Format eflags.
1934 */
1935 if ( pLookupRec->pSet->enmType == DBGFREGSETTYPE_CPU
1936 && pLookupRec->pDesc->enmReg == DBGFREG_RFLAGS
1937 && pLookupRec->pSubField == NULL)
1938 {
1939 rc = dbgfR3RegValCast(&Value, enmType, DBGFREGVALTYPE_U32);
1940 AssertRC(rc);
1941 uint32_t const efl = Value.u32;
1942
1943 /* the iopl */
1944 psz += RTStrPrintf(psz, sizeof(szTmp) / 2, "iopl=%u ", X86_EFL_GET_IOPL(efl));
1945
1946 /* add flags */
1947 static const struct
1948 {
1949 const char *pszSet;
1950 const char *pszClear;
1951 uint32_t fFlag;
1952 } aFlags[] =
1953 {
1954 { "vip",NULL, X86_EFL_VIP },
1955 { "vif",NULL, X86_EFL_VIF },
1956 { "ac", NULL, X86_EFL_AC },
1957 { "vm", NULL, X86_EFL_VM },
1958 { "rf", NULL, X86_EFL_RF },
1959 { "nt", NULL, X86_EFL_NT },
1960 { "ov", "nv", X86_EFL_OF },
1961 { "dn", "up", X86_EFL_DF },
1962 { "ei", "di", X86_EFL_IF },
1963 { "tf", NULL, X86_EFL_TF },
1964 { "ng", "pl", X86_EFL_SF },
1965 { "zr", "nz", X86_EFL_ZF },
1966 { "ac", "na", X86_EFL_AF },
1967 { "po", "pe", X86_EFL_PF },
1968 { "cy", "nc", X86_EFL_CF },
1969 };
1970 for (unsigned i = 0; i < RT_ELEMENTS(aFlags); i++)
1971 {
1972 const char *pszAdd = aFlags[i].fFlag & efl ? aFlags[i].pszSet : aFlags[i].pszClear;
1973 if (pszAdd)
1974 {
1975 *psz++ = *pszAdd++;
1976 *psz++ = *pszAdd++;
1977 if (*pszAdd)
1978 *psz++ = *pszAdd++;
1979 *psz++ = ' ';
1980 }
1981 }
1982
1983 /* drop trailing space */
1984 psz--;
1985 }
1986 else
1987 {
1988 /*
1989 * General case.
1990 */
1991 AssertMsgFailed(("Not implemented: %s\n", pLookupRec->Core.pszString));
1992 return pfnOutput(pvArgOutput, pLookupRec->Core.pszString, pLookupRec->Core.cchString);
1993 }
1994
1995 /* Output the string. */
1996 return pfnOutput(pvArgOutput, szTmp, psz - &szTmp[0]);
1997}
1998
1999
2000/**
2001 * Formats a register having parsed up to the register name.
2002 */
2003static size_t
2004dbgfR3RegNmPrintfCbFormatNormal(PDBGFR3REGNMPRINTFARGS pThis, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
2005 PCDBGFREGLOOKUP pLookupRec, unsigned uBase, int cchWidth, int cchPrecision, unsigned fFlags)
2006{
2007 char szTmp[160];
2008
2009 /*
2010 * Get the register value.
2011 */
2012 DBGFREGVAL Value;
2013 DBGFREGVALTYPE enmType;
2014 int rc = dbgfR3RegNmQueryWorkerOnCpu(pThis->pVM, pLookupRec, DBGFREGVALTYPE_END, &Value, &enmType);
2015 if (RT_FAILURE(rc))
2016 {
2017 PCRTSTATUSMSG pErr = RTErrGet(rc);
2018 if (pErr)
2019 return pfnOutput(pvArgOutput, pErr->pszDefine, strlen(pErr->pszDefine));
2020 return pfnOutput(pvArgOutput, szTmp, RTStrPrintf(szTmp, sizeof(szTmp), "rc=%d", rc));
2021 }
2022
2023 /*
2024 * Format the value.
2025 */
2026 ssize_t cchOutput = dbgfR3RegFormatValueInt(szTmp, sizeof(szTmp), &Value, enmType, uBase, cchWidth, cchPrecision, fFlags);
2027 if (RT_UNLIKELY(cchOutput <= 0))
2028 {
2029 AssertFailed();
2030 return pfnOutput(pvArgOutput, "internal-error", sizeof("internal-error") - 1);
2031 }
2032 return pfnOutput(pvArgOutput, szTmp, cchOutput);
2033}
2034
2035
2036/**
2037 * @callback_method_impl{FNSTRFORMAT}
2038 */
2039static DECLCALLBACK(size_t)
2040dbgfR3RegNmPrintfCbFormat(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
2041 const char **ppszFormat, va_list *pArgs, int cchWidth,
2042 int cchPrecision, unsigned fFlags, char chArgSize)
2043{
2044 /*
2045 * Parse the format type and hand the job to the appropriate worker.
2046 */
2047 PDBGFR3REGNMPRINTFARGS pThis = (PDBGFR3REGNMPRINTFARGS)pvArg;
2048 const char *pszFormat = *ppszFormat;
2049 if ( pszFormat[0] != 'V'
2050 || pszFormat[1] != 'R')
2051 {
2052 AssertMsgFailed(("'%s'\n", pszFormat));
2053 return 0;
2054 }
2055 unsigned offCurly = 2;
2056 if (pszFormat[offCurly] != '{')
2057 {
2058 AssertMsgReturn(pszFormat[offCurly], ("'%s'\n", pszFormat), 0);
2059 offCurly++;
2060 AssertMsgReturn(pszFormat[offCurly] == '{', ("'%s'\n", pszFormat), 0);
2061 }
2062 const char *pachReg = &pszFormat[offCurly + 1];
2063
2064 /*
2065 * The end and length of the register.
2066 */
2067 const char *pszEnd = strchr(&pachReg[3], '}');
2068 AssertMsgReturn(pszEnd, ("Missing closing curly bracket: '%s'\n", pszFormat), 0);
2069 size_t const cchReg = pszEnd - pachReg;
2070
2071 /*
2072 * Look up the register - same as dbgfR3RegResolve, except for locking and
2073 * input string termination.
2074 */
2075 /* Try looking up the name without any case folding or cpu prefixing. */
2076 PCDBGFREGLOOKUP pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGetN(&pThis->pVM->dbgf.s.RegSpace, pachReg, cchReg);
2077 if (!pLookupRec)
2078 {
2079 /* Lower case it and try again. */
2080 char szName[DBGF_REG_MAX_NAME * 4 + 16];
2081 ssize_t cchFolded = dbgfR3RegCopyToLower(pachReg, cchReg, szName, sizeof(szName) - DBGF_REG_MAX_NAME);
2082 if (cchFolded > 0)
2083 pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(&pThis->pVM->dbgf.s.RegSpace, szName);
2084 if ( !pLookupRec
2085 && cchFolded >= 0
2086 && pThis->idCpu != VMCPUID_ANY)
2087 {
2088 /* Prefix it with the specified CPU set. */
2089 size_t cchCpuSet = RTStrPrintf(szName, sizeof(szName), "cpu%u.", pThis->idCpu);
2090 dbgfR3RegCopyToLower(pachReg, cchReg, &szName[cchCpuSet], sizeof(szName) - cchCpuSet);
2091 pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(&pThis->pVM->dbgf.s.RegSpace, szName);
2092 }
2093 }
2094 AssertMsgReturn(pLookupRec, ("'%s'\n", pszFormat), 0);
2095 AssertMsgReturn( pLookupRec->pSet->enmType != DBGFREGSETTYPE_CPU
2096 || pLookupRec->pSet->uUserArg.pVCpu->idCpu == pThis->idCpu,
2097 ("'%s' idCpu=%u, pSet/cpu=%u\n", pszFormat, pThis->idCpu, pLookupRec->pSet->uUserArg.pVCpu->idCpu),
2098 0);
2099
2100 /*
2101 * Commit the parsed format string. Up to this point it is nice to know
2102 * what register lookup failed and such, so we've delayed comitting.
2103 */
2104 *ppszFormat = pszEnd + 1;
2105
2106 /*
2107 * Call the responsible worker.
2108 */
2109 switch (pszFormat[offCurly - 1])
2110 {
2111 case 'R': /* %VR{} */
2112 case 'X': /* %VRX{} */
2113 return dbgfR3RegNmPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
2114 16, cchWidth, cchPrecision, fFlags);
2115 case 'U':
2116 return dbgfR3RegNmPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
2117 10, cchWidth, cchPrecision, fFlags);
2118 case 'O':
2119 return dbgfR3RegNmPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
2120 8, cchWidth, cchPrecision, fFlags);
2121 case 'B':
2122 return dbgfR3RegNmPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
2123 2, cchWidth, cchPrecision, fFlags);
2124 case 'F':
2125 return dbgfR3RegNmPrintfCbFormatField(pThis, pfnOutput, pvArgOutput, pLookupRec, cchWidth, cchPrecision, fFlags);
2126 default:
2127 AssertFailed();
2128 return 0;
2129 }
2130}
2131
2132
2133
2134/**
2135 * @callback_method_impl{FNRTSTROUTPUT}
2136 */
2137static DECLCALLBACK(size_t)
2138dbgfR3RegNmPrintfCbOutput(void *pvArg, const char *pachChars, size_t cbChars)
2139{
2140 PDBGFR3REGNMPRINTFARGS pArgs = (PDBGFR3REGNMPRINTFARGS)pvArg;
2141 size_t cbToCopy = cbChars;
2142 if (cbToCopy >= pArgs->cchLeftBuf)
2143 {
2144 if (RT_SUCCESS(pArgs->rc))
2145 pArgs->rc = VERR_BUFFER_OVERFLOW;
2146 cbToCopy = pArgs->cchLeftBuf;
2147 }
2148 if (cbToCopy > 0)
2149 {
2150 memcpy(&pArgs->pszBuf[pArgs->offBuf], pachChars, cbChars);
2151 pArgs->offBuf += cbChars;
2152 pArgs->cchLeftBuf -= cbChars;
2153 pArgs->pszBuf[pArgs->offBuf] = '\0';
2154 }
2155 return cbToCopy;
2156}
2157
2158
2159/**
2160 * On CPU worker for the register formatting, used by DBGFR3RegNmPrintfV.
2161 *
2162 * @returns VBox status code.
2163 *
2164 * @param pArgs The argument package and state.
2165 */
2166static DECLCALLBACK(int) dbgfR3RegNmPrintfWorkerOnCpu(PDBGFR3REGNMPRINTFARGS pArgs)
2167{
2168 DBGF_REG_DB_LOCK_READ(pArgs->pVM);
2169 RTStrFormatV(dbgfR3RegNmPrintfCbOutput, pArgs, dbgfR3RegNmPrintfCbFormat, pArgs, pArgs->pszFormat, pArgs->va);
2170 DBGF_REG_DB_UNLOCK_READ(pArgs->pVM);
2171 return pArgs->rc;
2172}
2173
2174
2175/**
2176 * Format a registers.
2177 *
2178 * This is restricted to registers from one CPU, that specified by @a idCpu.
2179 *
2180 * @returns VBox status code.
2181 * @param pVM The VM handle.
2182 * @param idCpu The CPU ID of any CPU registers that may be
2183 * printed, pass VMCPUID_ANY if not applicable.
2184 * @param pszBuf The output buffer.
2185 * @param cbBuf The size of the output buffer.
2186 * @param pszFormat The format string. Register names are given by
2187 * %VR{name}, they take no arguments.
2188 * @param va Other format arguments.
2189 */
2190VMMR3DECL(int) DBGFR3RegNmPrintfV(PVM pVM, VMCPUID idCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, va_list va)
2191{
2192 AssertPtrReturn(pszBuf, VERR_INVALID_POINTER);
2193 AssertReturn(cbBuf > 0, VERR_BUFFER_OVERFLOW);
2194 *pszBuf = '\0';
2195
2196 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
2197 AssertReturn(idCpu < pVM->cCpus || idCpu == VMCPUID_ANY, VERR_INVALID_CPU_ID);
2198 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
2199
2200 /*
2201 * Set up an argument package and execute the formatting on the
2202 * specified CPU.
2203 */
2204 DBGFR3REGNMPRINTFARGS Args;
2205 Args.pVM = pVM;
2206 Args.idCpu = idCpu;
2207 Args.pszBuf = pszBuf;
2208 Args.pszFormat = pszFormat;
2209 va_copy(Args.va, va);
2210 Args.offBuf = 0;
2211 Args.cchLeftBuf = cbBuf - 1;
2212 Args.rc = VINF_SUCCESS;
2213 int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegNmPrintfWorkerOnCpu, 1, &Args);
2214 va_end(Args.va);
2215 return rc;
2216}
2217
2218
2219/**
2220 * Format a registers.
2221 *
2222 * This is restricted to registers from one CPU, that specified by @a idCpu.
2223 *
2224 * @returns VBox status code.
2225 * @param pVM The VM handle.
2226 * @param idCpu The CPU ID of any CPU registers that may be
2227 * printed, pass VMCPUID_ANY if not applicable.
2228 * @param pszBuf The output buffer.
2229 * @param cbBuf The size of the output buffer.
2230 * @param pszFormat The format string. Register names are given by
2231 * %VR{name}, %VRU{name}, %VRO{name} and
2232 * %VRB{name}, which are hexadecimal, (unsigned)
2233 * decimal, octal and binary representation. None
2234 * of these types takes any arguments.
2235 * @param ... Other format arguments.
2236 */
2237VMMR3DECL(int) DBGFR3RegNmPrintf(PVM pVM, VMCPUID idCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, ...)
2238{
2239 va_list va;
2240 va_start(va, pszFormat);
2241 int rc = DBGFR3RegNmPrintfV(pVM, idCpu, pszBuf, cbBuf, pszFormat, va);
2242 va_end(va);
2243 return rc;
2244}
2245
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