VirtualBox

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

Last change on this file since 102468 was 102092, checked in by vboxsync, 14 months ago

VMM/DBGF,DBGC,Main: Added DBGFR3RegNmQueryEx and fixed some issues with DBGFR3RegNmQueryAll that lead to assertions in Main and empty entries in VBoxManage output. Extended the 'r' and 'rg' debugger commands to make use of the two APIs, the first by appending '.' to a register (e.g. r @cr0.) and the latter by using 'all' as the register name.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette