VirtualBox

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

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

DBGFReg.cpp: Fixed buffer overflow bug caused by using the wrong variable.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 82.3 KB
Line 
1/* $Id: DBGFReg.cpp 36826 2011-04-23 23:12:54Z 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 DBGFR3RegPrintfV to dbgfR3RegPrintfCbOutput and
172 * dbgfR3RegPrintfCbFormat.
173 */
174typedef struct DBGFR3REGPRINTFARGS
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} DBGFR3REGPRINTFARGS;
197/** Pointer to a DBGFR3RegPrintfV argument packet. */
198typedef DBGFR3REGPRINTFARGS *PDBGFR3REGPRINTFARGS;
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 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 * dbgfR3RegPrintfCbFormatNormal.
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
1842VMMR3DECL(int) DBGFR3RegNmSet(PVM pVM, VMCPUID idDefCpu, const char *pszReg, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType)
1843{
1844 return VERR_NOT_IMPLEMENTED;
1845}
1846
1847
1848/**
1849 * Internal worker for DBGFR3RegFormatValue, cbTmp is sufficent.
1850 *
1851 * @copydoc DBGFR3RegFormatValue
1852 */
1853DECLINLINE(ssize_t) dbgfR3RegFormatValueInt(char *pszTmp, size_t cbTmp, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType,
1854 unsigned uBase, signed int cchWidth, signed int cchPrecision, uint32_t fFlags)
1855{
1856 switch (enmType)
1857 {
1858 case DBGFREGVALTYPE_U8:
1859 return RTStrFormatU8(pszTmp, cbTmp, pValue->u8, uBase, cchWidth, cchPrecision, fFlags);
1860 case DBGFREGVALTYPE_U16:
1861 return RTStrFormatU16(pszTmp, cbTmp, pValue->u16, uBase, cchWidth, cchPrecision, fFlags);
1862 case DBGFREGVALTYPE_U32:
1863 return RTStrFormatU32(pszTmp, cbTmp, pValue->u32, uBase, cchWidth, cchPrecision, fFlags);
1864 case DBGFREGVALTYPE_U64:
1865 return RTStrFormatU64(pszTmp, cbTmp, pValue->u64, uBase, cchWidth, cchPrecision, fFlags);
1866 case DBGFREGVALTYPE_U128:
1867 return RTStrFormatU128(pszTmp, cbTmp, &pValue->u128, uBase, cchWidth, cchPrecision, fFlags);
1868 case DBGFREGVALTYPE_R80:
1869 return RTStrFormatR80u2(pszTmp, cbTmp, &pValue->r80, cchWidth, cchPrecision, fFlags);
1870 case DBGFREGVALTYPE_DTR:
1871 {
1872 ssize_t cch = RTStrFormatU64(pszTmp, cbTmp, pValue->dtr.u64Base,
1873 16, 2+16, 0, RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD);
1874 AssertReturn(cch > 0, VERR_INTERNAL_ERROR_4);
1875 pszTmp[cch++] = ':';
1876 cch += RTStrFormatU64(&pszTmp[cch], cbTmp - cch, pValue->dtr.u32Limit,
1877 16, 4, 0, RTSTR_F_ZEROPAD | RTSTR_F_32BIT);
1878 return cch;
1879 }
1880
1881 case DBGFREGVALTYPE_32BIT_HACK:
1882 case DBGFREGVALTYPE_END:
1883 case DBGFREGVALTYPE_INVALID:
1884 break;
1885 /* no default, want gcc warnings */
1886 }
1887
1888 RTStrPrintf(pszTmp, cbTmp, "!enmType=%d!", enmType);
1889 return VERR_INTERNAL_ERROR_5;
1890}
1891
1892
1893
1894/**
1895 * Format a register value, extended version.
1896 *
1897 * @returns The number of bytes returned, VERR_BUFFER_OVERFLOW on failure.
1898 * @param pszBuf The output buffer.
1899 * @param cbBuf The size of the output buffer.
1900 * @param pValue The value to format.
1901 * @param enmType The value type.
1902 * @param uBase The base (ignored if not applicable).
1903 * @param cchWidth The width if RTSTR_F_WIDTH is set, otherwise
1904 * ignored.
1905 * @param cchPrecision The width if RTSTR_F_PRECISION is set, otherwise
1906 * ignored.
1907 * @param fFlags String formatting flags, RTSTR_F_XXX.
1908 */
1909VMMDECL(ssize_t) DBGFR3RegFormatValueEx(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType,
1910 unsigned uBase, signed int cchWidth, signed int cchPrecision, uint32_t fFlags)
1911{
1912 /*
1913 * Format to temporary buffer using worker shared with dbgfR3RegPrintfCbFormatNormal.
1914 */
1915 char szTmp[160];
1916 ssize_t cchOutput = dbgfR3RegFormatValueInt(szTmp, sizeof(szTmp), pValue, enmType, uBase, cchWidth, cchPrecision, fFlags);
1917 if (cchOutput > 0)
1918 {
1919 if ((size_t)cchOutput < cbBuf)
1920 memcpy(pszBuf, szTmp, cchOutput + 1);
1921 else
1922 {
1923 if (cbBuf)
1924 {
1925 memcpy(pszBuf, szTmp, cbBuf - 1);
1926 pszBuf[cbBuf - 1] = '\0';
1927 }
1928 cchOutput = VERR_BUFFER_OVERFLOW;
1929 }
1930 }
1931 return cchOutput;
1932}
1933
1934
1935/**
1936 * Format a register value as hexadecimal and with default width according to
1937 * the type.
1938 *
1939 * @returns The number of bytes returned, VERR_BUFFER_OVERFLOW on failure.
1940 * @param pszBuf The output buffer.
1941 * @param cbBuf The size of the output buffer.
1942 * @param pValue The value to format.
1943 * @param enmType The value type.
1944 * @param fSpecial Same as RTSTR_F_SPECIAL.
1945 */
1946VMMDECL(ssize_t) DBGFR3RegFormatValue(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType, bool fSpecial)
1947{
1948 int cchWidth = 0;
1949 switch (enmType)
1950 {
1951 case DBGFREGVALTYPE_U8: cchWidth = 2 + fSpecial*2; break;
1952 case DBGFREGVALTYPE_U16: cchWidth = 4 + fSpecial*2; break;
1953 case DBGFREGVALTYPE_U32: cchWidth = 8 + fSpecial*2; break;
1954 case DBGFREGVALTYPE_U64: cchWidth = 16 + fSpecial*2; break;
1955 case DBGFREGVALTYPE_U128: cchWidth = 32 + fSpecial*2; break;
1956 case DBGFREGVALTYPE_R80: cchWidth = 0; break;
1957 case DBGFREGVALTYPE_DTR: cchWidth = 16+1+4 + fSpecial*2; break;
1958
1959 case DBGFREGVALTYPE_32BIT_HACK:
1960 case DBGFREGVALTYPE_END:
1961 case DBGFREGVALTYPE_INVALID:
1962 break;
1963 /* no default, want gcc warnings */
1964 }
1965 uint32_t fFlags = RTSTR_F_ZEROPAD;
1966 if (fSpecial)
1967 fFlags |= RTSTR_F_SPECIAL;
1968 if (cchWidth != 0)
1969 fFlags |= RTSTR_F_WIDTH;
1970 return DBGFR3RegFormatValueEx(pszBuf, cbBuf, pValue, enmType, 16, cchWidth, 0, fFlags);
1971}
1972
1973
1974/**
1975 * Format a register using special hacks as well as sub-field specifications
1976 * (the latter isn't implemented yet).
1977 */
1978static size_t
1979dbgfR3RegPrintfCbFormatField(PDBGFR3REGPRINTFARGS pThis, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
1980 PCDBGFREGLOOKUP pLookupRec, int cchWidth, int cchPrecision, unsigned fFlags)
1981{
1982 char szTmp[160];
1983
1984 /*
1985 * Retrieve the register value.
1986 */
1987 DBGFREGVAL Value;
1988 DBGFREGVALTYPE enmType;
1989 int rc = dbgfR3RegNmQueryWorkerOnCpu(pThis->pVM, pLookupRec, DBGFREGVALTYPE_END, &Value, &enmType);
1990 if (RT_FAILURE(rc))
1991 {
1992 PCRTSTATUSMSG pErr = RTErrGet(rc);
1993 if (pErr)
1994 return pfnOutput(pvArgOutput, pErr->pszDefine, strlen(pErr->pszDefine));
1995 return pfnOutput(pvArgOutput, szTmp, RTStrPrintf(szTmp, sizeof(szTmp), "rc=%d", rc));
1996 }
1997
1998 char *psz = szTmp;
1999
2000 /*
2001 * Special case: Format eflags.
2002 */
2003 if ( pLookupRec->pSet->enmType == DBGFREGSETTYPE_CPU
2004 && pLookupRec->pDesc->enmReg == DBGFREG_RFLAGS
2005 && pLookupRec->pSubField == NULL)
2006 {
2007 rc = dbgfR3RegValCast(&Value, enmType, DBGFREGVALTYPE_U32);
2008 AssertRC(rc);
2009 uint32_t const efl = Value.u32;
2010
2011 /* the iopl */
2012 psz += RTStrPrintf(psz, sizeof(szTmp) / 2, "iopl=%u ", X86_EFL_GET_IOPL(efl));
2013
2014 /* add flags */
2015 static const struct
2016 {
2017 const char *pszSet;
2018 const char *pszClear;
2019 uint32_t fFlag;
2020 } aFlags[] =
2021 {
2022 { "vip",NULL, X86_EFL_VIP },
2023 { "vif",NULL, X86_EFL_VIF },
2024 { "ac", NULL, X86_EFL_AC },
2025 { "vm", NULL, X86_EFL_VM },
2026 { "rf", NULL, X86_EFL_RF },
2027 { "nt", NULL, X86_EFL_NT },
2028 { "ov", "nv", X86_EFL_OF },
2029 { "dn", "up", X86_EFL_DF },
2030 { "ei", "di", X86_EFL_IF },
2031 { "tf", NULL, X86_EFL_TF },
2032 { "ng", "pl", X86_EFL_SF },
2033 { "zr", "nz", X86_EFL_ZF },
2034 { "ac", "na", X86_EFL_AF },
2035 { "po", "pe", X86_EFL_PF },
2036 { "cy", "nc", X86_EFL_CF },
2037 };
2038 for (unsigned i = 0; i < RT_ELEMENTS(aFlags); i++)
2039 {
2040 const char *pszAdd = aFlags[i].fFlag & efl ? aFlags[i].pszSet : aFlags[i].pszClear;
2041 if (pszAdd)
2042 {
2043 *psz++ = *pszAdd++;
2044 *psz++ = *pszAdd++;
2045 if (*pszAdd)
2046 *psz++ = *pszAdd++;
2047 *psz++ = ' ';
2048 }
2049 }
2050
2051 /* drop trailing space */
2052 psz--;
2053 }
2054 else
2055 {
2056 /*
2057 * General case.
2058 */
2059 AssertMsgFailed(("Not implemented: %s\n", pLookupRec->Core.pszString));
2060 return pfnOutput(pvArgOutput, pLookupRec->Core.pszString, pLookupRec->Core.cchString);
2061 }
2062
2063 /* Output the string. */
2064 return pfnOutput(pvArgOutput, szTmp, psz - &szTmp[0]);
2065}
2066
2067
2068/**
2069 * Formats a register having parsed up to the register name.
2070 */
2071static size_t
2072dbgfR3RegPrintfCbFormatNormal(PDBGFR3REGPRINTFARGS pThis, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
2073 PCDBGFREGLOOKUP pLookupRec, unsigned uBase, int cchWidth, int cchPrecision, unsigned fFlags)
2074{
2075 char szTmp[160];
2076
2077 /*
2078 * Get the register value.
2079 */
2080 DBGFREGVAL Value;
2081 DBGFREGVALTYPE enmType;
2082 int rc = dbgfR3RegNmQueryWorkerOnCpu(pThis->pVM, pLookupRec, DBGFREGVALTYPE_END, &Value, &enmType);
2083 if (RT_FAILURE(rc))
2084 {
2085 PCRTSTATUSMSG pErr = RTErrGet(rc);
2086 if (pErr)
2087 return pfnOutput(pvArgOutput, pErr->pszDefine, strlen(pErr->pszDefine));
2088 return pfnOutput(pvArgOutput, szTmp, RTStrPrintf(szTmp, sizeof(szTmp), "rc=%d", rc));
2089 }
2090
2091 /*
2092 * Format the value.
2093 */
2094 ssize_t cchOutput = dbgfR3RegFormatValueInt(szTmp, sizeof(szTmp), &Value, enmType, uBase, cchWidth, cchPrecision, fFlags);
2095 if (RT_UNLIKELY(cchOutput <= 0))
2096 {
2097 AssertFailed();
2098 return pfnOutput(pvArgOutput, "internal-error", sizeof("internal-error") - 1);
2099 }
2100 return pfnOutput(pvArgOutput, szTmp, cchOutput);
2101}
2102
2103
2104/**
2105 * @callback_method_impl{FNSTRFORMAT}
2106 */
2107static DECLCALLBACK(size_t)
2108dbgfR3RegPrintfCbFormat(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
2109 const char **ppszFormat, va_list *pArgs, int cchWidth,
2110 int cchPrecision, unsigned fFlags, char chArgSize)
2111{
2112 /*
2113 * Parse the format type and hand the job to the appropriate worker.
2114 */
2115 PDBGFR3REGPRINTFARGS pThis = (PDBGFR3REGPRINTFARGS)pvArg;
2116 const char *pszFormat = *ppszFormat;
2117 if ( pszFormat[0] != 'V'
2118 || pszFormat[1] != 'R')
2119 {
2120 AssertMsgFailed(("'%s'\n", pszFormat));
2121 return 0;
2122 }
2123 unsigned offCurly = 2;
2124 if (pszFormat[offCurly] != '{')
2125 {
2126 AssertMsgReturn(pszFormat[offCurly], ("'%s'\n", pszFormat), 0);
2127 offCurly++;
2128 AssertMsgReturn(pszFormat[offCurly] == '{', ("'%s'\n", pszFormat), 0);
2129 }
2130 const char *pachReg = &pszFormat[offCurly + 1];
2131
2132 /*
2133 * The end and length of the register.
2134 */
2135 const char *pszEnd = strchr(pachReg, '}');
2136 AssertMsgReturn(pszEnd, ("Missing closing curly bracket: '%s'\n", pszFormat), 0);
2137 size_t const cchReg = pszEnd - pachReg;
2138
2139 /*
2140 * Look up the register - same as dbgfR3RegResolve, except for locking and
2141 * input string termination.
2142 */
2143 /* Try looking up the name without any case folding or cpu prefixing. */
2144 PCDBGFREGLOOKUP pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGetN(&pThis->pVM->dbgf.s.RegSpace, pachReg, cchReg);
2145 if (!pLookupRec)
2146 {
2147 /* Lower case it and try again. */
2148 char szName[DBGF_REG_MAX_NAME * 4 + 16];
2149 ssize_t cchFolded = dbgfR3RegCopyToLower(pachReg, cchReg, szName, sizeof(szName) - DBGF_REG_MAX_NAME);
2150 if (cchFolded > 0)
2151 pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(&pThis->pVM->dbgf.s.RegSpace, szName);
2152 if ( !pLookupRec
2153 && cchFolded >= 0
2154 && pThis->idCpu != VMCPUID_ANY)
2155 {
2156 /* Prefix it with the specified CPU set. */
2157 size_t cchCpuSet = RTStrPrintf(szName, sizeof(szName), pThis->fGuestRegs ? "cpu%u." : "hypercpu%u.", pThis->idCpu);
2158 dbgfR3RegCopyToLower(pachReg, cchReg, &szName[cchCpuSet], sizeof(szName) - cchCpuSet);
2159 pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(&pThis->pVM->dbgf.s.RegSpace, szName);
2160 }
2161 }
2162 AssertMsgReturn(pLookupRec, ("'%s'\n", pszFormat), 0);
2163 AssertMsgReturn( pLookupRec->pSet->enmType != DBGFREGSETTYPE_CPU
2164 || pLookupRec->pSet->uUserArg.pVCpu->idCpu == pThis->idCpu,
2165 ("'%s' idCpu=%u, pSet/cpu=%u\n", pszFormat, pThis->idCpu, pLookupRec->pSet->uUserArg.pVCpu->idCpu),
2166 0);
2167
2168 /*
2169 * Commit the parsed format string. Up to this point it is nice to know
2170 * what register lookup failed and such, so we've delayed comitting.
2171 */
2172 *ppszFormat = pszEnd + 1;
2173
2174 /*
2175 * Call the responsible worker.
2176 */
2177 switch (pszFormat[offCurly - 1])
2178 {
2179 case 'R': /* %VR{} */
2180 case 'X': /* %VRX{} */
2181 return dbgfR3RegPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
2182 16, cchWidth, cchPrecision, fFlags);
2183 case 'U':
2184 return dbgfR3RegPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
2185 10, cchWidth, cchPrecision, fFlags);
2186 case 'O':
2187 return dbgfR3RegPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
2188 8, cchWidth, cchPrecision, fFlags);
2189 case 'B':
2190 return dbgfR3RegPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
2191 2, cchWidth, cchPrecision, fFlags);
2192 case 'F':
2193 return dbgfR3RegPrintfCbFormatField(pThis, pfnOutput, pvArgOutput, pLookupRec, cchWidth, cchPrecision, fFlags);
2194 default:
2195 AssertFailed();
2196 return 0;
2197 }
2198}
2199
2200
2201
2202/**
2203 * @callback_method_impl{FNRTSTROUTPUT}
2204 */
2205static DECLCALLBACK(size_t)
2206dbgfR3RegPrintfCbOutput(void *pvArg, const char *pachChars, size_t cbChars)
2207{
2208 PDBGFR3REGPRINTFARGS pArgs = (PDBGFR3REGPRINTFARGS)pvArg;
2209 size_t cbToCopy = cbChars;
2210 if (cbToCopy >= pArgs->cchLeftBuf)
2211 {
2212 if (RT_SUCCESS(pArgs->rc))
2213 pArgs->rc = VERR_BUFFER_OVERFLOW;
2214 cbToCopy = pArgs->cchLeftBuf;
2215 }
2216 if (cbToCopy > 0)
2217 {
2218 memcpy(&pArgs->pszBuf[pArgs->offBuf], pachChars, cbToCopy);
2219 pArgs->offBuf += cbToCopy;
2220 pArgs->cchLeftBuf -= cbToCopy;
2221 pArgs->pszBuf[pArgs->offBuf] = '\0';
2222 }
2223 return cbToCopy;
2224}
2225
2226
2227/**
2228 * On CPU worker for the register formatting, used by DBGFR3RegPrintfV.
2229 *
2230 * @returns VBox status code.
2231 *
2232 * @param pArgs The argument package and state.
2233 */
2234static DECLCALLBACK(int) dbgfR3RegPrintfWorkerOnCpu(PDBGFR3REGPRINTFARGS pArgs)
2235{
2236 DBGF_REG_DB_LOCK_READ(pArgs->pVM);
2237 RTStrFormatV(dbgfR3RegPrintfCbOutput, pArgs, dbgfR3RegPrintfCbFormat, pArgs, pArgs->pszFormat, pArgs->va);
2238 DBGF_REG_DB_UNLOCK_READ(pArgs->pVM);
2239 return pArgs->rc;
2240}
2241
2242
2243/**
2244 * Format a registers.
2245 *
2246 * This is restricted to registers from one CPU, that specified by @a idCpu.
2247 *
2248 * @returns VBox status code.
2249 * @param pVM The VM handle.
2250 * @param idCpu The CPU ID of any CPU registers that may be
2251 * printed, pass VMCPUID_ANY if not applicable.
2252 * @param pszBuf The output buffer.
2253 * @param cbBuf The size of the output buffer.
2254 * @param pszFormat The format string. Register names are given by
2255 * %VR{name}, they take no arguments.
2256 * @param va Other format arguments.
2257 */
2258VMMR3DECL(int) DBGFR3RegPrintfV(PVM pVM, VMCPUID idCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, va_list va)
2259{
2260 AssertPtrReturn(pszBuf, VERR_INVALID_POINTER);
2261 AssertReturn(cbBuf > 0, VERR_BUFFER_OVERFLOW);
2262 *pszBuf = '\0';
2263
2264 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
2265 AssertReturn((idCpu & ~DBGFREG_HYPER_VMCPUID) < pVM->cCpus || idCpu == VMCPUID_ANY, VERR_INVALID_CPU_ID);
2266 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
2267
2268 /*
2269 * Set up an argument package and execute the formatting on the
2270 * specified CPU.
2271 */
2272 DBGFR3REGPRINTFARGS Args;
2273 Args.pVM = pVM;
2274 Args.idCpu = idCpu != VMCPUID_ANY ? idCpu & ~DBGFREG_HYPER_VMCPUID : idCpu;
2275 Args.fGuestRegs = idCpu != VMCPUID_ANY && !(idCpu & DBGFREG_HYPER_VMCPUID);
2276 Args.pszBuf = pszBuf;
2277 Args.pszFormat = pszFormat;
2278 va_copy(Args.va, va);
2279 Args.offBuf = 0;
2280 Args.cchLeftBuf = cbBuf - 1;
2281 Args.rc = VINF_SUCCESS;
2282 int rc = VMR3ReqCallWait(pVM, Args.idCpu, (PFNRT)dbgfR3RegPrintfWorkerOnCpu, 1, &Args);
2283 va_end(Args.va);
2284 return rc;
2285}
2286
2287
2288/**
2289 * Format a registers.
2290 *
2291 * This is restricted to registers from one CPU, that specified by @a idCpu.
2292 *
2293 * @returns VBox status code.
2294 * @param pVM The VM handle.
2295 * @param idCpu The CPU ID of any CPU registers that may be
2296 * printed, pass VMCPUID_ANY if not applicable.
2297 * @param pszBuf The output buffer.
2298 * @param cbBuf The size of the output buffer.
2299 * @param pszFormat The format string. Register names are given by
2300 * %VR{name}, %VRU{name}, %VRO{name} and
2301 * %VRB{name}, which are hexadecimal, (unsigned)
2302 * decimal, octal and binary representation. None
2303 * of these types takes any arguments.
2304 * @param ... Other format arguments.
2305 */
2306VMMR3DECL(int) DBGFR3RegPrintf(PVM pVM, VMCPUID idCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, ...)
2307{
2308 va_list va;
2309 va_start(va, pszFormat);
2310 int rc = DBGFR3RegPrintfV(pVM, idCpu, pszBuf, cbBuf, pszFormat, va);
2311 va_end(va);
2312 return rc;
2313}
2314
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