VirtualBox

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

Last change on this file since 35606 was 35606, checked in by vboxsync, 14 years ago

DBGFRegs: Introduced DBGFREG_HYPER_VMCPUID. Fixed some bugs.

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