VirtualBox

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

Last change on this file since 43667 was 41803, checked in by vboxsync, 12 years ago

Doxygen.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use