VirtualBox

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

Last change on this file since 50653 was 48898, checked in by vboxsync, 11 years ago

VMM,DBGC: Implemented DBGFR3RegNmSet and made the debugger side work.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use