VirtualBox

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

Last change on this file since 99897 was 99070, checked in by vboxsync, 18 months ago

VMM/{CPUM,DBGF}: Some basic support to dump register values with DBGF for ARMv8, bugref:10393

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