VirtualBox

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

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

DBGF,DBGC,++: PVM -> PUVM. Some refactoring and cleanup as well.

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