VirtualBox

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

Last change on this file since 97178 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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