VirtualBox

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

Last change on this file since 44689 was 44689, checked in by vboxsync, 12 years ago

Expose I/O APIC registers to the debugger facilities.

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