VirtualBox

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

Last change on this file since 72358 was 69111, checked in by vboxsync, 7 years ago

(C) year

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