VirtualBox

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

Last change on this file since 74795 was 73417, checked in by vboxsync, 6 years ago

VMM/DBGF: Implemented DBGFR3RegNmQueryXdtr and fixed exports, including DBGFR3ModInMem which is needed by previous commit.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 101.4 KB
RevLine 
[31491]1/* $Id: DBGFReg.cpp 73417 2018-08-01 11:09:23Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Register Methods.
4 */
5
6/*
[69111]7 * Copyright (C) 2010-2017 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
[57358]19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
[31491]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
[57358]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
[57358]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)
[72867]297 AssertMsgReturn(iDesc < (unsigned)DBGFREG_END && (unsigned)paRegisters[iDesc].enmReg == iDesc,
[35410]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 */
[73097]348 size_t cbRegSet = RT_UOFFSETOF_DYN(DBGFREGSET, szPrefix[cchPrefix + 4 + 1]);
[35466]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.
[58122]502 * @param pVM The cross context VM structure.
[58123]503 * @param pVCpu The cross context virtual CPU structure.
[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.
[58122]527 * @param pVM The cross context VM structure.
[44691]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;
[66885]554 pValue->au64[2] = 0;
555 pValue->au64[3] = 0;
556 pValue->au64[4] = 0;
557 pValue->au64[5] = 0;
558 pValue->au64[6] = 0;
559 pValue->au64[7] = 0;
[35410]560}
[35312]561
562
563/**
[35513]564 * Sets a 80-bit floating point variable to a 64-bit unsigned interger value.
565 *
566 * @param pValue The value.
567 * @param u64 The integer value.
568 */
569DECLINLINE(void) dbgfR3RegValR80SetU64(PDBGFREGVAL pValue, uint64_t u64)
570{
571 /** @todo fixme */
572 pValue->r80.s.fSign = 0;
573 pValue->r80.s.uExponent = 16383;
574 pValue->r80.s.u64Mantissa = u64;
575}
576
577
578/**
579 * Sets a 80-bit floating point variable to a 64-bit unsigned interger value.
580 *
581 * @param pValue The value.
582 * @param u128 The integer value.
583 */
584DECLINLINE(void) dbgfR3RegValR80SetU128(PDBGFREGVAL pValue, RTUINT128U u128)
585{
586 /** @todo fixme */
587 pValue->r80.s.fSign = 0;
588 pValue->r80.s.uExponent = 16383;
589 pValue->r80.s.u64Mantissa = u128.s.Lo;
590}
591
592
593/**
594 * Get a 80-bit floating point variable as a 64-bit unsigned integer.
595 *
596 * @returns 64-bit unsigned integer.
597 * @param pValue The value.
598 */
599DECLINLINE(uint64_t) dbgfR3RegValR80GetU64(PCDBGFREGVAL pValue)
600{
601 /** @todo stupid, stupid MSC. */
602 return pValue->r80.s.u64Mantissa;
603}
604
605
606/**
607 * Get a 80-bit floating point variable as a 128-bit unsigned integer.
608 *
609 * @returns 128-bit unsigned integer.
610 * @param pValue The value.
611 */
612DECLINLINE(RTUINT128U) dbgfR3RegValR80GetU128(PCDBGFREGVAL pValue)
613{
614 /** @todo stupid, stupid MSC. */
615 RTUINT128U uRet;
616#if 0
617 uRet.s.Lo = (uint64_t)InVal.lrd;
618 uRet.s.Hi = (uint64_t)InVal.lrd / _4G / _4G;
619#else
620 uRet.s.Lo = pValue->r80.s.u64Mantissa;
621 uRet.s.Hi = 0;
622#endif
623 return uRet;
624}
625
626
627/**
[35410]628 * Performs a cast between register value types.
629 *
630 * @retval VINF_SUCCESS
631 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
632 * @retval VINF_DBGF_TRUNCATED_REGISTER
633 * @retval VERR_DBGF_UNSUPPORTED_CAST
634 *
635 * @param pValue The value to cast (input + output).
636 * @param enmFromType The input value.
637 * @param enmToType The desired output value.
[35312]638 */
[35410]639static int dbgfR3RegValCast(PDBGFREGVAL pValue, DBGFREGVALTYPE enmFromType, DBGFREGVALTYPE enmToType)
[35312]640{
[35410]641 DBGFREGVAL const InVal = *pValue;
642 dbgfR3RegValClear(pValue);
[35312]643
[35466]644 /* Note! No default cases here as gcc warnings about missing enum values
645 are desired. */
[35410]646 switch (enmFromType)
647 {
648 case DBGFREGVALTYPE_U8:
649 switch (enmToType)
650 {
651 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u8; return VINF_SUCCESS;
652 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
653 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
654 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
655 case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
[66885]656 case DBGFREGVALTYPE_U256: pValue->u256.Words.w0 = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
657 case DBGFREGVALTYPE_U512: pValue->u512.Words.w0 = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
[35513]658 case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.u8); return VINF_DBGF_ZERO_EXTENDED_REGISTER;
[35410]659 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
[35312]660
[35410]661 case DBGFREGVALTYPE_32BIT_HACK:
662 case DBGFREGVALTYPE_END:
663 case DBGFREGVALTYPE_INVALID:
664 break;
665 }
666 break;
[35312]667
[35410]668 case DBGFREGVALTYPE_U16:
669 switch (enmToType)
670 {
671 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u16; return VINF_DBGF_TRUNCATED_REGISTER;
672 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u16; return VINF_SUCCESS;
673 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u16; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
674 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u16; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
675 case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.u16; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
[66885]676 case DBGFREGVALTYPE_U256: pValue->u256.Words.w0 = InVal.u16; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
677 case DBGFREGVALTYPE_U512: pValue->u512.Words.w0 = InVal.u16; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
[35513]678 case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.u16); return VINF_DBGF_ZERO_EXTENDED_REGISTER;
[35410]679 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
[35312]680
[35410]681 case DBGFREGVALTYPE_32BIT_HACK:
682 case DBGFREGVALTYPE_END:
683 case DBGFREGVALTYPE_INVALID:
684 break;
685 }
686 break;
[35312]687
[35410]688 case DBGFREGVALTYPE_U32:
689 switch (enmToType)
690 {
691 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u32; return VINF_DBGF_TRUNCATED_REGISTER;
692 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u32; return VINF_DBGF_TRUNCATED_REGISTER;
693 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u32; return VINF_SUCCESS;
694 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u32; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
695 case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.u32; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
[66885]696 case DBGFREGVALTYPE_U256: pValue->u256.DWords.dw0 = InVal.u32; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
697 case DBGFREGVALTYPE_U512: pValue->u512.DWords.dw0 = InVal.u32; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
[35513]698 case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.u32); return VINF_DBGF_ZERO_EXTENDED_REGISTER;
[35410]699 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
[35312]700
[35410]701 case DBGFREGVALTYPE_32BIT_HACK:
702 case DBGFREGVALTYPE_END:
703 case DBGFREGVALTYPE_INVALID:
704 break;
705 }
706 break;
[35312]707
[35410]708 case DBGFREGVALTYPE_U64:
709 switch (enmToType)
710 {
711 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
712 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
713 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
714 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u64; return VINF_SUCCESS;
715 case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
[66885]716 case DBGFREGVALTYPE_U256: pValue->u256.QWords.qw0 = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
717 case DBGFREGVALTYPE_U512: pValue->u512.QWords.qw0 = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
[35513]718 case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.u64); return VINF_DBGF_TRUNCATED_REGISTER;
[35410]719 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
[35312]720
[35410]721 case DBGFREGVALTYPE_32BIT_HACK:
722 case DBGFREGVALTYPE_END:
723 case DBGFREGVALTYPE_INVALID:
724 break;
725 }
726 break;
[35312]727
[35410]728 case DBGFREGVALTYPE_U128:
729 switch (enmToType)
730 {
731 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u128.s.Lo; return VINF_DBGF_TRUNCATED_REGISTER;
732 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u128.s.Lo; return VINF_DBGF_TRUNCATED_REGISTER;
733 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u128.s.Lo; return VINF_DBGF_TRUNCATED_REGISTER;
734 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u128.s.Lo; return VINF_DBGF_TRUNCATED_REGISTER;
735 case DBGFREGVALTYPE_U128: pValue->u128 = InVal.u128; return VINF_SUCCESS;
[66885]736 case DBGFREGVALTYPE_U256: pValue->u256.DQWords.dqw0 = InVal.u128; return VINF_SUCCESS;
737 case DBGFREGVALTYPE_U512: pValue->u512.DQWords.dqw0 = InVal.u128; return VINF_SUCCESS;
[35513]738 case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU128(pValue, InVal.u128); return VINF_DBGF_TRUNCATED_REGISTER;
[35410]739 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
[35312]740
[35410]741 case DBGFREGVALTYPE_32BIT_HACK:
742 case DBGFREGVALTYPE_END:
743 case DBGFREGVALTYPE_INVALID:
744 break;
745 }
746 break;
[35312]747
[66885]748 case DBGFREGVALTYPE_U256:
749 switch (enmToType)
750 {
751 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u256.Words.w0; return VINF_DBGF_TRUNCATED_REGISTER;
752 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u256.Words.w0; return VINF_DBGF_TRUNCATED_REGISTER;
753 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u256.DWords.dw0; return VINF_DBGF_TRUNCATED_REGISTER;
754 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u256.QWords.qw0; return VINF_DBGF_TRUNCATED_REGISTER;
755 case DBGFREGVALTYPE_U128: pValue->u128 = InVal.u256.DQWords.dqw0; return VINF_DBGF_TRUNCATED_REGISTER;
756 case DBGFREGVALTYPE_U256: pValue->u256 = InVal.u256; return VINF_SUCCESS;
757 case DBGFREGVALTYPE_U512: pValue->u512.OWords.ow0 = InVal.u256; return VINF_SUCCESS;
758 case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU128(pValue, InVal.u256.DQWords.dqw0); return VINF_DBGF_TRUNCATED_REGISTER;
759 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
760
761 case DBGFREGVALTYPE_32BIT_HACK:
762 case DBGFREGVALTYPE_END:
763 case DBGFREGVALTYPE_INVALID:
764 break;
765 }
766 break;
767
768 case DBGFREGVALTYPE_U512:
769 switch (enmToType)
770 {
771 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u512.Words.w0; return VINF_DBGF_TRUNCATED_REGISTER;
772 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u512.Words.w0; return VINF_DBGF_TRUNCATED_REGISTER;
773 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u512.DWords.dw0; return VINF_DBGF_TRUNCATED_REGISTER;
774 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u512.QWords.qw0; return VINF_DBGF_TRUNCATED_REGISTER;
775 case DBGFREGVALTYPE_U128: pValue->u128 = InVal.u512.DQWords.dqw0; return VINF_DBGF_TRUNCATED_REGISTER;
776 case DBGFREGVALTYPE_U256: pValue->u256 = InVal.u512.OWords.ow0; return VINF_DBGF_TRUNCATED_REGISTER;
777 case DBGFREGVALTYPE_U512: pValue->u512 = InVal.u512; return VINF_SUCCESS;
778 case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU128(pValue, InVal.u512.DQWords.dqw0); return VINF_DBGF_TRUNCATED_REGISTER;
779 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
780
781 case DBGFREGVALTYPE_32BIT_HACK:
782 case DBGFREGVALTYPE_END:
783 case DBGFREGVALTYPE_INVALID:
784 break;
785 }
786 break;
787
[35513]788 case DBGFREGVALTYPE_R80:
[35410]789 switch (enmToType)
790 {
[35513]791 case DBGFREGVALTYPE_U8: pValue->u8 = (uint8_t )dbgfR3RegValR80GetU64(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
792 case DBGFREGVALTYPE_U16: pValue->u16 = (uint16_t)dbgfR3RegValR80GetU64(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
793 case DBGFREGVALTYPE_U32: pValue->u32 = (uint32_t)dbgfR3RegValR80GetU64(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
794 case DBGFREGVALTYPE_U64: pValue->u64 = (uint64_t)dbgfR3RegValR80GetU64(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
795 case DBGFREGVALTYPE_U128: pValue->u128 = dbgfR3RegValR80GetU128(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
[66885]796 case DBGFREGVALTYPE_U256: pValue->u256.DQWords.dqw0 = dbgfR3RegValR80GetU128(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
797 case DBGFREGVALTYPE_U512: pValue->u512.DQWords.dqw0 = dbgfR3RegValR80GetU128(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
[35513]798 case DBGFREGVALTYPE_R80: pValue->r80 = InVal.r80; return VINF_SUCCESS;
799 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
[35312]800
[35410]801 case DBGFREGVALTYPE_32BIT_HACK:
802 case DBGFREGVALTYPE_END:
803 case DBGFREGVALTYPE_INVALID:
804 break;
805 }
806 break;
[35312]807
[35410]808 case DBGFREGVALTYPE_DTR:
809 switch (enmToType)
810 {
811 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
812 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
813 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
814 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
815 case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
[66885]816 case DBGFREGVALTYPE_U256: pValue->u256.QWords.qw0 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
817 case DBGFREGVALTYPE_U512: pValue->u512.QWords.qw0 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
[35513]818 case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.dtr.u64Base); return VINF_DBGF_TRUNCATED_REGISTER;
[35410]819 case DBGFREGVALTYPE_DTR: pValue->dtr = InVal.dtr; return VINF_SUCCESS;
[35312]820
[35410]821 case DBGFREGVALTYPE_32BIT_HACK:
822 case DBGFREGVALTYPE_END:
823 case DBGFREGVALTYPE_INVALID:
824 break;
825 }
826 break;
[35312]827
[35410]828 case DBGFREGVALTYPE_INVALID:
829 case DBGFREGVALTYPE_END:
830 case DBGFREGVALTYPE_32BIT_HACK:
831 break;
832 }
833
834 AssertMsgFailed(("%d / %d\n", enmFromType, enmToType));
835 return VERR_DBGF_UNSUPPORTED_CAST;
[35312]836}
837
838
839/**
[35410]840 * Worker for the CPU register queries.
[31491]841 *
[35410]842 * @returns VBox status code.
[31491]843 * @retval VINF_SUCCESS
[35410]844 * @retval VERR_INVALID_VM_HANDLE
845 * @retval VERR_INVALID_CPU_ID
[35466]846 * @retval VERR_DBGF_REGISTER_NOT_FOUND
[35410]847 * @retval VERR_DBGF_UNSUPPORTED_CAST
848 * @retval VINF_DBGF_TRUNCATED_REGISTER
849 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
[31491]850 *
[44399]851 * @param pUVM The user mode VM handle.
[35410]852 * @param idCpu The virtual CPU ID.
853 * @param enmReg The register to query.
854 * @param enmType The desired return type.
[35606]855 * @param fGuestRegs Query guest CPU registers if set (true),
856 * hypervisor CPU registers if clear (false).
[35466]857 * @param pValue Where to return the register value.
[31491]858 */
[44399]859static DECLCALLBACK(int) dbgfR3RegCpuQueryWorkerOnCpu(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, DBGFREGVALTYPE enmType,
[35606]860 bool fGuestRegs, PDBGFREGVAL pValue)
[31491]861{
[35410]862 int rc = VINF_SUCCESS;
[44399]863 DBGF_REG_DB_LOCK_READ(pUVM);
[31491]864
[35410]865 /*
[35466]866 * Look up the register set of the specified CPU.
[35410]867 */
[35606]868 PDBGFREGSET pSet = fGuestRegs
[44399]869 ? pUVM->aCpus[idCpu].dbgf.s.pGuestRegSet
870 : pUVM->aCpus[idCpu].dbgf.s.pHyperRegSet;
[35410]871 if (RT_LIKELY(pSet))
[31491]872 {
[35410]873 /*
874 * Look up the register and get the register value.
875 */
876 if (RT_LIKELY(pSet->cDescs > (size_t)enmReg))
[35312]877 {
[35410]878 PCDBGFREGDESC pDesc = &pSet->paDescs[enmReg];
[31491]879
[35466]880 pValue->au64[0] = pValue->au64[1] = 0;
881 rc = pDesc->pfnGet(pSet->uUserArg.pv, pDesc, pValue);
[35410]882 if (RT_SUCCESS(rc))
883 {
884 /*
885 * Do the cast if the desired return type doesn't match what
886 * the getter returned.
887 */
888 if (pDesc->enmType == enmType)
889 rc = VINF_SUCCESS;
890 else
[35466]891 rc = dbgfR3RegValCast(pValue, pDesc->enmType, enmType);
[35410]892 }
[35312]893 }
[35410]894 else
[35466]895 rc = VERR_DBGF_REGISTER_NOT_FOUND;
[31491]896 }
[35410]897 else
898 rc = VERR_INVALID_CPU_ID;
[31491]899
[44399]900 DBGF_REG_DB_UNLOCK_READ(pUVM);
[35410]901 return rc;
[31491]902}
903
904
905/**
[35606]906 * Internal worker for the CPU register query functions.
907 *
908 * @returns VBox status code.
909 * @retval VINF_SUCCESS
910 * @retval VERR_INVALID_VM_HANDLE
911 * @retval VERR_INVALID_CPU_ID
912 * @retval VERR_DBGF_REGISTER_NOT_FOUND
913 * @retval VERR_DBGF_UNSUPPORTED_CAST
914 * @retval VINF_DBGF_TRUNCATED_REGISTER
915 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
916 *
[44399]917 * @param pUVM The user mode VM handle.
[35606]918 * @param idCpu The virtual CPU ID. Can be OR'ed with
919 * DBGFREG_HYPER_VMCPUID.
920 * @param enmReg The register to query.
921 * @param enmType The desired return type.
922 * @param pValue Where to return the register value.
923 */
[44399]924static int dbgfR3RegCpuQueryWorker(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, DBGFREGVALTYPE enmType, PDBGFREGVAL pValue)
[35606]925{
[44399]926 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
927 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
[35606]928 AssertMsgReturn(enmReg >= DBGFREG_AL && enmReg <= DBGFREG_END, ("%d\n", enmReg), VERR_INVALID_PARAMETER);
929
[35607]930 bool const fGuestRegs = !(idCpu & DBGFREG_HYPER_VMCPUID);
[35606]931 idCpu &= ~DBGFREG_HYPER_VMCPUID;
[44399]932 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
[35606]933
[44399]934 return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3RegCpuQueryWorkerOnCpu, 6,
935 pUVM, idCpu, enmReg, enmType, fGuestRegs, pValue);
[35606]936}
937
938
939/**
[35410]940 * Queries a 8-bit CPU register value.
[31491]941 *
942 * @retval VINF_SUCCESS
943 * @retval VERR_INVALID_VM_HANDLE
944 * @retval VERR_INVALID_CPU_ID
[35466]945 * @retval VERR_DBGF_REGISTER_NOT_FOUND
[35410]946 * @retval VERR_DBGF_UNSUPPORTED_CAST
[31491]947 * @retval VINF_DBGF_TRUNCATED_REGISTER
948 *
[44399]949 * @param pUVM The user mode VM handle.
[35606]950 * @param idCpu The target CPU ID. Can be OR'ed with
951 * DBGFREG_HYPER_VMCPUID.
[31491]952 * @param enmReg The register that's being queried.
953 * @param pu8 Where to store the register value.
954 */
[44399]955VMMR3DECL(int) DBGFR3RegCpuQueryU8(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint8_t *pu8)
[31491]956{
[35410]957 DBGFREGVAL Value;
[44399]958 int rc = dbgfR3RegCpuQueryWorker(pUVM, idCpu, enmReg, DBGFREGVALTYPE_U8, &Value);
[31491]959 if (RT_SUCCESS(rc))
[35410]960 *pu8 = Value.u8;
[31491]961 else
962 *pu8 = 0;
963 return rc;
964}
965
966
967/**
[35410]968 * Queries a 16-bit CPU register value.
[31491]969 *
970 * @retval VINF_SUCCESS
971 * @retval VERR_INVALID_VM_HANDLE
972 * @retval VERR_INVALID_CPU_ID
[35466]973 * @retval VERR_DBGF_REGISTER_NOT_FOUND
[35410]974 * @retval VERR_DBGF_UNSUPPORTED_CAST
[31491]975 * @retval VINF_DBGF_TRUNCATED_REGISTER
976 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
977 *
[44399]978 * @param pUVM The user mode VM handle.
[35606]979 * @param idCpu The target CPU ID. Can be OR'ed with
980 * DBGFREG_HYPER_VMCPUID.
[31491]981 * @param enmReg The register that's being queried.
982 * @param pu16 Where to store the register value.
983 */
[44399]984VMMR3DECL(int) DBGFR3RegCpuQueryU16(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint16_t *pu16)
[31491]985{
[35410]986 DBGFREGVAL Value;
[44399]987 int rc = dbgfR3RegCpuQueryWorker(pUVM, idCpu, enmReg, DBGFREGVALTYPE_U16, &Value);
[31491]988 if (RT_SUCCESS(rc))
[35410]989 *pu16 = Value.u16;
[31491]990 else
991 *pu16 = 0;
992 return rc;
993}
994
995
996/**
[35410]997 * Queries a 32-bit CPU register value.
[31491]998 *
999 * @retval VINF_SUCCESS
1000 * @retval VERR_INVALID_VM_HANDLE
1001 * @retval VERR_INVALID_CPU_ID
[35466]1002 * @retval VERR_DBGF_REGISTER_NOT_FOUND
[35410]1003 * @retval VERR_DBGF_UNSUPPORTED_CAST
[31491]1004 * @retval VINF_DBGF_TRUNCATED_REGISTER
1005 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1006 *
[44399]1007 * @param pUVM The user mode VM handle.
[35606]1008 * @param idCpu The target CPU ID. Can be OR'ed with
1009 * DBGFREG_HYPER_VMCPUID.
[31491]1010 * @param enmReg The register that's being queried.
1011 * @param pu32 Where to store the register value.
1012 */
[44399]1013VMMR3DECL(int) DBGFR3RegCpuQueryU32(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint32_t *pu32)
[31491]1014{
[35410]1015 DBGFREGVAL Value;
[44399]1016 int rc = dbgfR3RegCpuQueryWorker(pUVM, idCpu, enmReg, DBGFREGVALTYPE_U32, &Value);
[31491]1017 if (RT_SUCCESS(rc))
[35410]1018 *pu32 = Value.u32;
[31491]1019 else
1020 *pu32 = 0;
1021 return rc;
1022}
1023
1024
1025/**
[35410]1026 * Queries a 64-bit CPU register value.
[31491]1027 *
1028 * @retval VINF_SUCCESS
1029 * @retval VERR_INVALID_VM_HANDLE
1030 * @retval VERR_INVALID_CPU_ID
[35466]1031 * @retval VERR_DBGF_REGISTER_NOT_FOUND
[35410]1032 * @retval VERR_DBGF_UNSUPPORTED_CAST
[31491]1033 * @retval VINF_DBGF_TRUNCATED_REGISTER
1034 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1035 *
[44399]1036 * @param pUVM The user mode VM handle.
[35606]1037 * @param idCpu The target CPU ID. Can be OR'ed with
1038 * DBGFREG_HYPER_VMCPUID.
[31491]1039 * @param enmReg The register that's being queried.
1040 * @param pu64 Where to store the register value.
1041 */
[44399]1042VMMR3DECL(int) DBGFR3RegCpuQueryU64(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint64_t *pu64)
[31491]1043{
[35410]1044 DBGFREGVAL Value;
[44399]1045 int rc = dbgfR3RegCpuQueryWorker(pUVM, idCpu, enmReg, DBGFREGVALTYPE_U64, &Value);
[31491]1046 if (RT_SUCCESS(rc))
[35410]1047 *pu64 = Value.u64;
[31491]1048 else
1049 *pu64 = 0;
1050 return rc;
1051}
1052
[73417]1053
1054/**
1055 * Queries a descriptor table register value.
1056 *
1057 * @retval VINF_SUCCESS
1058 * @retval VERR_INVALID_VM_HANDLE
1059 * @retval VERR_INVALID_CPU_ID
1060 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1061 * @retval VERR_DBGF_UNSUPPORTED_CAST
1062 * @retval VINF_DBGF_TRUNCATED_REGISTER
1063 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1064 *
1065 * @param pUVM The user mode VM handle.
1066 * @param idCpu The target CPU ID. Can be OR'ed with
1067 * DBGFREG_HYPER_VMCPUID.
1068 * @param enmReg The register that's being queried.
1069 * @param pu64Base Where to store the register base value.
1070 * @param pu16Limit Where to store the register limit value.
1071 */
1072VMMR3DECL(int) DBGFR3RegCpuQueryXdtr(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint64_t *pu64Base, uint16_t *pu16Limit)
1073{
1074 DBGFREGVAL Value;
1075 int rc = dbgfR3RegCpuQueryWorker(pUVM, idCpu, enmReg, DBGFREGVALTYPE_DTR, &Value);
1076 if (RT_SUCCESS(rc))
1077 {
1078 *pu64Base = Value.dtr.u64Base;
1079 *pu16Limit = Value.dtr.u32Limit;
1080 }
1081 else
1082 {
1083 *pu64Base = 0;
1084 *pu16Limit = 0;
1085 }
1086 return rc;
1087}
1088
1089
[35606]1090#if 0 /* rewrite / remove */
[35312]1091
1092/**
[35410]1093 * Wrapper around CPUMQueryGuestMsr for dbgfR3RegCpuQueryBatchWorker.
[35312]1094 *
1095 * @retval VINF_SUCCESS
[35466]1096 * @retval VERR_DBGF_REGISTER_NOT_FOUND
[35312]1097 *
[58123]1098 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
[35312]1099 * @param pReg The where to store the register value and
1100 * size.
1101 * @param idMsr The MSR to get.
1102 */
1103static void dbgfR3RegGetMsrBatch(PVMCPU pVCpu, PDBGFREGENTRY pReg, uint32_t idMsr)
1104{
1105 pReg->enmType = DBGFREGVALTYPE_U64;
1106 int rc = CPUMQueryGuestMsr(pVCpu, idMsr, &pReg->Val.u64);
1107 if (RT_FAILURE(rc))
1108 {
1109 AssertMsg(rc == VERR_CPUM_RAISE_GP_0, ("%Rrc\n", rc));
1110 pReg->Val.u64 = 0;
1111 }
1112}
1113
1114
[44399]1115static DECLCALLBACK(int) dbgfR3RegCpuQueryBatchWorker(PUVM pUVM, VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs)
[35312]1116{
[35410]1117#if 0
[44399]1118 PVMCPU pVCpu = &pUVM->pVM->aCpus[idCpu];
[35312]1119 PCCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
1120
1121 PDBGFREGENTRY pReg = paRegs - 1;
1122 while (cRegs-- > 0)
1123 {
1124 pReg++;
1125 pReg->Val.au64[0] = 0;
1126 pReg->Val.au64[1] = 0;
1127
1128 DBGFREG const enmReg = pReg->enmReg;
[35466]1129 AssertMsgReturn(enmReg >= 0 && enmReg <= DBGFREG_END, ("%d (%#x)\n", enmReg, enmReg), VERR_DBGF_REGISTER_NOT_FOUND);
[35312]1130 if (enmReg != DBGFREG_END)
1131 {
1132 PCDBGFREGDESC pDesc = &g_aDbgfRegDescs[enmReg];
1133 if (!pDesc->pfnGet)
1134 {
1135 PCRTUINT128U pu = (PCRTUINT128U)((uintptr_t)pCtx + pDesc->offCtx);
1136 pReg->enmType = pDesc->enmType;
1137 switch (pDesc->enmType)
1138 {
1139 case DBGFREGVALTYPE_U8: pReg->Val.u8 = pu->au8[0]; break;
1140 case DBGFREGVALTYPE_U16: pReg->Val.u16 = pu->au16[0]; break;
1141 case DBGFREGVALTYPE_U32: pReg->Val.u32 = pu->au32[0]; break;
1142 case DBGFREGVALTYPE_U64: pReg->Val.u64 = pu->au64[0]; break;
1143 case DBGFREGVALTYPE_U128:
1144 pReg->Val.au64[0] = pu->au64[0];
1145 pReg->Val.au64[1] = pu->au64[1];
1146 break;
[35513]1147 case DBGFREGVALTYPE_R80:
[35312]1148 pReg->Val.au64[0] = pu->au64[0];
1149 pReg->Val.au16[5] = pu->au16[5];
1150 break;
1151 default:
[39405]1152 AssertMsgFailedReturn(("%s %d\n", pDesc->pszName, pDesc->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
[35312]1153 }
1154 }
1155 else
1156 {
1157 int rc = pDesc->pfnGet(pVCpu, pDesc, pCtx, &pReg->Val.u);
1158 if (RT_FAILURE(rc))
1159 return rc;
1160 }
1161 }
1162 }
1163 return VINF_SUCCESS;
[35410]1164#else
1165 return VERR_NOT_IMPLEMENTED;
1166#endif
[35312]1167}
1168
1169
1170/**
1171 * Query a batch of registers.
1172 *
1173 * @retval VINF_SUCCESS
1174 * @retval VERR_INVALID_VM_HANDLE
1175 * @retval VERR_INVALID_CPU_ID
[35466]1176 * @retval VERR_DBGF_REGISTER_NOT_FOUND
[35312]1177 *
[44399]1178 * @param pUVM The user mode VM handle.
[35606]1179 * @param idCpu The target CPU ID. Can be OR'ed with
1180 * DBGFREG_HYPER_VMCPUID.
[35312]1181 * @param paRegs Pointer to an array of @a cRegs elements. On
1182 * input the enmReg members indicates which
1183 * registers to query. On successful return the
1184 * other members are set. DBGFREG_END can be used
1185 * as a filler.
1186 * @param cRegs The number of entries in @a paRegs.
1187 */
[44399]1188VMMR3DECL(int) DBGFR3RegCpuQueryBatch(PUVM pUVM, VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs)
[35312]1189{
[44399]1190 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
1191 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, NULL);
1192 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
[35312]1193 if (!cRegs)
1194 return VINF_SUCCESS;
1195 AssertReturn(cRegs < _1M, VERR_OUT_OF_RANGE);
1196 AssertPtrReturn(paRegs, VERR_INVALID_POINTER);
1197 size_t iReg = cRegs;
1198 while (iReg-- > 0)
1199 {
1200 DBGFREG enmReg = paRegs[iReg].enmReg;
[35466]1201 AssertMsgReturn(enmReg < DBGFREG_END && enmReg >= DBGFREG_AL, ("%d (%#x)", enmReg, enmReg), VERR_DBGF_REGISTER_NOT_FOUND);
[35312]1202 }
1203
[44399]1204 return VMR3ReqCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3RegCpuQueryBatchWorker, 4, pUVM, idCpu, paRegs, cRegs);
[35312]1205}
1206
1207
1208/**
[35609]1209 * Query all registers for a Virtual CPU.
[35312]1210 *
1211 * @retval VINF_SUCCESS
1212 * @retval VERR_INVALID_VM_HANDLE
1213 * @retval VERR_INVALID_CPU_ID
1214 *
[44399]1215 * @param pUVM The user mode VM handle.
[35606]1216 * @param idCpu The target CPU ID. Can be OR'ed with
1217 * DBGFREG_HYPER_VMCPUID.
[35312]1218 * @param paRegs Pointer to an array of @a cRegs elements.
1219 * These will be filled with the CPU register
1220 * values. Overflowing entries will be set to
1221 * DBGFREG_END. The returned registers can be
1222 * accessed by using the DBGFREG values as index.
1223 * @param cRegs The number of entries in @a paRegs. The
1224 * recommended value is DBGFREG_ALL_COUNT.
1225 */
[44399]1226VMMR3DECL(int) DBGFR3RegCpuQueryAll(PUVM pUVM, VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs)
[35312]1227{
1228 /*
1229 * Validate input.
1230 */
[44399]1231 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
1232 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, NULL);
1233 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
[35312]1234 if (!cRegs)
1235 return VINF_SUCCESS;
1236 AssertReturn(cRegs < _1M, VERR_OUT_OF_RANGE);
1237 AssertPtrReturn(paRegs, VERR_INVALID_POINTER);
1238
1239 /*
1240 * Convert it into a batch query (lazy bird).
1241 */
1242 unsigned iReg = 0;
1243 while (iReg < cRegs && iReg < DBGFREG_ALL_COUNT)
1244 {
1245 paRegs[iReg].enmReg = (DBGFREG)iReg;
1246 iReg++;
1247 }
1248 while (iReg < cRegs)
1249 paRegs[iReg++].enmReg = DBGFREG_END;
1250
[44399]1251 return VMR3ReqCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3RegCpuQueryBatchWorker, 4, pUVM, idCpu, paRegs, cRegs);
[35312]1252}
1253
[35606]1254#endif /* rewrite or remove? */
[35312]1255
1256/**
1257 * Gets the name of a register.
1258 *
1259 * @returns Pointer to read-only register name (lower case). NULL if the
1260 * parameters are invalid.
[35466]1261 *
[44399]1262 * @param pUVM The user mode VM handle.
[35312]1263 * @param enmReg The register identifier.
1264 * @param enmType The register type. This is for sort out
1265 * aliases. Pass DBGFREGVALTYPE_INVALID to get
1266 * the standard name.
1267 */
[44399]1268VMMR3DECL(const char *) DBGFR3RegCpuName(PUVM pUVM, DBGFREG enmReg, DBGFREGVALTYPE enmType)
[35312]1269{
1270 AssertReturn(enmReg >= DBGFREG_AL && enmReg < DBGFREG_END, NULL);
1271 AssertReturn(enmType >= DBGFREGVALTYPE_INVALID && enmType < DBGFREGVALTYPE_END, NULL);
[44399]1272 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
1273 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, NULL);
[35312]1274
[44399]1275 PCDBGFREGSET pSet = pUVM->aCpus[0].dbgf.s.pGuestRegSet;
[35466]1276 if (RT_UNLIKELY(!pSet))
1277 return NULL;
1278
1279 PCDBGFREGDESC pDesc = &pSet->paDescs[enmReg];
1280 PCDBGFREGALIAS pAlias = pDesc->paAliases;
[35312]1281 if ( pAlias
1282 && pDesc->enmType != enmType
1283 && enmType != DBGFREGVALTYPE_INVALID)
1284 {
1285 while (pAlias->pszName)
1286 {
1287 if (pAlias->enmType == enmType)
1288 return pAlias->pszName;
1289 pAlias++;
1290 }
1291 }
1292
1293 return pDesc->pszName;
1294}
1295
[35466]1296
1297/**
1298 * Fold the string to lower case and copy it into the destination buffer.
1299 *
1300 * @returns Number of folder characters, -1 on overflow.
1301 * @param pszSrc The source string.
1302 * @param cchSrc How much to fold and copy.
1303 * @param pszDst The output buffer.
1304 * @param cbDst The size of the output buffer.
1305 */
1306static ssize_t dbgfR3RegCopyToLower(const char *pszSrc, size_t cchSrc, char *pszDst, size_t cbDst)
1307{
1308 ssize_t cchFolded = 0;
1309 char ch;
1310 while (cchSrc-- > 0 && (ch = *pszSrc++))
1311 {
1312 if (RT_UNLIKELY(cbDst <= 1))
1313 return -1;
1314 cbDst--;
1315
1316 char chLower = RT_C_TO_LOWER(ch);
1317 cchFolded += chLower != ch;
1318 *pszDst++ = chLower;
1319 }
1320 if (RT_UNLIKELY(!cbDst))
1321 return -1;
1322 *pszDst = '\0';
1323 return cchFolded;
1324}
1325
1326
1327/**
1328 * Resolves the register name.
1329 *
1330 * @returns Lookup record.
[44399]1331 * @param pUVM The user mode VM handle.
[35466]1332 * @param idDefCpu The default CPU ID set.
1333 * @param pszReg The register name.
[35606]1334 * @param fGuestRegs Default to guest CPU registers if set, the
1335 * hypervisor CPU registers if clear.
[35466]1336 */
[44399]1337static PCDBGFREGLOOKUP dbgfR3RegResolve(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, bool fGuestRegs)
[35466]1338{
[44399]1339 DBGF_REG_DB_LOCK_READ(pUVM);
[35466]1340
1341 /* Try looking up the name without any case folding or cpu prefixing. */
[44399]1342 PRTSTRSPACE pRegSpace = &pUVM->dbgf.s.RegSpace;
1343 PCDBGFREGLOOKUP pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(pRegSpace, pszReg);
[35466]1344 if (!pLookupRec)
1345 {
1346 char szName[DBGF_REG_MAX_NAME * 4 + 16];
1347
1348 /* Lower case it and try again. */
1349 ssize_t cchFolded = dbgfR3RegCopyToLower(pszReg, RTSTR_MAX, szName, sizeof(szName) - DBGF_REG_MAX_NAME);
1350 if (cchFolded > 0)
[44399]1351 pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(pRegSpace, szName);
[35466]1352 if ( !pLookupRec
1353 && cchFolded >= 0
1354 && idDefCpu != VMCPUID_ANY)
1355 {
1356 /* Prefix it with the specified CPU set. */
[35606]1357 size_t cchCpuSet = RTStrPrintf(szName, sizeof(szName), fGuestRegs ? "cpu%u." : "hypercpu%u.", idDefCpu);
[35466]1358 dbgfR3RegCopyToLower(pszReg, RTSTR_MAX, &szName[cchCpuSet], sizeof(szName) - cchCpuSet);
[44399]1359 pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(pRegSpace, szName);
[35466]1360 }
1361 }
1362
[44399]1363 DBGF_REG_DB_UNLOCK_READ(pUVM);
[35466]1364 return pLookupRec;
1365}
1366
1367
1368/**
[41545]1369 * Validates the register name.
1370 *
1371 * @returns VBox status code.
1372 * @retval VINF_SUCCESS if the register was found.
1373 * @retval VERR_DBGF_REGISTER_NOT_FOUND if not found.
1374 *
[44399]1375 * @param pUVM The user mode VM handle.
[41545]1376 * @param idDefCpu The default CPU.
1377 * @param pszReg The registe name.
1378 */
[44399]1379VMMR3DECL(int) DBGFR3RegNmValidate(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg)
[41545]1380{
1381 /*
1382 * Validate input.
1383 */
[44399]1384 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1385 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
1386 AssertReturn((idDefCpu & ~DBGFREG_HYPER_VMCPUID) < pUVM->cCpus || idDefCpu == VMCPUID_ANY, VERR_INVALID_CPU_ID);
[41545]1387 AssertPtrReturn(pszReg, VERR_INVALID_POINTER);
1388
1389 /*
1390 * Resolve the register.
1391 */
[46155]1392 bool fGuestRegs = true;
1393 if ((idDefCpu & DBGFREG_HYPER_VMCPUID) && idDefCpu != VMCPUID_ANY)
1394 {
1395 fGuestRegs = false;
1396 idDefCpu &= ~DBGFREG_HYPER_VMCPUID;
1397 }
1398
[44399]1399 PCDBGFREGLOOKUP pLookupRec = dbgfR3RegResolve(pUVM, idDefCpu, pszReg, fGuestRegs);
[41545]1400 if (!pLookupRec)
1401 return VERR_DBGF_REGISTER_NOT_FOUND;
1402 return VINF_SUCCESS;
1403}
1404
1405
1406/**
[35586]1407 * On CPU worker for the register queries, used by dbgfR3RegNmQueryWorker and
[35625]1408 * dbgfR3RegPrintfCbFormatNormal.
[35466]1409 *
1410 * @returns VBox status code.
1411 *
[44399]1412 * @param pUVM The user mode VM handle.
[35466]1413 * @param pLookupRec The register lookup record.
1414 * @param enmType The desired return type.
1415 * @param pValue Where to return the register value.
1416 * @param penmType Where to store the register value type.
1417 * Optional.
1418 */
[44399]1419static DECLCALLBACK(int) dbgfR3RegNmQueryWorkerOnCpu(PUVM pUVM, PCDBGFREGLOOKUP pLookupRec, DBGFREGVALTYPE enmType,
[35466]1420 PDBGFREGVAL pValue, PDBGFREGVALTYPE penmType)
1421{
1422 PCDBGFREGDESC pDesc = pLookupRec->pDesc;
1423 PCDBGFREGSET pSet = pLookupRec->pSet;
1424 PCDBGFREGSUBFIELD pSubField = pLookupRec->pSubField;
1425 DBGFREGVALTYPE enmValueType = pDesc->enmType;
1426 int rc;
1427
[44399]1428 NOREF(pUVM);
[39078]1429
[35466]1430 /*
1431 * Get the register or sub-field value.
1432 */
1433 dbgfR3RegValClear(pValue);
1434 if (!pSubField)
[35505]1435 {
[35466]1436 rc = pDesc->pfnGet(pSet->uUserArg.pv, pDesc, pValue);
[35505]1437 if ( pLookupRec->pAlias
1438 && pLookupRec->pAlias->enmType != enmValueType
1439 && RT_SUCCESS(rc))
1440 {
1441 rc = dbgfR3RegValCast(pValue, enmValueType, pLookupRec->pAlias->enmType);
1442 enmValueType = pLookupRec->pAlias->enmType;
1443 }
1444 }
[35466]1445 else
1446 {
1447 if (pSubField->pfnGet)
1448 {
1449 rc = pSubField->pfnGet(pSet->uUserArg.pv, pSubField, &pValue->u128);
1450 enmValueType = DBGFREGVALTYPE_U128;
1451 }
1452 else
1453 {
1454 rc = pDesc->pfnGet(pSet->uUserArg.pv, pDesc, pValue);
[35505]1455 if ( pLookupRec->pAlias
1456 && pLookupRec->pAlias->enmType != enmValueType
1457 && RT_SUCCESS(rc))
1458 {
1459 rc = dbgfR3RegValCast(pValue, enmValueType, pLookupRec->pAlias->enmType);
1460 enmValueType = pLookupRec->pAlias->enmType;
1461 }
[35466]1462 if (RT_SUCCESS(rc))
1463 {
1464 rc = dbgfR3RegValCast(pValue, enmValueType, DBGFREGVALTYPE_U128);
1465 if (RT_SUCCESS(rc))
1466 {
[35490]1467 RTUInt128AssignShiftLeft(&pValue->u128, -pSubField->iFirstBit);
1468 RTUInt128AssignAndNFirstBits(&pValue->u128, pSubField->cBits);
[35466]1469 if (pSubField->cShift)
[35490]1470 RTUInt128AssignShiftLeft(&pValue->u128, pSubField->cShift);
[35466]1471 }
1472 }
1473 }
1474 if (RT_SUCCESS(rc))
1475 {
1476 unsigned const cBits = pSubField->cBits + pSubField->cShift;
1477 if (cBits <= 8)
1478 enmValueType = DBGFREGVALTYPE_U8;
1479 else if (cBits <= 16)
1480 enmValueType = DBGFREGVALTYPE_U16;
1481 else if (cBits <= 32)
1482 enmValueType = DBGFREGVALTYPE_U32;
1483 else if (cBits <= 64)
1484 enmValueType = DBGFREGVALTYPE_U64;
1485 else
1486 enmValueType = DBGFREGVALTYPE_U128;
1487 rc = dbgfR3RegValCast(pValue, DBGFREGVALTYPE_U128, enmValueType);
1488 }
1489 }
1490 if (RT_SUCCESS(rc))
1491 {
1492 /*
1493 * Do the cast if the desired return type doesn't match what
1494 * the getter returned.
1495 */
1496 if ( enmValueType == enmType
1497 || enmType == DBGFREGVALTYPE_END)
1498 {
1499 rc = VINF_SUCCESS;
1500 if (penmType)
1501 *penmType = enmValueType;
1502 }
1503 else
1504 {
1505 rc = dbgfR3RegValCast(pValue, enmValueType, enmType);
1506 if (penmType)
1507 *penmType = RT_SUCCESS(rc) ? enmType : enmValueType;
1508 }
1509 }
1510
1511 return rc;
1512}
1513
1514
1515/**
1516 * Worker for the register queries.
1517 *
1518 * @returns VBox status code.
1519 * @retval VINF_SUCCESS
1520 * @retval VERR_INVALID_VM_HANDLE
1521 * @retval VERR_INVALID_CPU_ID
1522 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1523 * @retval VERR_DBGF_UNSUPPORTED_CAST
1524 * @retval VINF_DBGF_TRUNCATED_REGISTER
1525 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1526 *
[44399]1527 * @param pUVM The user mode VM handle.
[35466]1528 * @param idDefCpu The virtual CPU ID for the default CPU register
[35606]1529 * set. Can be OR'ed with DBGFREG_HYPER_VMCPUID.
[35466]1530 * @param pszReg The register to query.
1531 * @param enmType The desired return type.
1532 * @param pValue Where to return the register value.
1533 * @param penmType Where to store the register value type.
1534 * Optional.
1535 */
[44399]1536static int dbgfR3RegNmQueryWorker(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, DBGFREGVALTYPE enmType,
[35550]1537 PDBGFREGVAL pValue, PDBGFREGVALTYPE penmType)
[35466]1538{
1539 /*
1540 * Validate input.
1541 */
[44399]1542 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1543 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
1544 AssertReturn((idDefCpu & ~DBGFREG_HYPER_VMCPUID) < pUVM->cCpus || idDefCpu == VMCPUID_ANY, VERR_INVALID_CPU_ID);
[35466]1545 AssertPtrReturn(pszReg, VERR_INVALID_POINTER);
1546
1547 Assert(enmType > DBGFREGVALTYPE_INVALID && enmType <= DBGFREGVALTYPE_END);
1548 AssertPtr(pValue);
1549
1550 /*
1551 * Resolve the register and call the getter on the relevant CPU.
1552 */
[46155]1553 bool fGuestRegs = true;
1554 if ((idDefCpu & DBGFREG_HYPER_VMCPUID) && idDefCpu != VMCPUID_ANY)
1555 {
1556 fGuestRegs = false;
1557 idDefCpu &= ~DBGFREG_HYPER_VMCPUID;
1558 }
[44399]1559 PCDBGFREGLOOKUP pLookupRec = dbgfR3RegResolve(pUVM, idDefCpu, pszReg, fGuestRegs);
[35466]1560 if (pLookupRec)
1561 {
1562 if (pLookupRec->pSet->enmType == DBGFREGSETTYPE_CPU)
1563 idDefCpu = pLookupRec->pSet->uUserArg.pVCpu->idCpu;
[35606]1564 else if (idDefCpu != VMCPUID_ANY)
1565 idDefCpu &= ~DBGFREG_HYPER_VMCPUID;
[44399]1566 return VMR3ReqPriorityCallWaitU(pUVM, idDefCpu, (PFNRT)dbgfR3RegNmQueryWorkerOnCpu, 5,
1567 pUVM, pLookupRec, enmType, pValue, penmType);
[35466]1568 }
1569 return VERR_DBGF_REGISTER_NOT_FOUND;
1570}
1571
1572
1573/**
1574 * Queries a descriptor table register value.
1575 *
1576 * @retval VINF_SUCCESS
1577 * @retval VERR_INVALID_VM_HANDLE
1578 * @retval VERR_INVALID_CPU_ID
1579 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1580 *
[44399]1581 * @param pUVM The user mode VM handle.
[35466]1582 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
[35606]1583 * applicable. Can be OR'ed with
1584 * DBGFREG_HYPER_VMCPUID.
[35466]1585 * @param pszReg The register that's being queried. Except for
1586 * CPU registers, this must be on the form
1587 * "set.reg[.sub]".
1588 * @param pValue Where to store the register value.
1589 * @param penmType Where to store the register value type.
1590 */
[44399]1591VMMR3DECL(int) DBGFR3RegNmQuery(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, PDBGFREGVAL pValue, PDBGFREGVALTYPE penmType)
[35466]1592{
[44399]1593 return dbgfR3RegNmQueryWorker(pUVM, idDefCpu, pszReg, DBGFREGVALTYPE_END, pValue, penmType);
[35466]1594}
1595
1596
1597/**
1598 * Queries a 8-bit register value.
1599 *
1600 * @retval VINF_SUCCESS
1601 * @retval VERR_INVALID_VM_HANDLE
1602 * @retval VERR_INVALID_CPU_ID
1603 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1604 * @retval VERR_DBGF_UNSUPPORTED_CAST
1605 * @retval VINF_DBGF_TRUNCATED_REGISTER
1606 *
[44399]1607 * @param pUVM The user mode VM handle.
[35466]1608 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
[35606]1609 * applicable. Can be OR'ed with
1610 * DBGFREG_HYPER_VMCPUID.
[35466]1611 * @param pszReg The register that's being queried. Except for
1612 * CPU registers, this must be on the form
1613 * "set.reg[.sub]".
1614 * @param pu8 Where to store the register value.
1615 */
[44399]1616VMMR3DECL(int) DBGFR3RegNmQueryU8(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint8_t *pu8)
[35466]1617{
1618 DBGFREGVAL Value;
[44399]1619 int rc = dbgfR3RegNmQueryWorker(pUVM, idDefCpu, pszReg, DBGFREGVALTYPE_U8, &Value, NULL);
[35466]1620 if (RT_SUCCESS(rc))
1621 *pu8 = Value.u8;
1622 else
1623 *pu8 = 0;
1624 return rc;
1625}
1626
1627
1628/**
1629 * Queries a 16-bit register value.
1630 *
1631 * @retval VINF_SUCCESS
1632 * @retval VERR_INVALID_VM_HANDLE
1633 * @retval VERR_INVALID_CPU_ID
1634 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1635 * @retval VERR_DBGF_UNSUPPORTED_CAST
1636 * @retval VINF_DBGF_TRUNCATED_REGISTER
1637 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1638 *
[44399]1639 * @param pUVM The user mode VM handle.
[35466]1640 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
[35606]1641 * applicable. Can be OR'ed with
1642 * DBGFREG_HYPER_VMCPUID.
[35466]1643 * @param pszReg The register that's being queried. Except for
1644 * CPU registers, this must be on the form
1645 * "set.reg[.sub]".
1646 * @param pu16 Where to store the register value.
1647 */
[44399]1648VMMR3DECL(int) DBGFR3RegNmQueryU16(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint16_t *pu16)
[35466]1649{
1650 DBGFREGVAL Value;
[44399]1651 int rc = dbgfR3RegNmQueryWorker(pUVM, idDefCpu, pszReg, DBGFREGVALTYPE_U16, &Value, NULL);
[35466]1652 if (RT_SUCCESS(rc))
1653 *pu16 = Value.u16;
1654 else
1655 *pu16 = 0;
1656 return rc;
1657}
1658
1659
1660/**
1661 * Queries a 32-bit 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 pu32 Where to store the register value.
1679 */
[44399]1680VMMR3DECL(int) DBGFR3RegNmQueryU32(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint32_t *pu32)
[35466]1681{
1682 DBGFREGVAL Value;
[44399]1683 int rc = dbgfR3RegNmQueryWorker(pUVM, idDefCpu, pszReg, DBGFREGVALTYPE_U32, &Value, NULL);
[35466]1684 if (RT_SUCCESS(rc))
1685 *pu32 = Value.u32;
1686 else
1687 *pu32 = 0;
1688 return rc;
1689}
1690
1691
1692/**
1693 * Queries a 64-bit register value.
1694 *
1695 * @retval VINF_SUCCESS
1696 * @retval VERR_INVALID_VM_HANDLE
1697 * @retval VERR_INVALID_CPU_ID
1698 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1699 * @retval VERR_DBGF_UNSUPPORTED_CAST
1700 * @retval VINF_DBGF_TRUNCATED_REGISTER
1701 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1702 *
[44399]1703 * @param pUVM The user mode VM handle.
[35466]1704 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
[35606]1705 * applicable. Can be OR'ed with
1706 * DBGFREG_HYPER_VMCPUID.
[35466]1707 * @param pszReg The register that's being queried. Except for
1708 * CPU registers, this must be on the form
1709 * "set.reg[.sub]".
1710 * @param pu64 Where to store the register value.
1711 */
[44399]1712VMMR3DECL(int) DBGFR3RegNmQueryU64(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64)
[35466]1713{
1714 DBGFREGVAL Value;
[44399]1715 int rc = dbgfR3RegNmQueryWorker(pUVM, idDefCpu, pszReg, DBGFREGVALTYPE_U64, &Value, NULL);
[35466]1716 if (RT_SUCCESS(rc))
1717 *pu64 = Value.u64;
1718 else
1719 *pu64 = 0;
1720 return rc;
1721}
1722
1723
1724/**
1725 * Queries a 128-bit register value.
1726 *
1727 * @retval VINF_SUCCESS
1728 * @retval VERR_INVALID_VM_HANDLE
1729 * @retval VERR_INVALID_CPU_ID
1730 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1731 * @retval VERR_DBGF_UNSUPPORTED_CAST
1732 * @retval VINF_DBGF_TRUNCATED_REGISTER
1733 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1734 *
[44399]1735 * @param pUVM The user mode VM handle.
[35466]1736 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
[35606]1737 * applicable. Can be OR'ed with
1738 * DBGFREG_HYPER_VMCPUID.
[35466]1739 * @param pszReg The register that's being queried. Except for
1740 * CPU registers, this must be on the form
1741 * "set.reg[.sub]".
1742 * @param pu128 Where to store the register value.
1743 */
[44399]1744VMMR3DECL(int) DBGFR3RegNmQueryU128(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, PRTUINT128U pu128)
[35466]1745{
1746 DBGFREGVAL Value;
[44399]1747 int rc = dbgfR3RegNmQueryWorker(pUVM, idDefCpu, pszReg, DBGFREGVALTYPE_U128, &Value, NULL);
[35466]1748 if (RT_SUCCESS(rc))
1749 *pu128 = Value.u128;
1750 else
1751 pu128->s.Hi = pu128->s.Lo = 0;
1752 return rc;
1753}
1754
1755
[35513]1756#if 0
[35466]1757/**
1758 * Queries a long double register value.
1759 *
1760 * @retval VINF_SUCCESS
1761 * @retval VERR_INVALID_VM_HANDLE
1762 * @retval VERR_INVALID_CPU_ID
1763 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1764 * @retval VERR_DBGF_UNSUPPORTED_CAST
1765 * @retval VINF_DBGF_TRUNCATED_REGISTER
1766 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1767 *
[44399]1768 * @param pUVM The user mode VM handle.
[35466]1769 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
[35606]1770 * applicable. Can be OR'ed with
1771 * DBGFREG_HYPER_VMCPUID.
[35466]1772 * @param pszReg The register that's being queried. Except for
1773 * CPU registers, this must be on the form
1774 * "set.reg[.sub]".
1775 * @param plrd Where to store the register value.
1776 */
[44399]1777VMMR3DECL(int) DBGFR3RegNmQueryLrd(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, long double *plrd)
[35466]1778{
1779 DBGFREGVAL Value;
[44399]1780 int rc = dbgfR3RegNmQueryWorker(pUVM, idDefCpu, pszReg, DBGFREGVALTYPE_R80, &Value, NULL);
[35466]1781 if (RT_SUCCESS(rc))
1782 *plrd = Value.lrd;
1783 else
1784 *plrd = 0;
1785 return rc;
1786}
[35513]1787#endif
[35466]1788
1789
1790/**
1791 * Queries a descriptor table register value.
1792 *
1793 * @retval VINF_SUCCESS
1794 * @retval VERR_INVALID_VM_HANDLE
1795 * @retval VERR_INVALID_CPU_ID
1796 * @retval VERR_DBGF_REGISTER_NOT_FOUND
1797 * @retval VERR_DBGF_UNSUPPORTED_CAST
1798 * @retval VINF_DBGF_TRUNCATED_REGISTER
1799 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
1800 *
[44399]1801 * @param pUVM The user mode VM handle.
[35466]1802 * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
[35606]1803 * applicable. Can be OR'ed with
1804 * DBGFREG_HYPER_VMCPUID.
[35466]1805 * @param pszReg The register that's being queried. Except for
1806 * CPU registers, this must be on the form
1807 * "set.reg[.sub]".
1808 * @param pu64Base Where to store the register base value.
[73417]1809 * @param pu16Limit Where to store the register limit value.
[35466]1810 */
[73417]1811VMMR3DECL(int) DBGFR3RegNmQueryXdtr(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64Base, uint16_t *pu16Limit)
[35466]1812{
1813 DBGFREGVAL Value;
[44399]1814 int rc = dbgfR3RegNmQueryWorker(pUVM, idDefCpu, pszReg, DBGFREGVALTYPE_DTR, &Value, NULL);
[35466]1815 if (RT_SUCCESS(rc))
1816 {
1817 *pu64Base = Value.dtr.u64Base;
[73417]1818 *pu16Limit = Value.dtr.u32Limit;
[35466]1819 }
1820 else
1821 {
1822 *pu64Base = 0;
[73417]1823 *pu16Limit = 0;
[35466]1824 }
1825 return rc;
1826}
1827
1828
[44399]1829/// @todo VMMR3DECL(int) DBGFR3RegNmQueryBatch(PUVM pUVM,VMCPUID idDefCpu, DBGFREGENTRYNM paRegs, size_t cRegs);
[35466]1830
1831
1832/**
1833 * Gets the number of registers returned by DBGFR3RegNmQueryAll.
1834 *
1835 * @returns VBox status code.
[44399]1836 * @param pUVM The user mode VM handle.
[35466]1837 * @param pcRegs Where to return the register count.
1838 */
[44399]1839VMMR3DECL(int) DBGFR3RegNmQueryAllCount(PUVM pUVM, size_t *pcRegs)
[35466]1840{
[44399]1841 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1842 *pcRegs = pUVM->dbgf.s.cRegs;
[35466]1843 return VINF_SUCCESS;
1844}
1845
1846
[35550]1847/**
1848 * Pad register entries.
1849 *
1850 * @param paRegs The output array.
1851 * @param cRegs The size of the output array.
1852 * @param iReg The first register to pad.
1853 * @param cRegsToPad The number of registers to pad.
1854 */
1855static void dbgfR3RegNmQueryAllPadEntries(PDBGFREGENTRYNM paRegs, size_t cRegs, size_t iReg, size_t cRegsToPad)
[35466]1856{
[35550]1857 if (iReg < cRegs)
1858 {
1859 size_t iEndReg = iReg + cRegsToPad;
1860 if (iEndReg > cRegs)
1861 iEndReg = cRegs;
1862 while (iReg < iEndReg)
1863 {
1864 paRegs[iReg].pszName = NULL;
1865 paRegs[iReg].enmType = DBGFREGVALTYPE_END;
1866 dbgfR3RegValClear(&paRegs[iReg].Val);
1867 iReg++;
1868 }
1869 }
[35466]1870}
1871
1872
[35550]1873/**
1874 * Query all registers in a set.
1875 *
1876 * @param pSet The set.
1877 * @param cRegsToQuery The number of registers to query.
1878 * @param paRegs The output array.
1879 * @param cRegs The size of the output array.
1880 */
1881static void dbgfR3RegNmQueryAllInSet(PCDBGFREGSET pSet, size_t cRegsToQuery, PDBGFREGENTRYNM paRegs, size_t cRegs)
1882{
1883 if (cRegsToQuery > pSet->cDescs)
1884 cRegsToQuery = pSet->cDescs;
1885 if (cRegsToQuery > cRegs)
1886 cRegsToQuery = cRegs;
1887
1888 for (size_t iReg = 0; iReg < cRegsToQuery; iReg++)
1889 {
1890 paRegs[iReg].enmType = pSet->paDescs[iReg].enmType;
1891 paRegs[iReg].pszName = pSet->paLookupRecs[iReg].Core.pszString;
1892 dbgfR3RegValClear(&paRegs[iReg].Val);
1893 int rc2 = pSet->paDescs[iReg].pfnGet(pSet->uUserArg.pv, &pSet->paDescs[iReg], &paRegs[iReg].Val);
1894 AssertRCSuccess(rc2);
1895 if (RT_FAILURE(rc2))
1896 dbgfR3RegValClear(&paRegs[iReg].Val);
1897 }
1898}
1899
1900
1901/**
1902 * @callback_method_impl{FNRTSTRSPACECALLBACK, Worker used by
1903 * dbgfR3RegNmQueryAllWorker}
1904 */
1905static DECLCALLBACK(int) dbgfR3RegNmQueryAllEnum(PRTSTRSPACECORE pStr, void *pvUser)
1906{
1907 PCDBGFREGSET pSet = (PCDBGFREGSET)pStr;
1908 if (pSet->enmType != DBGFREGSETTYPE_CPU)
1909 {
1910 PDBGFR3REGNMQUERYALLARGS pArgs = (PDBGFR3REGNMQUERYALLARGS)pvUser;
1911 if (pArgs->iReg < pArgs->cRegs)
1912 dbgfR3RegNmQueryAllInSet(pSet, pSet->cDescs, &pArgs->paRegs[pArgs->iReg], pArgs->cRegs - pArgs->iReg);
1913 pArgs->iReg += pSet->cDescs;
1914 }
1915
1916 return 0;
1917}
1918
1919
1920/**
1921 * @callback_method_impl{FNVMMEMTRENDEZVOUS, Worker used by DBGFR3RegNmQueryAll}
1922 */
1923static DECLCALLBACK(VBOXSTRICTRC) dbgfR3RegNmQueryAllWorker(PVM pVM, PVMCPU pVCpu, void *pvUser)
1924{
1925 PDBGFR3REGNMQUERYALLARGS pArgs = (PDBGFR3REGNMQUERYALLARGS)pvUser;
1926 PDBGFREGENTRYNM paRegs = pArgs->paRegs;
1927 size_t const cRegs = pArgs->cRegs;
[44399]1928 PUVM pUVM = pVM->pUVM;
1929 PUVMCPU pUVCpu = pVCpu->pUVCpu;
[35550]1930
[44399]1931 DBGF_REG_DB_LOCK_READ(pUVM);
[35586]1932
[35550]1933 /*
[35601]1934 * My guest CPU registers.
[35550]1935 */
1936 size_t iCpuReg = pVCpu->idCpu * DBGFREG_ALL_COUNT;
[44399]1937 if (pUVCpu->dbgf.s.pGuestRegSet)
[35550]1938 {
1939 if (iCpuReg < cRegs)
[44399]1940 dbgfR3RegNmQueryAllInSet(pUVCpu->dbgf.s.pGuestRegSet, DBGFREG_ALL_COUNT, &paRegs[iCpuReg], cRegs - iCpuReg);
[35550]1941 }
1942 else
1943 dbgfR3RegNmQueryAllPadEntries(paRegs, cRegs, iCpuReg, DBGFREG_ALL_COUNT);
1944
1945 /*
[35601]1946 * My hypervisor CPU registers.
1947 */
[44399]1948 iCpuReg = pUVM->cCpus * DBGFREG_ALL_COUNT + pUVCpu->idCpu * DBGFREG_ALL_COUNT;
1949 if (pUVCpu->dbgf.s.pHyperRegSet)
[35601]1950 {
1951 if (iCpuReg < cRegs)
[44399]1952 dbgfR3RegNmQueryAllInSet(pUVCpu->dbgf.s.pHyperRegSet, DBGFREG_ALL_COUNT, &paRegs[iCpuReg], cRegs - iCpuReg);
[35601]1953 }
1954 else
1955 dbgfR3RegNmQueryAllPadEntries(paRegs, cRegs, iCpuReg, DBGFREG_ALL_COUNT);
1956
1957 /*
[35550]1958 * The primary CPU does all the other registers.
1959 */
[44399]1960 if (pUVCpu->idCpu == 0)
[35550]1961 {
[44399]1962 pArgs->iReg = pUVM->cCpus * DBGFREG_ALL_COUNT * 2;
1963 RTStrSpaceEnumerate(&pUVM->dbgf.s.RegSetSpace, dbgfR3RegNmQueryAllEnum, pArgs);
[35550]1964 dbgfR3RegNmQueryAllPadEntries(paRegs, cRegs, pArgs->iReg, cRegs);
1965 }
1966
[44399]1967 DBGF_REG_DB_UNLOCK_READ(pUVM);
[35550]1968 return VINF_SUCCESS; /* Ignore errors. */
1969}
1970
1971
1972/**
1973 * Queries all register.
1974 *
1975 * @returns VBox status code.
[44399]1976 * @param pUVM The user mode VM handle.
[35550]1977 * @param paRegs The output register value array. The register
1978 * name string is read only and shall not be freed
1979 * or modified.
1980 * @param cRegs The number of entries in @a paRegs. The
1981 * correct size can be obtained by calling
1982 * DBGFR3RegNmQueryAllCount.
1983 */
[44399]1984VMMR3DECL(int) DBGFR3RegNmQueryAll(PUVM pUVM, PDBGFREGENTRYNM paRegs, size_t cRegs)
[35550]1985{
[44399]1986 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1987 PVM pVM = pUVM->pVM;
[35550]1988 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1989 AssertPtrReturn(paRegs, VERR_INVALID_POINTER);
1990 AssertReturn(cRegs > 0, VERR_OUT_OF_RANGE);
1991
1992 DBGFR3REGNMQUERYALLARGS Args;
1993 Args.paRegs = paRegs;
1994 Args.cRegs = cRegs;
1995
1996 return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3RegNmQueryAllWorker, &Args);
1997}
1998
1999
[48898]2000/**
2001 * On CPU worker for the register modifications, used by DBGFR3RegNmSet.
2002 *
2003 * @returns VBox status code.
2004 *
2005 * @param pUVM The user mode VM handle.
2006 * @param pLookupRec The register lookup record. Maybe be modified,
2007 * so please pass a copy of the user's one.
2008 * @param pValue The new register value.
[58126]2009 * @param pMask Indicate which bits to modify.
[48898]2010 */
2011static DECLCALLBACK(int) dbgfR3RegNmSetWorkerOnCpu(PUVM pUVM, PDBGFREGLOOKUP pLookupRec,
2012 PCDBGFREGVAL pValue, PCDBGFREGVAL pMask)
2013{
[62637]2014 RT_NOREF_PV(pUVM);
[48898]2015 PCDBGFREGSUBFIELD pSubField = pLookupRec->pSubField;
2016 if (pSubField && pSubField->pfnSet)
2017 return pSubField->pfnSet(pLookupRec->pSet->uUserArg.pv, pSubField, pValue->u128, pMask->u128);
2018 return pLookupRec->pDesc->pfnSet(pLookupRec->pSet->uUserArg.pv, pLookupRec->pDesc, pValue, pMask);
2019}
2020
2021
2022/**
2023 * Worker for the register setting.
2024 *
2025 * @returns VBox status code.
2026 * @retval VINF_SUCCESS
2027 * @retval VERR_INVALID_VM_HANDLE
2028 * @retval VERR_INVALID_CPU_ID
2029 * @retval VERR_DBGF_REGISTER_NOT_FOUND
2030 * @retval VERR_DBGF_UNSUPPORTED_CAST
2031 * @retval VINF_DBGF_TRUNCATED_REGISTER
2032 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
2033 *
2034 * @param pUVM The user mode VM handle.
2035 * @param idDefCpu The virtual CPU ID for the default CPU register
2036 * set. Can be OR'ed with DBGFREG_HYPER_VMCPUID.
2037 * @param pszReg The register to query.
2038 * @param pValue The value to set
2039 * @param enmType How to interpret the value in @a pValue.
2040 */
[44399]2041VMMR3DECL(int) DBGFR3RegNmSet(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType)
[35625]2042{
[48898]2043 /*
2044 * Validate input.
2045 */
2046 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
2047 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
2048 AssertReturn((idDefCpu & ~DBGFREG_HYPER_VMCPUID) < pUVM->cCpus || idDefCpu == VMCPUID_ANY, VERR_INVALID_CPU_ID);
2049 AssertPtrReturn(pszReg, VERR_INVALID_POINTER);
2050 AssertReturn(enmType > DBGFREGVALTYPE_INVALID && enmType < DBGFREGVALTYPE_END, VERR_INVALID_PARAMETER);
2051 AssertPtrReturn(pValue, VERR_INVALID_PARAMETER);
2052
2053 /*
2054 * Resolve the register and check that it is writable.
2055 */
2056 bool fGuestRegs = true;
2057 if ((idDefCpu & DBGFREG_HYPER_VMCPUID) && idDefCpu != VMCPUID_ANY)
2058 {
2059 fGuestRegs = false;
2060 idDefCpu &= ~DBGFREG_HYPER_VMCPUID;
2061 }
2062 PCDBGFREGLOOKUP pLookupRec = dbgfR3RegResolve(pUVM, idDefCpu, pszReg, fGuestRegs);
2063 if (pLookupRec)
2064 {
2065 PCDBGFREGDESC pDesc = pLookupRec->pDesc;
2066 PCDBGFREGSET pSet = pLookupRec->pSet;
2067 PCDBGFREGSUBFIELD pSubField = pLookupRec->pSubField;
2068
2069 if ( !(pDesc->fFlags & DBGFREG_FLAGS_READ_ONLY)
2070 && (pSubField
2071 ? !(pSubField->fFlags & DBGFREGSUBFIELD_FLAGS_READ_ONLY)
2072 && (pSubField->pfnSet != NULL || pDesc->pfnSet != NULL)
2073 : pDesc->pfnSet != NULL) )
2074 {
2075 /*
2076 * Calculate the modification mask and cast the input value to the
2077 * type of the target register.
2078 */
2079 DBGFREGVAL Mask = DBGFREGVAL_INITIALIZE_ZERO;
2080 DBGFREGVAL Value = DBGFREGVAL_INITIALIZE_ZERO;
2081 switch (enmType)
2082 {
2083 case DBGFREGVALTYPE_U8:
2084 Value.u8 = pValue->u8;
2085 Mask.u8 = UINT8_MAX;
2086 break;
2087 case DBGFREGVALTYPE_U16:
2088 Value.u16 = pValue->u16;
2089 Mask.u16 = UINT16_MAX;
2090 break;
2091 case DBGFREGVALTYPE_U32:
2092 Value.u32 = pValue->u32;
2093 Mask.u32 = UINT32_MAX;
2094 break;
2095 case DBGFREGVALTYPE_U64:
2096 Value.u64 = pValue->u64;
2097 Mask.u64 = UINT64_MAX;
2098 break;
2099 case DBGFREGVALTYPE_U128:
2100 Value.u128 = pValue->u128;
2101 Mask.u128.s.Lo = UINT64_MAX;
2102 Mask.u128.s.Hi = UINT64_MAX;
2103 break;
[66885]2104 case DBGFREGVALTYPE_U256:
2105 Value.u256 = pValue->u256;
2106 Mask.u256.QWords.qw0 = UINT64_MAX;
2107 Mask.u256.QWords.qw1 = UINT64_MAX;
2108 Mask.u256.QWords.qw2 = UINT64_MAX;
2109 Mask.u256.QWords.qw3 = UINT64_MAX;
2110 break;
2111 case DBGFREGVALTYPE_U512:
2112 Value.u512 = pValue->u512;
2113 Mask.u512.QWords.qw0 = UINT64_MAX;
2114 Mask.u512.QWords.qw1 = UINT64_MAX;
2115 Mask.u512.QWords.qw2 = UINT64_MAX;
2116 Mask.u512.QWords.qw3 = UINT64_MAX;
2117 Mask.u512.QWords.qw4 = UINT64_MAX;
2118 Mask.u512.QWords.qw5 = UINT64_MAX;
2119 Mask.u512.QWords.qw6 = UINT64_MAX;
2120 Mask.u512.QWords.qw7 = UINT64_MAX;
2121 break;
[48898]2122 case DBGFREGVALTYPE_R80:
2123#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
2124 Value.r80Ex.lrd = pValue->r80Ex.lrd;
2125#else
2126 Value.r80Ex.au64[0] = pValue->r80Ex.au64[0];
2127 Value.r80Ex.au16[4] = pValue->r80Ex.au16[4];
2128#endif
2129 Value.r80Ex.au64[0] = UINT64_MAX;
2130 Value.r80Ex.au16[4] = UINT16_MAX;
2131 break;
2132 case DBGFREGVALTYPE_DTR:
2133 Value.dtr.u32Limit = pValue->dtr.u32Limit;
2134 Value.dtr.u64Base = pValue->dtr.u64Base;
2135 Mask.dtr.u32Limit = UINT32_MAX;
2136 Mask.dtr.u64Base = UINT64_MAX;
2137 break;
2138 case DBGFREGVALTYPE_32BIT_HACK:
2139 case DBGFREGVALTYPE_END:
2140 case DBGFREGVALTYPE_INVALID:
2141 AssertFailedReturn(VERR_INTERNAL_ERROR_3);
2142 }
2143
2144 int rc = VINF_SUCCESS;
2145 DBGFREGVALTYPE enmRegType = pDesc->enmType;
2146 if (pSubField)
2147 {
2148 unsigned const cBits = pSubField->cBits + pSubField->cShift;
2149 if (cBits <= 8)
2150 enmRegType = DBGFREGVALTYPE_U8;
2151 else if (cBits <= 16)
2152 enmRegType = DBGFREGVALTYPE_U16;
2153 else if (cBits <= 32)
2154 enmRegType = DBGFREGVALTYPE_U32;
2155 else if (cBits <= 64)
2156 enmRegType = DBGFREGVALTYPE_U64;
[66885]2157 else if (cBits <= 128)
2158 enmRegType = DBGFREGVALTYPE_U128;
2159 else if (cBits <= 256)
2160 enmRegType = DBGFREGVALTYPE_U256;
[48898]2161 else
[66885]2162 enmRegType = DBGFREGVALTYPE_U512;
[48898]2163 }
2164 else if (pLookupRec->pAlias)
2165 {
2166 /* Restrict the input to the size of the alias register. */
2167 DBGFREGVALTYPE enmAliasType = pLookupRec->pAlias->enmType;
2168 if (enmAliasType != enmType)
2169 {
2170 rc = dbgfR3RegValCast(&Value, enmType, enmAliasType);
2171 if (RT_FAILURE(rc))
2172 return rc;
2173 dbgfR3RegValCast(&Mask, enmType, enmAliasType);
2174 enmType = enmAliasType;
2175 }
2176 }
2177
2178 if (enmType != enmRegType)
2179 {
2180 int rc2 = dbgfR3RegValCast(&Value, enmType, enmRegType);
2181 if (RT_FAILURE(rc2))
2182 return rc2;
2183 if (rc2 != VINF_SUCCESS && rc == VINF_SUCCESS)
2184 rc2 = VINF_SUCCESS;
2185 dbgfR3RegValCast(&Mask, enmType, enmRegType);
2186 }
2187
2188 /*
2189 * Subfields needs some extra processing if there is no subfield
2190 * setter, since we'll be feeding it to the normal register setter
2191 * instead. The mask and value must be shifted and truncated to the
2192 * subfield position.
2193 */
2194 if (pSubField && !pSubField->pfnSet)
2195 {
2196 /* The shift factor is for displaying a subfield value
2197 2**cShift times larger than the stored value. We have
2198 to undo this before adjusting value and mask. */
2199 if (pSubField->cShift)
2200 {
2201 /* Warn about trunction of the lower bits that get
2202 shifted out below. */
2203 if (rc == VINF_SUCCESS)
2204 {
2205 DBGFREGVAL Value2 = Value;
2206 RTUInt128AssignAndNFirstBits(&Value2.u128, -pSubField->cShift);
2207 if (!RTUInt128BitAreAllClear(&Value2.u128))
2208 rc = VINF_DBGF_TRUNCATED_REGISTER;
2209 }
2210 RTUInt128AssignShiftRight(&Value.u128, pSubField->cShift);
2211 }
2212
2213 RTUInt128AssignAndNFirstBits(&Value.u128, pSubField->cBits);
2214 if (rc == VINF_SUCCESS && RTUInt128IsNotEqual(&Value.u128, &Value.u128))
2215 rc = VINF_DBGF_TRUNCATED_REGISTER;
2216 RTUInt128AssignAndNFirstBits(&Mask.u128, pSubField->cBits);
2217
2218 RTUInt128AssignShiftLeft(&Value.u128, pSubField->iFirstBit);
2219 RTUInt128AssignShiftLeft(&Mask.u128, pSubField->iFirstBit);
2220 }
2221
2222 /*
2223 * Do the actual work on an EMT.
2224 */
2225 if (pSet->enmType == DBGFREGSETTYPE_CPU)
2226 idDefCpu = pSet->uUserArg.pVCpu->idCpu;
2227 else if (idDefCpu != VMCPUID_ANY)
2228 idDefCpu &= ~DBGFREG_HYPER_VMCPUID;
2229
2230 int rc2 = VMR3ReqPriorityCallWaitU(pUVM, idDefCpu, (PFNRT)dbgfR3RegNmSetWorkerOnCpu, 4,
2231 pUVM, pLookupRec, &Value, &Mask);
2232
2233 if (rc == VINF_SUCCESS || RT_FAILURE(rc2))
2234 rc = rc2;
2235 return rc;
2236 }
2237 return VERR_DBGF_READ_ONLY_REGISTER;
2238 }
2239 return VERR_DBGF_REGISTER_NOT_FOUND;
[35625]2240}
2241
2242
[35586]2243/**
[58126]2244 * Internal worker for DBGFR3RegFormatValue, cbBuf is sufficent.
[35586]2245 *
[58126]2246 * @copydoc DBGFR3RegFormatValueEx
[35586]2247 */
[58126]2248DECLINLINE(ssize_t) dbgfR3RegFormatValueInt(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType,
[35586]2249 unsigned uBase, signed int cchWidth, signed int cchPrecision, uint32_t fFlags)
2250{
2251 switch (enmType)
2252 {
2253 case DBGFREGVALTYPE_U8:
[58126]2254 return RTStrFormatU8(pszBuf, cbBuf, pValue->u8, uBase, cchWidth, cchPrecision, fFlags);
[35586]2255 case DBGFREGVALTYPE_U16:
[58126]2256 return RTStrFormatU16(pszBuf, cbBuf, pValue->u16, uBase, cchWidth, cchPrecision, fFlags);
[35586]2257 case DBGFREGVALTYPE_U32:
[58126]2258 return RTStrFormatU32(pszBuf, cbBuf, pValue->u32, uBase, cchWidth, cchPrecision, fFlags);
[35586]2259 case DBGFREGVALTYPE_U64:
[58126]2260 return RTStrFormatU64(pszBuf, cbBuf, pValue->u64, uBase, cchWidth, cchPrecision, fFlags);
[35586]2261 case DBGFREGVALTYPE_U128:
[58126]2262 return RTStrFormatU128(pszBuf, cbBuf, &pValue->u128, uBase, cchWidth, cchPrecision, fFlags);
[66885]2263 case DBGFREGVALTYPE_U256:
2264 return RTStrFormatU256(pszBuf, cbBuf, &pValue->u256, uBase, cchWidth, cchPrecision, fFlags);
2265 case DBGFREGVALTYPE_U512:
2266 return RTStrFormatU512(pszBuf, cbBuf, &pValue->u512, uBase, cchWidth, cchPrecision, fFlags);
[35586]2267 case DBGFREGVALTYPE_R80:
[58126]2268 return RTStrFormatR80u2(pszBuf, cbBuf, &pValue->r80Ex, cchWidth, cchPrecision, fFlags);
[35586]2269 case DBGFREGVALTYPE_DTR:
2270 {
[58126]2271 ssize_t cch = RTStrFormatU64(pszBuf, cbBuf, pValue->dtr.u64Base,
[35586]2272 16, 2+16, 0, RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD);
[39405]2273 AssertReturn(cch > 0, VERR_DBGF_REG_IPE_1);
[58126]2274 pszBuf[cch++] = ':';
2275 cch += RTStrFormatU64(&pszBuf[cch], cbBuf - cch, pValue->dtr.u32Limit,
[35586]2276 16, 4, 0, RTSTR_F_ZEROPAD | RTSTR_F_32BIT);
2277 return cch;
2278 }
[35466]2279
[35586]2280 case DBGFREGVALTYPE_32BIT_HACK:
2281 case DBGFREGVALTYPE_END:
2282 case DBGFREGVALTYPE_INVALID:
2283 break;
2284 /* no default, want gcc warnings */
2285 }
2286
[58126]2287 RTStrPrintf(pszBuf, cbBuf, "!enmType=%d!", enmType);
[39405]2288 return VERR_DBGF_REG_IPE_2;
[35586]2289}
2290
2291
2292/**
2293 * Format a register value, extended version.
2294 *
2295 * @returns The number of bytes returned, VERR_BUFFER_OVERFLOW on failure.
2296 * @param pszBuf The output buffer.
2297 * @param cbBuf The size of the output buffer.
2298 * @param pValue The value to format.
2299 * @param enmType The value type.
2300 * @param uBase The base (ignored if not applicable).
2301 * @param cchWidth The width if RTSTR_F_WIDTH is set, otherwise
2302 * ignored.
2303 * @param cchPrecision The width if RTSTR_F_PRECISION is set, otherwise
2304 * ignored.
2305 * @param fFlags String formatting flags, RTSTR_F_XXX.
2306 */
[44399]2307VMMR3DECL(ssize_t) DBGFR3RegFormatValueEx(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType,
2308 unsigned uBase, signed int cchWidth, signed int cchPrecision, uint32_t fFlags)
[35586]2309{
2310 /*
[35625]2311 * Format to temporary buffer using worker shared with dbgfR3RegPrintfCbFormatNormal.
[35586]2312 */
2313 char szTmp[160];
2314 ssize_t cchOutput = dbgfR3RegFormatValueInt(szTmp, sizeof(szTmp), pValue, enmType, uBase, cchWidth, cchPrecision, fFlags);
2315 if (cchOutput > 0)
2316 {
2317 if ((size_t)cchOutput < cbBuf)
2318 memcpy(pszBuf, szTmp, cchOutput + 1);
2319 else
2320 {
2321 if (cbBuf)
2322 {
2323 memcpy(pszBuf, szTmp, cbBuf - 1);
2324 pszBuf[cbBuf - 1] = '\0';
2325 }
2326 cchOutput = VERR_BUFFER_OVERFLOW;
2327 }
2328 }
2329 return cchOutput;
2330}
2331
2332
2333/**
2334 * Format a register value as hexadecimal and with default width according to
2335 * the type.
2336 *
2337 * @returns The number of bytes returned, VERR_BUFFER_OVERFLOW on failure.
2338 * @param pszBuf The output buffer.
2339 * @param cbBuf The size of the output buffer.
2340 * @param pValue The value to format.
2341 * @param enmType The value type.
2342 * @param fSpecial Same as RTSTR_F_SPECIAL.
2343 */
[44399]2344VMMR3DECL(ssize_t) DBGFR3RegFormatValue(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType, bool fSpecial)
[35586]2345{
2346 int cchWidth = 0;
2347 switch (enmType)
2348 {
[66885]2349 case DBGFREGVALTYPE_U8: cchWidth = 2 + fSpecial*2; break;
2350 case DBGFREGVALTYPE_U16: cchWidth = 4 + fSpecial*2; break;
2351 case DBGFREGVALTYPE_U32: cchWidth = 8 + fSpecial*2; break;
2352 case DBGFREGVALTYPE_U64: cchWidth = 16 + fSpecial*2; break;
2353 case DBGFREGVALTYPE_U128: cchWidth = 32 + fSpecial*2; break;
2354 case DBGFREGVALTYPE_U256: cchWidth = 64 + fSpecial*2; break;
2355 case DBGFREGVALTYPE_U512: cchWidth = 128 + fSpecial*2; break;
[35586]2356 case DBGFREGVALTYPE_R80: cchWidth = 0; break;
2357 case DBGFREGVALTYPE_DTR: cchWidth = 16+1+4 + fSpecial*2; break;
2358
2359 case DBGFREGVALTYPE_32BIT_HACK:
2360 case DBGFREGVALTYPE_END:
2361 case DBGFREGVALTYPE_INVALID:
2362 break;
2363 /* no default, want gcc warnings */
2364 }
2365 uint32_t fFlags = RTSTR_F_ZEROPAD;
2366 if (fSpecial)
2367 fFlags |= RTSTR_F_SPECIAL;
2368 if (cchWidth != 0)
2369 fFlags |= RTSTR_F_WIDTH;
2370 return DBGFR3RegFormatValueEx(pszBuf, cbBuf, pValue, enmType, 16, cchWidth, 0, fFlags);
2371}
2372
2373
2374/**
[35590]2375 * Format a register using special hacks as well as sub-field specifications
2376 * (the latter isn't implemented yet).
2377 */
2378static size_t
[35625]2379dbgfR3RegPrintfCbFormatField(PDBGFR3REGPRINTFARGS pThis, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
2380 PCDBGFREGLOOKUP pLookupRec, int cchWidth, int cchPrecision, unsigned fFlags)
[35590]2381{
2382 char szTmp[160];
2383
[39078]2384 NOREF(cchWidth); NOREF(cchPrecision); NOREF(fFlags);
2385
[35590]2386 /*
2387 * Retrieve the register value.
2388 */
2389 DBGFREGVAL Value;
2390 DBGFREGVALTYPE enmType;
[44399]2391 int rc = dbgfR3RegNmQueryWorkerOnCpu(pThis->pUVM, pLookupRec, DBGFREGVALTYPE_END, &Value, &enmType);
[35590]2392 if (RT_FAILURE(rc))
2393 {
2394 PCRTSTATUSMSG pErr = RTErrGet(rc);
2395 if (pErr)
2396 return pfnOutput(pvArgOutput, pErr->pszDefine, strlen(pErr->pszDefine));
2397 return pfnOutput(pvArgOutput, szTmp, RTStrPrintf(szTmp, sizeof(szTmp), "rc=%d", rc));
2398 }
2399
2400 char *psz = szTmp;
2401
2402 /*
2403 * Special case: Format eflags.
2404 */
2405 if ( pLookupRec->pSet->enmType == DBGFREGSETTYPE_CPU
2406 && pLookupRec->pDesc->enmReg == DBGFREG_RFLAGS
2407 && pLookupRec->pSubField == NULL)
2408 {
2409 rc = dbgfR3RegValCast(&Value, enmType, DBGFREGVALTYPE_U32);
2410 AssertRC(rc);
2411 uint32_t const efl = Value.u32;
2412
2413 /* the iopl */
2414 psz += RTStrPrintf(psz, sizeof(szTmp) / 2, "iopl=%u ", X86_EFL_GET_IOPL(efl));
2415
2416 /* add flags */
2417 static const struct
2418 {
2419 const char *pszSet;
2420 const char *pszClear;
2421 uint32_t fFlag;
2422 } aFlags[] =
2423 {
2424 { "vip",NULL, X86_EFL_VIP },
2425 { "vif",NULL, X86_EFL_VIF },
2426 { "ac", NULL, X86_EFL_AC },
2427 { "vm", NULL, X86_EFL_VM },
2428 { "rf", NULL, X86_EFL_RF },
2429 { "nt", NULL, X86_EFL_NT },
2430 { "ov", "nv", X86_EFL_OF },
2431 { "dn", "up", X86_EFL_DF },
2432 { "ei", "di", X86_EFL_IF },
2433 { "tf", NULL, X86_EFL_TF },
2434 { "ng", "pl", X86_EFL_SF },
2435 { "zr", "nz", X86_EFL_ZF },
2436 { "ac", "na", X86_EFL_AF },
2437 { "po", "pe", X86_EFL_PF },
2438 { "cy", "nc", X86_EFL_CF },
2439 };
2440 for (unsigned i = 0; i < RT_ELEMENTS(aFlags); i++)
2441 {
2442 const char *pszAdd = aFlags[i].fFlag & efl ? aFlags[i].pszSet : aFlags[i].pszClear;
2443 if (pszAdd)
2444 {
2445 *psz++ = *pszAdd++;
2446 *psz++ = *pszAdd++;
2447 if (*pszAdd)
2448 *psz++ = *pszAdd++;
2449 *psz++ = ' ';
2450 }
2451 }
2452
2453 /* drop trailing space */
2454 psz--;
2455 }
2456 else
2457 {
2458 /*
2459 * General case.
2460 */
2461 AssertMsgFailed(("Not implemented: %s\n", pLookupRec->Core.pszString));
2462 return pfnOutput(pvArgOutput, pLookupRec->Core.pszString, pLookupRec->Core.cchString);
2463 }
2464
2465 /* Output the string. */
2466 return pfnOutput(pvArgOutput, szTmp, psz - &szTmp[0]);
2467}
2468
2469
2470/**
2471 * Formats a register having parsed up to the register name.
2472 */
2473static size_t
[35625]2474dbgfR3RegPrintfCbFormatNormal(PDBGFR3REGPRINTFARGS pThis, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
2475 PCDBGFREGLOOKUP pLookupRec, unsigned uBase, int cchWidth, int cchPrecision, unsigned fFlags)
[35590]2476{
2477 char szTmp[160];
2478
2479 /*
2480 * Get the register value.
2481 */
2482 DBGFREGVAL Value;
2483 DBGFREGVALTYPE enmType;
[44399]2484 int rc = dbgfR3RegNmQueryWorkerOnCpu(pThis->pUVM, pLookupRec, DBGFREGVALTYPE_END, &Value, &enmType);
[35590]2485 if (RT_FAILURE(rc))
2486 {
2487 PCRTSTATUSMSG pErr = RTErrGet(rc);
2488 if (pErr)
2489 return pfnOutput(pvArgOutput, pErr->pszDefine, strlen(pErr->pszDefine));
2490 return pfnOutput(pvArgOutput, szTmp, RTStrPrintf(szTmp, sizeof(szTmp), "rc=%d", rc));
2491 }
2492
2493 /*
2494 * Format the value.
2495 */
2496 ssize_t cchOutput = dbgfR3RegFormatValueInt(szTmp, sizeof(szTmp), &Value, enmType, uBase, cchWidth, cchPrecision, fFlags);
2497 if (RT_UNLIKELY(cchOutput <= 0))
2498 {
2499 AssertFailed();
2500 return pfnOutput(pvArgOutput, "internal-error", sizeof("internal-error") - 1);
2501 }
2502 return pfnOutput(pvArgOutput, szTmp, cchOutput);
2503}
2504
2505
2506/**
[35586]2507 * @callback_method_impl{FNSTRFORMAT}
2508 */
2509static DECLCALLBACK(size_t)
[35625]2510dbgfR3RegPrintfCbFormat(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
2511 const char **ppszFormat, va_list *pArgs, int cchWidth,
2512 int cchPrecision, unsigned fFlags, char chArgSize)
[35586]2513{
[39078]2514 NOREF(pArgs); NOREF(chArgSize);
2515
[35586]2516 /*
[35590]2517 * Parse the format type and hand the job to the appropriate worker.
[35586]2518 */
[35625]2519 PDBGFR3REGPRINTFARGS pThis = (PDBGFR3REGPRINTFARGS)pvArg;
[35586]2520 const char *pszFormat = *ppszFormat;
2521 if ( pszFormat[0] != 'V'
2522 || pszFormat[1] != 'R')
2523 {
2524 AssertMsgFailed(("'%s'\n", pszFormat));
2525 return 0;
2526 }
[35590]2527 unsigned offCurly = 2;
2528 if (pszFormat[offCurly] != '{')
[35586]2529 {
[35590]2530 AssertMsgReturn(pszFormat[offCurly], ("'%s'\n", pszFormat), 0);
2531 offCurly++;
2532 AssertMsgReturn(pszFormat[offCurly] == '{', ("'%s'\n", pszFormat), 0);
[35586]2533 }
[35590]2534 const char *pachReg = &pszFormat[offCurly + 1];
[35586]2535
[35590]2536 /*
2537 * The end and length of the register.
2538 */
[35606]2539 const char *pszEnd = strchr(pachReg, '}');
[35586]2540 AssertMsgReturn(pszEnd, ("Missing closing curly bracket: '%s'\n", pszFormat), 0);
[35590]2541 size_t const cchReg = pszEnd - pachReg;
[35586]2542
2543 /*
2544 * Look up the register - same as dbgfR3RegResolve, except for locking and
2545 * input string termination.
2546 */
[44399]2547 PRTSTRSPACE pRegSpace = &pThis->pUVM->dbgf.s.RegSpace;
[35586]2548 /* Try looking up the name without any case folding or cpu prefixing. */
[44399]2549 PCDBGFREGLOOKUP pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGetN(pRegSpace, pachReg, cchReg);
[35586]2550 if (!pLookupRec)
2551 {
2552 /* Lower case it and try again. */
[35590]2553 char szName[DBGF_REG_MAX_NAME * 4 + 16];
2554 ssize_t cchFolded = dbgfR3RegCopyToLower(pachReg, cchReg, szName, sizeof(szName) - DBGF_REG_MAX_NAME);
[35586]2555 if (cchFolded > 0)
[44399]2556 pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(pRegSpace, szName);
[35586]2557 if ( !pLookupRec
2558 && cchFolded >= 0
2559 && pThis->idCpu != VMCPUID_ANY)
2560 {
2561 /* Prefix it with the specified CPU set. */
[35606]2562 size_t cchCpuSet = RTStrPrintf(szName, sizeof(szName), pThis->fGuestRegs ? "cpu%u." : "hypercpu%u.", pThis->idCpu);
[35590]2563 dbgfR3RegCopyToLower(pachReg, cchReg, &szName[cchCpuSet], sizeof(szName) - cchCpuSet);
[44399]2564 pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(pRegSpace, szName);
[35586]2565 }
2566 }
2567 AssertMsgReturn(pLookupRec, ("'%s'\n", pszFormat), 0);
2568 AssertMsgReturn( pLookupRec->pSet->enmType != DBGFREGSETTYPE_CPU
2569 || pLookupRec->pSet->uUserArg.pVCpu->idCpu == pThis->idCpu,
2570 ("'%s' idCpu=%u, pSet/cpu=%u\n", pszFormat, pThis->idCpu, pLookupRec->pSet->uUserArg.pVCpu->idCpu),
2571 0);
2572
2573 /*
[35590]2574 * Commit the parsed format string. Up to this point it is nice to know
2575 * what register lookup failed and such, so we've delayed comitting.
[35586]2576 */
[35590]2577 *ppszFormat = pszEnd + 1;
[35586]2578
2579 /*
[35590]2580 * Call the responsible worker.
[35586]2581 */
[35590]2582 switch (pszFormat[offCurly - 1])
[35586]2583 {
[35590]2584 case 'R': /* %VR{} */
2585 case 'X': /* %VRX{} */
[35625]2586 return dbgfR3RegPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
2587 16, cchWidth, cchPrecision, fFlags);
[35590]2588 case 'U':
[35625]2589 return dbgfR3RegPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
2590 10, cchWidth, cchPrecision, fFlags);
[35590]2591 case 'O':
[35625]2592 return dbgfR3RegPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
2593 8, cchWidth, cchPrecision, fFlags);
[35590]2594 case 'B':
[35625]2595 return dbgfR3RegPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
2596 2, cchWidth, cchPrecision, fFlags);
[35590]2597 case 'F':
[35625]2598 return dbgfR3RegPrintfCbFormatField(pThis, pfnOutput, pvArgOutput, pLookupRec, cchWidth, cchPrecision, fFlags);
[35590]2599 default:
2600 AssertFailed();
2601 return 0;
[35586]2602 }
2603}
2604
2605
[35590]2606
[35586]2607/**
2608 * @callback_method_impl{FNRTSTROUTPUT}
2609 */
2610static DECLCALLBACK(size_t)
[35625]2611dbgfR3RegPrintfCbOutput(void *pvArg, const char *pachChars, size_t cbChars)
[35586]2612{
[35625]2613 PDBGFR3REGPRINTFARGS pArgs = (PDBGFR3REGPRINTFARGS)pvArg;
[35586]2614 size_t cbToCopy = cbChars;
2615 if (cbToCopy >= pArgs->cchLeftBuf)
2616 {
2617 if (RT_SUCCESS(pArgs->rc))
2618 pArgs->rc = VERR_BUFFER_OVERFLOW;
2619 cbToCopy = pArgs->cchLeftBuf;
2620 }
2621 if (cbToCopy > 0)
2622 {
[36826]2623 memcpy(&pArgs->pszBuf[pArgs->offBuf], pachChars, cbToCopy);
2624 pArgs->offBuf += cbToCopy;
2625 pArgs->cchLeftBuf -= cbToCopy;
[35586]2626 pArgs->pszBuf[pArgs->offBuf] = '\0';
2627 }
2628 return cbToCopy;
2629}
2630
2631
2632/**
[35625]2633 * On CPU worker for the register formatting, used by DBGFR3RegPrintfV.
[35586]2634 *
2635 * @returns VBox status code.
2636 *
2637 * @param pArgs The argument package and state.
2638 */
[35625]2639static DECLCALLBACK(int) dbgfR3RegPrintfWorkerOnCpu(PDBGFR3REGPRINTFARGS pArgs)
[35586]2640{
[44399]2641 DBGF_REG_DB_LOCK_READ(pArgs->pUVM);
[35625]2642 RTStrFormatV(dbgfR3RegPrintfCbOutput, pArgs, dbgfR3RegPrintfCbFormat, pArgs, pArgs->pszFormat, pArgs->va);
[44399]2643 DBGF_REG_DB_UNLOCK_READ(pArgs->pUVM);
[35586]2644 return pArgs->rc;
2645}
2646
2647
2648/**
2649 * Format a registers.
2650 *
2651 * This is restricted to registers from one CPU, that specified by @a idCpu.
2652 *
2653 * @returns VBox status code.
[44399]2654 * @param pUVM The user mode VM handle.
[35586]2655 * @param idCpu The CPU ID of any CPU registers that may be
2656 * printed, pass VMCPUID_ANY if not applicable.
2657 * @param pszBuf The output buffer.
2658 * @param cbBuf The size of the output buffer.
2659 * @param pszFormat The format string. Register names are given by
2660 * %VR{name}, they take no arguments.
2661 * @param va Other format arguments.
2662 */
[44399]2663VMMR3DECL(int) DBGFR3RegPrintfV(PUVM pUVM, VMCPUID idCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, va_list va)
[35586]2664{
2665 AssertPtrReturn(pszBuf, VERR_INVALID_POINTER);
2666 AssertReturn(cbBuf > 0, VERR_BUFFER_OVERFLOW);
2667 *pszBuf = '\0';
2668
[44399]2669 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
2670 AssertReturn((idCpu & ~DBGFREG_HYPER_VMCPUID) < pUVM->cCpus || idCpu == VMCPUID_ANY, VERR_INVALID_CPU_ID);
[35586]2671 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
2672
2673 /*
2674 * Set up an argument package and execute the formatting on the
2675 * specified CPU.
2676 */
[35625]2677 DBGFR3REGPRINTFARGS Args;
[44399]2678 Args.pUVM = pUVM;
[35606]2679 Args.idCpu = idCpu != VMCPUID_ANY ? idCpu & ~DBGFREG_HYPER_VMCPUID : idCpu;
2680 Args.fGuestRegs = idCpu != VMCPUID_ANY && !(idCpu & DBGFREG_HYPER_VMCPUID);
[35586]2681 Args.pszBuf = pszBuf;
2682 Args.pszFormat = pszFormat;
2683 va_copy(Args.va, va);
2684 Args.offBuf = 0;
2685 Args.cchLeftBuf = cbBuf - 1;
2686 Args.rc = VINF_SUCCESS;
[44399]2687 int rc = VMR3ReqPriorityCallWaitU(pUVM, Args.idCpu, (PFNRT)dbgfR3RegPrintfWorkerOnCpu, 1, &Args);
[35586]2688 va_end(Args.va);
2689 return rc;
2690}
2691
2692
2693/**
2694 * Format a registers.
2695 *
2696 * This is restricted to registers from one CPU, that specified by @a idCpu.
2697 *
2698 * @returns VBox status code.
[44399]2699 * @param pUVM The user mode VM handle.
[35586]2700 * @param idCpu The CPU ID of any CPU registers that may be
2701 * printed, pass VMCPUID_ANY if not applicable.
2702 * @param pszBuf The output buffer.
2703 * @param cbBuf The size of the output buffer.
2704 * @param pszFormat The format string. Register names are given by
2705 * %VR{name}, %VRU{name}, %VRO{name} and
2706 * %VRB{name}, which are hexadecimal, (unsigned)
2707 * decimal, octal and binary representation. None
2708 * of these types takes any arguments.
2709 * @param ... Other format arguments.
2710 */
[44399]2711VMMR3DECL(int) DBGFR3RegPrintf(PUVM pUVM, VMCPUID idCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, ...)
[35586]2712{
2713 va_list va;
2714 va_start(va, pszFormat);
[44399]2715 int rc = DBGFR3RegPrintfV(pUVM, idCpu, pszBuf, cbBuf, pszFormat, va);
[35586]2716 va_end(va);
2717 return rc;
2718}
2719
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use