VirtualBox

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

Last change on this file since 38908 was 38838, checked in by vboxsync, 13 years ago

VMM,++: Try fix the async reset, suspend and power-off problems in PDM wrt conflicting VMM requests. Split them into priority requests and normal requests. The priority requests can safely be processed when PDM is doing async state change waits, the normal ones cannot. (The problem I bumped into was a unmap-chunk request from PGM being processed during PDMR3Reset, causing a recursive VMMR3EmtRendezvous deadlock.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 82.3 KB
Line 
1/* $Id: DBGFReg.cpp 38838 2011-09-23 11:21:55Z 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 /** The VM handle. */
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 The VM handle.
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 The VM handle.
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 The VM handle.
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));
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 The VM handle.
500 * @param pVCpu The virtual CPU handle.
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 The VM handle.
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 The VM handle.
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 The VM handle.
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 The VM handle.
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 The VM handle.
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 The VM handle.
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_INTERNAL_ERROR_3);
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 The VM handle.
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 The VM handle.
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 The VM handle.
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 The VM handle.
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 * On CPU worker for the register queries, used by dbgfR3RegNmQueryWorker and
1261 * dbgfR3RegPrintfCbFormatNormal.
1262 *
1263 * @returns VBox status code.
1264 *
1265 * @param pVM The VM handle.
1266 * @param pLookupRec The register lookup record.
1267 * @param enmType The desired return type.
1268 * @param pValue Where to return the register value.
1269 * @param penmType Where to store the register value type.
1270 * Optional.
1271 */
1272static DECLCALLBACK(int) dbgfR3RegNmQueryWorkerOnCpu(PVM pVM, PCDBGFREGLOOKUP pLookupRec, DBGFREGVALTYPE enmType,
1273 PDBGFREGVAL pValue, PDBGFREGVALTYPE penmType)
1274{
1275 PCDBGFREGDESC pDesc = pLookupRec->pDesc;
1276 PCDBGFREGSET pSet = pLookupRec->pSet;
1277 PCDBGFREGSUBFIELD pSubField = pLookupRec->pSubField;
1278 DBGFREGVALTYPE enmValueType = pDesc->enmType;
1279 int rc;
1280
1281 /*
1282 * Get the register or sub-field value.
1283 */
1284 dbgfR3RegValClear(pValue);
1285 if (!pSubField)
1286 {
1287 rc = pDesc->pfnGet(pSet->uUserArg.pv, pDesc, pValue);
1288 if ( pLookupRec->pAlias
1289 && pLookupRec->pAlias->enmType != enmValueType
1290 && RT_SUCCESS(rc))
1291 {
1292 rc = dbgfR3RegValCast(pValue, enmValueType, pLookupRec->pAlias->enmType);
1293 enmValueType = pLookupRec->pAlias->enmType;
1294 }
1295 }
1296 else
1297 {
1298 if (pSubField->pfnGet)
1299 {
1300 rc = pSubField->pfnGet(pSet->uUserArg.pv, pSubField, &pValue->u128);
1301 enmValueType = DBGFREGVALTYPE_U128;
1302 }
1303 else
1304 {
1305 rc = pDesc->pfnGet(pSet->uUserArg.pv, pDesc, pValue);
1306 if ( pLookupRec->pAlias
1307 && pLookupRec->pAlias->enmType != enmValueType
1308 && RT_SUCCESS(rc))
1309 {
1310 rc = dbgfR3RegValCast(pValue, enmValueType, pLookupRec->pAlias->enmType);
1311 enmValueType = pLookupRec->pAlias->enmType;
1312 }
1313 if (RT_SUCCESS(rc))
1314 {
1315 rc = dbgfR3RegValCast(pValue, enmValueType, DBGFREGVALTYPE_U128);
1316 if (RT_SUCCESS(rc))
1317 {
1318 RTUInt128AssignShiftLeft(&pValue->u128, -pSubField->iFirstBit);
1319 RTUInt128AssignAndNFirstBits(&pValue->u128, pSubField->cBits);
1320 if (pSubField->cShift)
1321 RTUInt128AssignShiftLeft(&pValue->u128, pSubField->cShift);
1322 }
1323 }
1324 }
1325 if (RT_SUCCESS(rc))
1326 {
1327 unsigned const cBits = pSubField->cBits + pSubField->cShift;
1328 if (cBits <= 8)
1329 enmValueType = DBGFREGVALTYPE_U8;
1330 else if (cBits <= 16)
1331 enmValueType = DBGFREGVALTYPE_U16;
1332 else if (cBits <= 32)
1333 enmValueType = DBGFREGVALTYPE_U32;
1334 else if (cBits <= 64)
1335 enmValueType = DBGFREGVALTYPE_U64;
1336 else
1337 enmValueType = DBGFREGVALTYPE_U128;
1338 rc = dbgfR3RegValCast(pValue, DBGFREGVALTYPE_U128, enmValueType);
1339 }
1340 }
1341 if (RT_SUCCESS(rc))
1342 {
1343 /*
1344 * Do the cast if the desired return type doesn't match what
1345 * the getter returned.
1346 */
1347 if ( enmValueType == enmType
1348 || enmType == DBGFREGVALTYPE_END)
1349 {
1350 rc = VINF_SUCCESS;
1351 if (penmType)
1352 *penmType = enmValueType;
1353 }
1354 else
1355 {
1356 rc = dbgfR3RegValCast(pValue, enmValueType, enmType);
1357 if (penmType)
1358 *penmType = RT_SUCCESS(rc) ? enmType : enmValueType;
1359 }
1360 }
1361
1362 return rc;
1363}
1364
1365
1366/**
1367 * Worker for the register queries.
1368 *
1369 * @returns VBox status code.
1370 * @retval VINF_SUCCESS
1371 * @retval VERR_INVALID_VM_HANDLE
1372 * @retval VERR_INVALID_CPU_ID
1373 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1374 * @retval VERR_DBGF_UNSUPPORTED_CAST
1375 * @retval VINF_DBGF_TRUNCATED_REGISTER
1376 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1377 *
1378 * @param pVM The VM handle.
1379 * @param idDefCpu The virtual CPU ID for the default CPU register
1380 * set. Can be OR'ed with DBGFREG_HYPER_VMCPUID.
1381 * @param pszReg The register to query.
1382 * @param enmType The desired return type.
1383 * @param pValue Where to return the register value.
1384 * @param penmType Where to store the register value type.
1385 * Optional.
1386 */
1387static int dbgfR3RegNmQueryWorker(PVM pVM, VMCPUID idDefCpu, const char *pszReg, DBGFREGVALTYPE enmType,
1388 PDBGFREGVAL pValue, PDBGFREGVALTYPE penmType)
1389{
1390 /*
1391 * Validate input.
1392 */
1393 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1394 AssertReturn((idDefCpu & ~DBGFREG_HYPER_VMCPUID) < pVM->cCpus || idDefCpu == VMCPUID_ANY, VERR_INVALID_CPU_ID);
1395 AssertPtrReturn(pszReg, VERR_INVALID_POINTER);
1396
1397 Assert(enmType > DBGFREGVALTYPE_INVALID && enmType <= DBGFREGVALTYPE_END);
1398 AssertPtr(pValue);
1399
1400 /*
1401 * Resolve the register and call the getter on the relevant CPU.
1402 */
1403 bool const fGuestRegs = !(idDefCpu & DBGFREG_HYPER_VMCPUID) && idDefCpu != VMCPUID_ANY;
1404 PCDBGFREGLOOKUP pLookupRec = dbgfR3RegResolve(pVM, idDefCpu, pszReg, fGuestRegs);
1405 if (pLookupRec)
1406 {
1407 if (pLookupRec->pSet->enmType == DBGFREGSETTYPE_CPU)
1408 idDefCpu = pLookupRec->pSet->uUserArg.pVCpu->idCpu;
1409 else if (idDefCpu != VMCPUID_ANY)
1410 idDefCpu &= ~DBGFREG_HYPER_VMCPUID;
1411 return VMR3ReqPriorityCallWait(pVM, idDefCpu, (PFNRT)dbgfR3RegNmQueryWorkerOnCpu, 5, pVM, pLookupRec, enmType, pValue, penmType);
1412 }
1413 return VERR_DBGF_REGISTER_NOT_FOUND;
1414}
1415
1416
1417/**
1418 * Queries a descriptor table register value.
1419 *
1420 * @retval VINF_SUCCESS
1421 * @retval VERR_INVALID_VM_HANDLE
1422 * @retval VERR_INVALID_CPU_ID
1423 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1424 *
1425 * @param pVM The VM handle.
1426 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
1427 * applicable. Can be OR'ed with
1428 * DBGFREG_HYPER_VMCPUID.
1429 * @param pszReg The register that's being queried. Except for
1430 * CPU registers, this must be on the form
1431 * "set.reg[.sub]".
1432 * @param pValue Where to store the register value.
1433 * @param penmType Where to store the register value type.
1434 */
1435VMMR3DECL(int) DBGFR3RegNmQuery(PVM pVM, VMCPUID idDefCpu, const char *pszReg, PDBGFREGVAL pValue, PDBGFREGVALTYPE penmType)
1436{
1437 return dbgfR3RegNmQueryWorker(pVM, idDefCpu, pszReg, DBGFREGVALTYPE_END, pValue, penmType);
1438}
1439
1440
1441/**
1442 * Queries a 8-bit register value.
1443 *
1444 * @retval VINF_SUCCESS
1445 * @retval VERR_INVALID_VM_HANDLE
1446 * @retval VERR_INVALID_CPU_ID
1447 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1448 * @retval VERR_DBGF_UNSUPPORTED_CAST
1449 * @retval VINF_DBGF_TRUNCATED_REGISTER
1450 *
1451 * @param pVM The VM handle.
1452 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
1453 * applicable. Can be OR'ed with
1454 * DBGFREG_HYPER_VMCPUID.
1455 * @param pszReg The register that's being queried. Except for
1456 * CPU registers, this must be on the form
1457 * "set.reg[.sub]".
1458 * @param pu8 Where to store the register value.
1459 */
1460VMMR3DECL(int) DBGFR3RegNmQueryU8(PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint8_t *pu8)
1461{
1462 DBGFREGVAL Value;
1463 int rc = dbgfR3RegNmQueryWorker(pVM, idDefCpu, pszReg, DBGFREGVALTYPE_U8, &Value, NULL);
1464 if (RT_SUCCESS(rc))
1465 *pu8 = Value.u8;
1466 else
1467 *pu8 = 0;
1468 return rc;
1469}
1470
1471
1472/**
1473 * Queries a 16-bit register value.
1474 *
1475 * @retval VINF_SUCCESS
1476 * @retval VERR_INVALID_VM_HANDLE
1477 * @retval VERR_INVALID_CPU_ID
1478 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1479 * @retval VERR_DBGF_UNSUPPORTED_CAST
1480 * @retval VINF_DBGF_TRUNCATED_REGISTER
1481 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1482 *
1483 * @param pVM The VM handle.
1484 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
1485 * applicable. Can be OR'ed with
1486 * DBGFREG_HYPER_VMCPUID.
1487 * @param pszReg The register that's being queried. Except for
1488 * CPU registers, this must be on the form
1489 * "set.reg[.sub]".
1490 * @param pu16 Where to store the register value.
1491 */
1492VMMR3DECL(int) DBGFR3RegNmQueryU16(PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint16_t *pu16)
1493{
1494 DBGFREGVAL Value;
1495 int rc = dbgfR3RegNmQueryWorker(pVM, idDefCpu, pszReg, DBGFREGVALTYPE_U16, &Value, NULL);
1496 if (RT_SUCCESS(rc))
1497 *pu16 = Value.u16;
1498 else
1499 *pu16 = 0;
1500 return rc;
1501}
1502
1503
1504/**
1505 * Queries a 32-bit register value.
1506 *
1507 * @retval VINF_SUCCESS
1508 * @retval VERR_INVALID_VM_HANDLE
1509 * @retval VERR_INVALID_CPU_ID
1510 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1511 * @retval VERR_DBGF_UNSUPPORTED_CAST
1512 * @retval VINF_DBGF_TRUNCATED_REGISTER
1513 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1514 *
1515 * @param pVM The VM handle.
1516 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
1517 * applicable. Can be OR'ed with
1518 * DBGFREG_HYPER_VMCPUID.
1519 * @param pszReg The register that's being queried. Except for
1520 * CPU registers, this must be on the form
1521 * "set.reg[.sub]".
1522 * @param pu32 Where to store the register value.
1523 */
1524VMMR3DECL(int) DBGFR3RegNmQueryU32(PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint32_t *pu32)
1525{
1526 DBGFREGVAL Value;
1527 int rc = dbgfR3RegNmQueryWorker(pVM, idDefCpu, pszReg, DBGFREGVALTYPE_U32, &Value, NULL);
1528 if (RT_SUCCESS(rc))
1529 *pu32 = Value.u32;
1530 else
1531 *pu32 = 0;
1532 return rc;
1533}
1534
1535
1536/**
1537 * Queries a 64-bit register value.
1538 *
1539 * @retval VINF_SUCCESS
1540 * @retval VERR_INVALID_VM_HANDLE
1541 * @retval VERR_INVALID_CPU_ID
1542 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1543 * @retval VERR_DBGF_UNSUPPORTED_CAST
1544 * @retval VINF_DBGF_TRUNCATED_REGISTER
1545 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1546 *
1547 * @param pVM The VM handle.
1548 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
1549 * applicable. Can be OR'ed with
1550 * DBGFREG_HYPER_VMCPUID.
1551 * @param pszReg The register that's being queried. Except for
1552 * CPU registers, this must be on the form
1553 * "set.reg[.sub]".
1554 * @param pu64 Where to store the register value.
1555 */
1556VMMR3DECL(int) DBGFR3RegNmQueryU64(PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64)
1557{
1558 DBGFREGVAL Value;
1559 int rc = dbgfR3RegNmQueryWorker(pVM, idDefCpu, pszReg, DBGFREGVALTYPE_U64, &Value, NULL);
1560 if (RT_SUCCESS(rc))
1561 *pu64 = Value.u64;
1562 else
1563 *pu64 = 0;
1564 return rc;
1565}
1566
1567
1568/**
1569 * Queries a 128-bit register value.
1570 *
1571 * @retval VINF_SUCCESS
1572 * @retval VERR_INVALID_VM_HANDLE
1573 * @retval VERR_INVALID_CPU_ID
1574 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1575 * @retval VERR_DBGF_UNSUPPORTED_CAST
1576 * @retval VINF_DBGF_TRUNCATED_REGISTER
1577 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1578 *
1579 * @param pVM The VM handle.
1580 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
1581 * applicable. Can be OR'ed with
1582 * DBGFREG_HYPER_VMCPUID.
1583 * @param pszReg The register that's being queried. Except for
1584 * CPU registers, this must be on the form
1585 * "set.reg[.sub]".
1586 * @param pu128 Where to store the register value.
1587 */
1588VMMR3DECL(int) DBGFR3RegNmQueryU128(PVM pVM, VMCPUID idDefCpu, const char *pszReg, PRTUINT128U pu128)
1589{
1590 DBGFREGVAL Value;
1591 int rc = dbgfR3RegNmQueryWorker(pVM, idDefCpu, pszReg, DBGFREGVALTYPE_U128, &Value, NULL);
1592 if (RT_SUCCESS(rc))
1593 *pu128 = Value.u128;
1594 else
1595 pu128->s.Hi = pu128->s.Lo = 0;
1596 return rc;
1597}
1598
1599
1600#if 0
1601/**
1602 * Queries a long double 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 The VM handle.
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 plrd Where to store the register value.
1620 */
1621VMMR3DECL(int) DBGFR3RegNmQueryLrd(PVM pVM, VMCPUID idDefCpu, const char *pszReg, long double *plrd)
1622{
1623 DBGFREGVAL Value;
1624 int rc = dbgfR3RegNmQueryWorker(pVM, idDefCpu, pszReg, DBGFREGVALTYPE_R80, &Value, NULL);
1625 if (RT_SUCCESS(rc))
1626 *plrd = Value.lrd;
1627 else
1628 *plrd = 0;
1629 return rc;
1630}
1631#endif
1632
1633
1634/**
1635 * Queries a descriptor table 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 The VM handle.
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 pu64Base Where to store the register base value.
1653 * @param pu32Limit Where to store the register limit value.
1654 */
1655VMMR3DECL(int) DBGFR3RegNmQueryXdtr(PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64Base, uint32_t *pu32Limit)
1656{
1657 DBGFREGVAL Value;
1658 int rc = dbgfR3RegNmQueryWorker(pVM, idDefCpu, pszReg, DBGFREGVALTYPE_DTR, &Value, NULL);
1659 if (RT_SUCCESS(rc))
1660 {
1661 *pu64Base = Value.dtr.u64Base;
1662 *pu32Limit = Value.dtr.u32Limit;
1663 }
1664 else
1665 {
1666 *pu64Base = 0;
1667 *pu32Limit = 0;
1668 }
1669 return rc;
1670}
1671
1672
1673/// @todo VMMR3DECL(int) DBGFR3RegNmQueryBatch(PVM pVM,VMCPUID idDefCpu, DBGFREGENTRYNM paRegs, size_t cRegs);
1674
1675
1676/**
1677 * Gets the number of registers returned by DBGFR3RegNmQueryAll.
1678 *
1679 * @returns VBox status code.
1680 * @param pVM The VM handle.
1681 * @param pcRegs Where to return the register count.
1682 */
1683VMMR3DECL(int) DBGFR3RegNmQueryAllCount(PVM pVM, size_t *pcRegs)
1684{
1685 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1686 *pcRegs = pVM->dbgf.s.cRegs;
1687 return VINF_SUCCESS;
1688}
1689
1690
1691/**
1692 * Pad register entries.
1693 *
1694 * @param paRegs The output array.
1695 * @param cRegs The size of the output array.
1696 * @param iReg The first register to pad.
1697 * @param cRegsToPad The number of registers to pad.
1698 */
1699static void dbgfR3RegNmQueryAllPadEntries(PDBGFREGENTRYNM paRegs, size_t cRegs, size_t iReg, size_t cRegsToPad)
1700{
1701 if (iReg < cRegs)
1702 {
1703 size_t iEndReg = iReg + cRegsToPad;
1704 if (iEndReg > cRegs)
1705 iEndReg = cRegs;
1706 while (iReg < iEndReg)
1707 {
1708 paRegs[iReg].pszName = NULL;
1709 paRegs[iReg].enmType = DBGFREGVALTYPE_END;
1710 dbgfR3RegValClear(&paRegs[iReg].Val);
1711 iReg++;
1712 }
1713 }
1714}
1715
1716
1717/**
1718 * Query all registers in a set.
1719 *
1720 * @param pSet The set.
1721 * @param cRegsToQuery The number of registers to query.
1722 * @param paRegs The output array.
1723 * @param cRegs The size of the output array.
1724 */
1725static void dbgfR3RegNmQueryAllInSet(PCDBGFREGSET pSet, size_t cRegsToQuery, PDBGFREGENTRYNM paRegs, size_t cRegs)
1726{
1727 int rc = VINF_SUCCESS;
1728
1729 if (cRegsToQuery > pSet->cDescs)
1730 cRegsToQuery = pSet->cDescs;
1731 if (cRegsToQuery > cRegs)
1732 cRegsToQuery = cRegs;
1733
1734 for (size_t iReg = 0; iReg < cRegsToQuery; iReg++)
1735 {
1736 paRegs[iReg].enmType = pSet->paDescs[iReg].enmType;
1737 paRegs[iReg].pszName = pSet->paLookupRecs[iReg].Core.pszString;
1738 dbgfR3RegValClear(&paRegs[iReg].Val);
1739 int rc2 = pSet->paDescs[iReg].pfnGet(pSet->uUserArg.pv, &pSet->paDescs[iReg], &paRegs[iReg].Val);
1740 AssertRCSuccess(rc2);
1741 if (RT_FAILURE(rc2))
1742 dbgfR3RegValClear(&paRegs[iReg].Val);
1743 }
1744}
1745
1746
1747/**
1748 * @callback_method_impl{FNRTSTRSPACECALLBACK, Worker used by
1749 * dbgfR3RegNmQueryAllWorker}
1750 */
1751static DECLCALLBACK(int) dbgfR3RegNmQueryAllEnum(PRTSTRSPACECORE pStr, void *pvUser)
1752{
1753 PCDBGFREGSET pSet = (PCDBGFREGSET)pStr;
1754 if (pSet->enmType != DBGFREGSETTYPE_CPU)
1755 {
1756 PDBGFR3REGNMQUERYALLARGS pArgs = (PDBGFR3REGNMQUERYALLARGS)pvUser;
1757 if (pArgs->iReg < pArgs->cRegs)
1758 dbgfR3RegNmQueryAllInSet(pSet, pSet->cDescs, &pArgs->paRegs[pArgs->iReg], pArgs->cRegs - pArgs->iReg);
1759 pArgs->iReg += pSet->cDescs;
1760 }
1761
1762 return 0;
1763}
1764
1765
1766/**
1767 * @callback_method_impl{FNVMMEMTRENDEZVOUS, Worker used by DBGFR3RegNmQueryAll}
1768 */
1769static DECLCALLBACK(VBOXSTRICTRC) dbgfR3RegNmQueryAllWorker(PVM pVM, PVMCPU pVCpu, void *pvUser)
1770{
1771 PDBGFR3REGNMQUERYALLARGS pArgs = (PDBGFR3REGNMQUERYALLARGS)pvUser;
1772 PDBGFREGENTRYNM paRegs = pArgs->paRegs;
1773 size_t const cRegs = pArgs->cRegs;
1774
1775 DBGF_REG_DB_LOCK_READ(pVM);
1776
1777 /*
1778 * My guest CPU registers.
1779 */
1780 size_t iCpuReg = pVCpu->idCpu * DBGFREG_ALL_COUNT;
1781 if (pVCpu->dbgf.s.pGuestRegSet)
1782 {
1783 if (iCpuReg < cRegs)
1784 dbgfR3RegNmQueryAllInSet(pVCpu->dbgf.s.pGuestRegSet, DBGFREG_ALL_COUNT, &paRegs[iCpuReg], cRegs - iCpuReg);
1785 }
1786 else
1787 dbgfR3RegNmQueryAllPadEntries(paRegs, cRegs, iCpuReg, DBGFREG_ALL_COUNT);
1788
1789 /*
1790 * My hypervisor CPU registers.
1791 */
1792 iCpuReg = pVM->cCpus * DBGFREG_ALL_COUNT + pVCpu->idCpu * DBGFREG_ALL_COUNT;
1793 if (pVCpu->dbgf.s.pHyperRegSet)
1794 {
1795 if (iCpuReg < cRegs)
1796 dbgfR3RegNmQueryAllInSet(pVCpu->dbgf.s.pHyperRegSet, DBGFREG_ALL_COUNT, &paRegs[iCpuReg], cRegs - iCpuReg);
1797 }
1798 else
1799 dbgfR3RegNmQueryAllPadEntries(paRegs, cRegs, iCpuReg, DBGFREG_ALL_COUNT);
1800
1801 /*
1802 * The primary CPU does all the other registers.
1803 */
1804 if (pVCpu->idCpu == 0)
1805 {
1806 pArgs->iReg = pVM->cCpus * DBGFREG_ALL_COUNT * 2;
1807 RTStrSpaceEnumerate(&pVM->dbgf.s.RegSetSpace, dbgfR3RegNmQueryAllEnum, pArgs);
1808 dbgfR3RegNmQueryAllPadEntries(paRegs, cRegs, pArgs->iReg, cRegs);
1809 }
1810
1811 DBGF_REG_DB_UNLOCK_READ(pVM);
1812 return VINF_SUCCESS; /* Ignore errors. */
1813}
1814
1815
1816/**
1817 * Queries all register.
1818 *
1819 * @returns VBox status code.
1820 * @param pVM The VM handle.
1821 * @param paRegs The output register value array. The register
1822 * name string is read only and shall not be freed
1823 * or modified.
1824 * @param cRegs The number of entries in @a paRegs. The
1825 * correct size can be obtained by calling
1826 * DBGFR3RegNmQueryAllCount.
1827 */
1828VMMR3DECL(int) DBGFR3RegNmQueryAll(PVM pVM, PDBGFREGENTRYNM paRegs, size_t cRegs)
1829{
1830 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1831 AssertPtrReturn(paRegs, VERR_INVALID_POINTER);
1832 AssertReturn(cRegs > 0, VERR_OUT_OF_RANGE);
1833
1834 DBGFR3REGNMQUERYALLARGS Args;
1835 Args.paRegs = paRegs;
1836 Args.cRegs = cRegs;
1837
1838 return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3RegNmQueryAllWorker, &Args);
1839}
1840
1841
1842VMMR3DECL(int) DBGFR3RegNmSet(PVM pVM, VMCPUID idDefCpu, const char *pszReg, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType)
1843{
1844 return VERR_NOT_IMPLEMENTED;
1845}
1846
1847
1848/**
1849 * Internal worker for DBGFR3RegFormatValue, cbTmp is sufficent.
1850 *
1851 * @copydoc DBGFR3RegFormatValue
1852 */
1853DECLINLINE(ssize_t) dbgfR3RegFormatValueInt(char *pszTmp, size_t cbTmp, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType,
1854 unsigned uBase, signed int cchWidth, signed int cchPrecision, uint32_t fFlags)
1855{
1856 switch (enmType)
1857 {
1858 case DBGFREGVALTYPE_U8:
1859 return RTStrFormatU8(pszTmp, cbTmp, pValue->u8, uBase, cchWidth, cchPrecision, fFlags);
1860 case DBGFREGVALTYPE_U16:
1861 return RTStrFormatU16(pszTmp, cbTmp, pValue->u16, uBase, cchWidth, cchPrecision, fFlags);
1862 case DBGFREGVALTYPE_U32:
1863 return RTStrFormatU32(pszTmp, cbTmp, pValue->u32, uBase, cchWidth, cchPrecision, fFlags);
1864 case DBGFREGVALTYPE_U64:
1865 return RTStrFormatU64(pszTmp, cbTmp, pValue->u64, uBase, cchWidth, cchPrecision, fFlags);
1866 case DBGFREGVALTYPE_U128:
1867 return RTStrFormatU128(pszTmp, cbTmp, &pValue->u128, uBase, cchWidth, cchPrecision, fFlags);
1868 case DBGFREGVALTYPE_R80:
1869 return RTStrFormatR80u2(pszTmp, cbTmp, &pValue->r80, cchWidth, cchPrecision, fFlags);
1870 case DBGFREGVALTYPE_DTR:
1871 {
1872 ssize_t cch = RTStrFormatU64(pszTmp, cbTmp, pValue->dtr.u64Base,
1873 16, 2+16, 0, RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD);
1874 AssertReturn(cch > 0, VERR_INTERNAL_ERROR_4);
1875 pszTmp[cch++] = ':';
1876 cch += RTStrFormatU64(&pszTmp[cch], cbTmp - cch, pValue->dtr.u32Limit,
1877 16, 4, 0, RTSTR_F_ZEROPAD | RTSTR_F_32BIT);
1878 return cch;
1879 }
1880
1881 case DBGFREGVALTYPE_32BIT_HACK:
1882 case DBGFREGVALTYPE_END:
1883 case DBGFREGVALTYPE_INVALID:
1884 break;
1885 /* no default, want gcc warnings */
1886 }
1887
1888 RTStrPrintf(pszTmp, cbTmp, "!enmType=%d!", enmType);
1889 return VERR_INTERNAL_ERROR_5;
1890}
1891
1892
1893
1894/**
1895 * Format a register value, extended version.
1896 *
1897 * @returns The number of bytes returned, VERR_BUFFER_OVERFLOW on failure.
1898 * @param pszBuf The output buffer.
1899 * @param cbBuf The size of the output buffer.
1900 * @param pValue The value to format.
1901 * @param enmType The value type.
1902 * @param uBase The base (ignored if not applicable).
1903 * @param cchWidth The width if RTSTR_F_WIDTH is set, otherwise
1904 * ignored.
1905 * @param cchPrecision The width if RTSTR_F_PRECISION is set, otherwise
1906 * ignored.
1907 * @param fFlags String formatting flags, RTSTR_F_XXX.
1908 */
1909VMMDECL(ssize_t) DBGFR3RegFormatValueEx(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType,
1910 unsigned uBase, signed int cchWidth, signed int cchPrecision, uint32_t fFlags)
1911{
1912 /*
1913 * Format to temporary buffer using worker shared with dbgfR3RegPrintfCbFormatNormal.
1914 */
1915 char szTmp[160];
1916 ssize_t cchOutput = dbgfR3RegFormatValueInt(szTmp, sizeof(szTmp), pValue, enmType, uBase, cchWidth, cchPrecision, fFlags);
1917 if (cchOutput > 0)
1918 {
1919 if ((size_t)cchOutput < cbBuf)
1920 memcpy(pszBuf, szTmp, cchOutput + 1);
1921 else
1922 {
1923 if (cbBuf)
1924 {
1925 memcpy(pszBuf, szTmp, cbBuf - 1);
1926 pszBuf[cbBuf - 1] = '\0';
1927 }
1928 cchOutput = VERR_BUFFER_OVERFLOW;
1929 }
1930 }
1931 return cchOutput;
1932}
1933
1934
1935/**
1936 * Format a register value as hexadecimal and with default width according to
1937 * the type.
1938 *
1939 * @returns The number of bytes returned, VERR_BUFFER_OVERFLOW on failure.
1940 * @param pszBuf The output buffer.
1941 * @param cbBuf The size of the output buffer.
1942 * @param pValue The value to format.
1943 * @param enmType The value type.
1944 * @param fSpecial Same as RTSTR_F_SPECIAL.
1945 */
1946VMMDECL(ssize_t) DBGFR3RegFormatValue(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType, bool fSpecial)
1947{
1948 int cchWidth = 0;
1949 switch (enmType)
1950 {
1951 case DBGFREGVALTYPE_U8: cchWidth = 2 + fSpecial*2; break;
1952 case DBGFREGVALTYPE_U16: cchWidth = 4 + fSpecial*2; break;
1953 case DBGFREGVALTYPE_U32: cchWidth = 8 + fSpecial*2; break;
1954 case DBGFREGVALTYPE_U64: cchWidth = 16 + fSpecial*2; break;
1955 case DBGFREGVALTYPE_U128: cchWidth = 32 + fSpecial*2; break;
1956 case DBGFREGVALTYPE_R80: cchWidth = 0; break;
1957 case DBGFREGVALTYPE_DTR: cchWidth = 16+1+4 + fSpecial*2; break;
1958
1959 case DBGFREGVALTYPE_32BIT_HACK:
1960 case DBGFREGVALTYPE_END:
1961 case DBGFREGVALTYPE_INVALID:
1962 break;
1963 /* no default, want gcc warnings */
1964 }
1965 uint32_t fFlags = RTSTR_F_ZEROPAD;
1966 if (fSpecial)
1967 fFlags |= RTSTR_F_SPECIAL;
1968 if (cchWidth != 0)
1969 fFlags |= RTSTR_F_WIDTH;
1970 return DBGFR3RegFormatValueEx(pszBuf, cbBuf, pValue, enmType, 16, cchWidth, 0, fFlags);
1971}
1972
1973
1974/**
1975 * Format a register using special hacks as well as sub-field specifications
1976 * (the latter isn't implemented yet).
1977 */
1978static size_t
1979dbgfR3RegPrintfCbFormatField(PDBGFR3REGPRINTFARGS pThis, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
1980 PCDBGFREGLOOKUP pLookupRec, int cchWidth, int cchPrecision, unsigned fFlags)
1981{
1982 char szTmp[160];
1983
1984 /*
1985 * Retrieve the register value.
1986 */
1987 DBGFREGVAL Value;
1988 DBGFREGVALTYPE enmType;
1989 int rc = dbgfR3RegNmQueryWorkerOnCpu(pThis->pVM, pLookupRec, DBGFREGVALTYPE_END, &Value, &enmType);
1990 if (RT_FAILURE(rc))
1991 {
1992 PCRTSTATUSMSG pErr = RTErrGet(rc);
1993 if (pErr)
1994 return pfnOutput(pvArgOutput, pErr->pszDefine, strlen(pErr->pszDefine));
1995 return pfnOutput(pvArgOutput, szTmp, RTStrPrintf(szTmp, sizeof(szTmp), "rc=%d", rc));
1996 }
1997
1998 char *psz = szTmp;
1999
2000 /*
2001 * Special case: Format eflags.
2002 */
2003 if ( pLookupRec->pSet->enmType == DBGFREGSETTYPE_CPU
2004 && pLookupRec->pDesc->enmReg == DBGFREG_RFLAGS
2005 && pLookupRec->pSubField == NULL)
2006 {
2007 rc = dbgfR3RegValCast(&Value, enmType, DBGFREGVALTYPE_U32);
2008 AssertRC(rc);
2009 uint32_t const efl = Value.u32;
2010
2011 /* the iopl */
2012 psz += RTStrPrintf(psz, sizeof(szTmp) / 2, "iopl=%u ", X86_EFL_GET_IOPL(efl));
2013
2014 /* add flags */
2015 static const struct
2016 {
2017 const char *pszSet;
2018 const char *pszClear;
2019 uint32_t fFlag;
2020 } aFlags[] =
2021 {
2022 { "vip",NULL, X86_EFL_VIP },
2023 { "vif",NULL, X86_EFL_VIF },
2024 { "ac", NULL, X86_EFL_AC },
2025 { "vm", NULL, X86_EFL_VM },
2026 { "rf", NULL, X86_EFL_RF },
2027 { "nt", NULL, X86_EFL_NT },
2028 { "ov", "nv", X86_EFL_OF },
2029 { "dn", "up", X86_EFL_DF },
2030 { "ei", "di", X86_EFL_IF },
2031 { "tf", NULL, X86_EFL_TF },
2032 { "ng", "pl", X86_EFL_SF },
2033 { "zr", "nz", X86_EFL_ZF },
2034 { "ac", "na", X86_EFL_AF },
2035 { "po", "pe", X86_EFL_PF },
2036 { "cy", "nc", X86_EFL_CF },
2037 };
2038 for (unsigned i = 0; i < RT_ELEMENTS(aFlags); i++)
2039 {
2040 const char *pszAdd = aFlags[i].fFlag & efl ? aFlags[i].pszSet : aFlags[i].pszClear;
2041 if (pszAdd)
2042 {
2043 *psz++ = *pszAdd++;
2044 *psz++ = *pszAdd++;
2045 if (*pszAdd)
2046 *psz++ = *pszAdd++;
2047 *psz++ = ' ';
2048 }
2049 }
2050
2051 /* drop trailing space */
2052 psz--;
2053 }
2054 else
2055 {
2056 /*
2057 * General case.
2058 */
2059 AssertMsgFailed(("Not implemented: %s\n", pLookupRec->Core.pszString));
2060 return pfnOutput(pvArgOutput, pLookupRec->Core.pszString, pLookupRec->Core.cchString);
2061 }
2062
2063 /* Output the string. */
2064 return pfnOutput(pvArgOutput, szTmp, psz - &szTmp[0]);
2065}
2066
2067
2068/**
2069 * Formats a register having parsed up to the register name.
2070 */
2071static size_t
2072dbgfR3RegPrintfCbFormatNormal(PDBGFR3REGPRINTFARGS pThis, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
2073 PCDBGFREGLOOKUP pLookupRec, unsigned uBase, int cchWidth, int cchPrecision, unsigned fFlags)
2074{
2075 char szTmp[160];
2076
2077 /*
2078 * Get the register value.
2079 */
2080 DBGFREGVAL Value;
2081 DBGFREGVALTYPE enmType;
2082 int rc = dbgfR3RegNmQueryWorkerOnCpu(pThis->pVM, pLookupRec, DBGFREGVALTYPE_END, &Value, &enmType);
2083 if (RT_FAILURE(rc))
2084 {
2085 PCRTSTATUSMSG pErr = RTErrGet(rc);
2086 if (pErr)
2087 return pfnOutput(pvArgOutput, pErr->pszDefine, strlen(pErr->pszDefine));
2088 return pfnOutput(pvArgOutput, szTmp, RTStrPrintf(szTmp, sizeof(szTmp), "rc=%d", rc));
2089 }
2090
2091 /*
2092 * Format the value.
2093 */
2094 ssize_t cchOutput = dbgfR3RegFormatValueInt(szTmp, sizeof(szTmp), &Value, enmType, uBase, cchWidth, cchPrecision, fFlags);
2095 if (RT_UNLIKELY(cchOutput <= 0))
2096 {
2097 AssertFailed();
2098 return pfnOutput(pvArgOutput, "internal-error", sizeof("internal-error") - 1);
2099 }
2100 return pfnOutput(pvArgOutput, szTmp, cchOutput);
2101}
2102
2103
2104/**
2105 * @callback_method_impl{FNSTRFORMAT}
2106 */
2107static DECLCALLBACK(size_t)
2108dbgfR3RegPrintfCbFormat(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
2109 const char **ppszFormat, va_list *pArgs, int cchWidth,
2110 int cchPrecision, unsigned fFlags, char chArgSize)
2111{
2112 /*
2113 * Parse the format type and hand the job to the appropriate worker.
2114 */
2115 PDBGFR3REGPRINTFARGS pThis = (PDBGFR3REGPRINTFARGS)pvArg;
2116 const char *pszFormat = *ppszFormat;
2117 if ( pszFormat[0] != 'V'
2118 || pszFormat[1] != 'R')
2119 {
2120 AssertMsgFailed(("'%s'\n", pszFormat));
2121 return 0;
2122 }
2123 unsigned offCurly = 2;
2124 if (pszFormat[offCurly] != '{')
2125 {
2126 AssertMsgReturn(pszFormat[offCurly], ("'%s'\n", pszFormat), 0);
2127 offCurly++;
2128 AssertMsgReturn(pszFormat[offCurly] == '{', ("'%s'\n", pszFormat), 0);
2129 }
2130 const char *pachReg = &pszFormat[offCurly + 1];
2131
2132 /*
2133 * The end and length of the register.
2134 */
2135 const char *pszEnd = strchr(pachReg, '}');
2136 AssertMsgReturn(pszEnd, ("Missing closing curly bracket: '%s'\n", pszFormat), 0);
2137 size_t const cchReg = pszEnd - pachReg;
2138
2139 /*
2140 * Look up the register - same as dbgfR3RegResolve, except for locking and
2141 * input string termination.
2142 */
2143 /* Try looking up the name without any case folding or cpu prefixing. */
2144 PCDBGFREGLOOKUP pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGetN(&pThis->pVM->dbgf.s.RegSpace, pachReg, cchReg);
2145 if (!pLookupRec)
2146 {
2147 /* Lower case it and try again. */
2148 char szName[DBGF_REG_MAX_NAME * 4 + 16];
2149 ssize_t cchFolded = dbgfR3RegCopyToLower(pachReg, cchReg, szName, sizeof(szName) - DBGF_REG_MAX_NAME);
2150 if (cchFolded > 0)
2151 pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(&pThis->pVM->dbgf.s.RegSpace, szName);
2152 if ( !pLookupRec
2153 && cchFolded >= 0
2154 && pThis->idCpu != VMCPUID_ANY)
2155 {
2156 /* Prefix it with the specified CPU set. */
2157 size_t cchCpuSet = RTStrPrintf(szName, sizeof(szName), pThis->fGuestRegs ? "cpu%u." : "hypercpu%u.", pThis->idCpu);
2158 dbgfR3RegCopyToLower(pachReg, cchReg, &szName[cchCpuSet], sizeof(szName) - cchCpuSet);
2159 pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(&pThis->pVM->dbgf.s.RegSpace, szName);
2160 }
2161 }
2162 AssertMsgReturn(pLookupRec, ("'%s'\n", pszFormat), 0);
2163 AssertMsgReturn( pLookupRec->pSet->enmType != DBGFREGSETTYPE_CPU
2164 || pLookupRec->pSet->uUserArg.pVCpu->idCpu == pThis->idCpu,
2165 ("'%s' idCpu=%u, pSet/cpu=%u\n", pszFormat, pThis->idCpu, pLookupRec->pSet->uUserArg.pVCpu->idCpu),
2166 0);
2167
2168 /*
2169 * Commit the parsed format string. Up to this point it is nice to know
2170 * what register lookup failed and such, so we've delayed comitting.
2171 */
2172 *ppszFormat = pszEnd + 1;
2173
2174 /*
2175 * Call the responsible worker.
2176 */
2177 switch (pszFormat[offCurly - 1])
2178 {
2179 case 'R': /* %VR{} */
2180 case 'X': /* %VRX{} */
2181 return dbgfR3RegPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
2182 16, cchWidth, cchPrecision, fFlags);
2183 case 'U':
2184 return dbgfR3RegPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
2185 10, cchWidth, cchPrecision, fFlags);
2186 case 'O':
2187 return dbgfR3RegPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
2188 8, cchWidth, cchPrecision, fFlags);
2189 case 'B':
2190 return dbgfR3RegPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
2191 2, cchWidth, cchPrecision, fFlags);
2192 case 'F':
2193 return dbgfR3RegPrintfCbFormatField(pThis, pfnOutput, pvArgOutput, pLookupRec, cchWidth, cchPrecision, fFlags);
2194 default:
2195 AssertFailed();
2196 return 0;
2197 }
2198}
2199
2200
2201
2202/**
2203 * @callback_method_impl{FNRTSTROUTPUT}
2204 */
2205static DECLCALLBACK(size_t)
2206dbgfR3RegPrintfCbOutput(void *pvArg, const char *pachChars, size_t cbChars)
2207{
2208 PDBGFR3REGPRINTFARGS pArgs = (PDBGFR3REGPRINTFARGS)pvArg;
2209 size_t cbToCopy = cbChars;
2210 if (cbToCopy >= pArgs->cchLeftBuf)
2211 {
2212 if (RT_SUCCESS(pArgs->rc))
2213 pArgs->rc = VERR_BUFFER_OVERFLOW;
2214 cbToCopy = pArgs->cchLeftBuf;
2215 }
2216 if (cbToCopy > 0)
2217 {
2218 memcpy(&pArgs->pszBuf[pArgs->offBuf], pachChars, cbToCopy);
2219 pArgs->offBuf += cbToCopy;
2220 pArgs->cchLeftBuf -= cbToCopy;
2221 pArgs->pszBuf[pArgs->offBuf] = '\0';
2222 }
2223 return cbToCopy;
2224}
2225
2226
2227/**
2228 * On CPU worker for the register formatting, used by DBGFR3RegPrintfV.
2229 *
2230 * @returns VBox status code.
2231 *
2232 * @param pArgs The argument package and state.
2233 */
2234static DECLCALLBACK(int) dbgfR3RegPrintfWorkerOnCpu(PDBGFR3REGPRINTFARGS pArgs)
2235{
2236 DBGF_REG_DB_LOCK_READ(pArgs->pVM);
2237 RTStrFormatV(dbgfR3RegPrintfCbOutput, pArgs, dbgfR3RegPrintfCbFormat, pArgs, pArgs->pszFormat, pArgs->va);
2238 DBGF_REG_DB_UNLOCK_READ(pArgs->pVM);
2239 return pArgs->rc;
2240}
2241
2242
2243/**
2244 * Format a registers.
2245 *
2246 * This is restricted to registers from one CPU, that specified by @a idCpu.
2247 *
2248 * @returns VBox status code.
2249 * @param pVM The VM handle.
2250 * @param idCpu The CPU ID of any CPU registers that may be
2251 * printed, pass VMCPUID_ANY if not applicable.
2252 * @param pszBuf The output buffer.
2253 * @param cbBuf The size of the output buffer.
2254 * @param pszFormat The format string. Register names are given by
2255 * %VR{name}, they take no arguments.
2256 * @param va Other format arguments.
2257 */
2258VMMR3DECL(int) DBGFR3RegPrintfV(PVM pVM, VMCPUID idCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, va_list va)
2259{
2260 AssertPtrReturn(pszBuf, VERR_INVALID_POINTER);
2261 AssertReturn(cbBuf > 0, VERR_BUFFER_OVERFLOW);
2262 *pszBuf = '\0';
2263
2264 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
2265 AssertReturn((idCpu & ~DBGFREG_HYPER_VMCPUID) < pVM->cCpus || idCpu == VMCPUID_ANY, VERR_INVALID_CPU_ID);
2266 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
2267
2268 /*
2269 * Set up an argument package and execute the formatting on the
2270 * specified CPU.
2271 */
2272 DBGFR3REGPRINTFARGS Args;
2273 Args.pVM = pVM;
2274 Args.idCpu = idCpu != VMCPUID_ANY ? idCpu & ~DBGFREG_HYPER_VMCPUID : idCpu;
2275 Args.fGuestRegs = idCpu != VMCPUID_ANY && !(idCpu & DBGFREG_HYPER_VMCPUID);
2276 Args.pszBuf = pszBuf;
2277 Args.pszFormat = pszFormat;
2278 va_copy(Args.va, va);
2279 Args.offBuf = 0;
2280 Args.cchLeftBuf = cbBuf - 1;
2281 Args.rc = VINF_SUCCESS;
2282 int rc = VMR3ReqPriorityCallWait(pVM, Args.idCpu, (PFNRT)dbgfR3RegPrintfWorkerOnCpu, 1, &Args);
2283 va_end(Args.va);
2284 return rc;
2285}
2286
2287
2288/**
2289 * Format a registers.
2290 *
2291 * This is restricted to registers from one CPU, that specified by @a idCpu.
2292 *
2293 * @returns VBox status code.
2294 * @param pVM The VM handle.
2295 * @param idCpu The CPU ID of any CPU registers that may be
2296 * printed, pass VMCPUID_ANY if not applicable.
2297 * @param pszBuf The output buffer.
2298 * @param cbBuf The size of the output buffer.
2299 * @param pszFormat The format string. Register names are given by
2300 * %VR{name}, %VRU{name}, %VRO{name} and
2301 * %VRB{name}, which are hexadecimal, (unsigned)
2302 * decimal, octal and binary representation. None
2303 * of these types takes any arguments.
2304 * @param ... Other format arguments.
2305 */
2306VMMR3DECL(int) DBGFR3RegPrintf(PVM pVM, VMCPUID idCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, ...)
2307{
2308 va_list va;
2309 va_start(va, pszFormat);
2310 int rc = DBGFR3RegPrintfV(pVM, idCpu, pszBuf, cbBuf, pszFormat, va);
2311 va_end(va);
2312 return rc;
2313}
2314
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