VirtualBox

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

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

DBGFReg revamp #2.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.7 KB
Line 
1/* $Id: DBGFReg.cpp 35410 2011-01-05 17:21:11Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Register Methods.
4 */
5
6/*
7 * Copyright (C) 2010 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
33
34/*******************************************************************************
35* Defined Constants And Macros *
36*******************************************************************************/
37/** Locks the register database for writing. */
38#define DBGF_REG_DB_LOCK_WRITE(pVM) \
39 do { \
40 int rcSem = RTSemRWRequestWrite((pVM)->dbgf.s.hRegDbLock, RT_INDEFINITE_WAIT); \
41 AssertRC(rcSem); \
42 } while (0)
43
44/** Unlocks the register database after writing. */
45#define DBGF_REG_DB_UNLOCK_WRITE(pVM) \
46 do { \
47 int rcSem = RTSemRWReleaseWrite((pVM)->dbgf.s.hRegDbLock); \
48 AssertRC(rcSem); \
49 } while (0)
50
51/** Locks the register database for reading. */
52#define DBGF_REG_DB_LOCK_READ(pVM) \
53 do { \
54 int rcSem = RTSemRWRequestRead((pVM)->dbgf.s.hRegDbLock, RT_INDEFINITE_WAIT); \
55 AssertRC(rcSem); \
56 } while (0)
57
58/** Unlocks the register database after reading. */
59#define DBGF_REG_DB_UNLOCK_READ(pVM) \
60 do { \
61 int rcSem = RTSemRWReleaseRead((pVM)->dbgf.s.hRegDbLock); \
62 AssertRC(rcSem); \
63 } while (0)
64
65
66
67/*******************************************************************************
68* Structures and Typedefs *
69*******************************************************************************/
70/**
71 * Register set registration record type.
72 */
73typedef enum DBGFREGSETTYPE
74{
75 /** Invalid zero value. */
76 DBGFREGSETTYPE_INVALID = 0,
77 /** CPU record. */
78 DBGFREGSETTYPE_CPU,
79 /** Device record. */
80 DBGFREGSETTYPE_DEVICE,
81 /** End of valid record types. */
82 DBGFREGSETTYPE_END
83} DBGFREGSETTYPE;
84
85
86/**
87 * Register set registration record.
88 */
89typedef struct DBGFREGSET
90{
91 /** String space core. */
92 RTSTRSPACECORE Core;
93 /** The registration record type. */
94 DBGFREGSETTYPE enmType;
95 /** The user argument for the callbacks. */
96 union
97 {
98 /** The CPU view. */
99 PVMCPU pVCpu;
100 /** The device view. */
101 PPDMDEVINS pDevIns;
102 /** The general view. */
103 void *pv;
104 } uUserArg;
105
106 /** The register descriptors. */
107 PCDBGFREGDESC paDescs;
108 /** The number of register descriptors. */
109 size_t cDescs;
110
111 /** The register name prefix. */
112 char szPrefix[32];
113} DBGFREGSET;
114/** Pointer to a register registration record. */
115typedef DBGFREGSET *PDBGFREGSET;
116
117
118/**
119 * Validates a register name.
120 *
121 * This is used for prefixes, aliases and field names.
122 *
123 * @returns true if valid, false if not.
124 * @param pszName The register name to validate.
125 */
126static bool dbgfR3RegIsNameValid(const char *pszName)
127{
128 if (!RT_C_IS_ALPHA(*pszName))
129 return false;
130 char ch;
131 while ((ch = *++pszName))
132 if ( !RT_C_IS_LOWER(ch)
133 && !RT_C_IS_DIGIT(ch)
134 && ch != '_')
135 return false;
136 return true;
137}
138
139
140/**
141 * Common worker for registering a register set.
142 *
143 * @returns VBox status code.
144 * @param pVM The VM handle.
145 * @param paRegisters The register descriptors.
146 * @param enmType The set type.
147 * @param pvUserArg The user argument for the callbacks.
148 * @param pszPrefix The name prefix.
149 * @param iInstance The instance number to be appended to @a
150 * pszPrefix when creating the set name.
151 */
152static int dbgfR3RegRegisterCommon(PVM pVM, PCDBGFREGDESC paRegisters, DBGFREGSETTYPE enmType, void *pvUserArg, const char *pszPrefix, uint32_t iInstance)
153{
154 /*
155 * Validate input.
156 */
157 /* The name components. */
158 AssertMsgReturn(dbgfR3RegIsNameValid(pszPrefix), ("%s\n", pszPrefix), VERR_INVALID_NAME);
159 const char *psz = RTStrEnd(pszPrefix, RTSTR_MAX);
160 bool const fNeedUnderscore = RT_C_IS_DIGIT(psz[-1]);
161 size_t const cchPrefix = psz - pszPrefix + fNeedUnderscore;
162 AssertMsgReturn(cchPrefix < RT_SIZEOFMEMB(DBGFREGSET, szPrefix) - 4 - 1, ("%s\n", pszPrefix), VERR_INVALID_NAME);
163
164 AssertMsgReturn(iInstance <= 9999, ("%d\n", iInstance), VERR_INVALID_NAME);
165
166 /* The descriptors. */
167 uint32_t iDesc;
168 for (iDesc = 0; paRegisters[iDesc].pszName != NULL; iDesc++)
169 {
170 AssertMsgReturn(dbgfR3RegIsNameValid(paRegisters[iDesc].pszName), ("%s (#%u)\n", paRegisters[iDesc].pszName, iDesc), VERR_INVALID_NAME);
171
172 if (enmType == DBGFREGSETTYPE_CPU)
173 AssertMsgReturn((unsigned)paRegisters[iDesc].enmReg == iDesc && iDesc < (unsigned)DBGFREG_END,
174 ("%d iDesc=%d\n", paRegisters[iDesc].enmReg, iDesc),
175 VERR_INVALID_PARAMETER);
176 else
177 AssertReturn(paRegisters[iDesc].enmReg == DBGFREG_END, VERR_INVALID_PARAMETER);
178 AssertReturn( paRegisters[iDesc].enmType > DBGFREGVALTYPE_INVALID
179 && paRegisters[iDesc].enmType < DBGFREGVALTYPE_END, VERR_INVALID_PARAMETER);
180 AssertMsgReturn(paRegisters[iDesc].fFlags & ~DBGFREG_FLAGS_READ_ONLY,
181 ("%#x (#%u)\n", paRegisters[iDesc].fFlags, iDesc),
182 VERR_INVALID_PARAMETER);
183 AssertPtrReturn(paRegisters[iDesc].pfnGet, VERR_INVALID_PARAMETER);
184 AssertPtrReturn(paRegisters[iDesc].pfnSet, VERR_INVALID_PARAMETER);
185
186 PCDBGFREGALIAS paAliases = paRegisters[iDesc].paAliases;
187 if (paAliases)
188 {
189 AssertPtrReturn(paAliases, VERR_INVALID_PARAMETER);
190 for (uint32_t j = 0; paAliases[j].pszName; j++)
191 {
192 AssertMsgReturn(dbgfR3RegIsNameValid(paAliases[j].pszName), ("%s (%s)\n", paAliases[j].pszName, paRegisters[iDesc].pszName), VERR_INVALID_NAME);
193 AssertReturn( paAliases[j].enmType > DBGFREGVALTYPE_INVALID
194 && paAliases[j].enmType < DBGFREGVALTYPE_END, VERR_INVALID_PARAMETER);
195 }
196 }
197
198 PCDBGFREGSUBFIELD paSubFields = paRegisters[iDesc].paSubFields;
199 if (paSubFields)
200 {
201 AssertPtrReturn(paSubFields, VERR_INVALID_PARAMETER);
202 for (uint32_t j = 0; paSubFields[j].pszName; j++)
203 {
204 AssertMsgReturn(dbgfR3RegIsNameValid(paSubFields[j].pszName), ("%s (%s)\n", paSubFields[j].pszName, paRegisters[iDesc].pszName), VERR_INVALID_NAME);
205 AssertReturn(paSubFields[j].iFirstBit + paSubFields[j].cBits <= 128, VERR_INVALID_PARAMETER);
206 AssertReturn(paSubFields[j].cBits + paSubFields[j].cShift <= 128, VERR_INVALID_PARAMETER);
207 AssertPtrNullReturn(paSubFields[j].pfnGet, VERR_INVALID_POINTER);
208 AssertPtrNullReturn(paSubFields[j].pfnSet, VERR_INVALID_POINTER);
209 }
210 }
211 }
212
213 /*
214 * Allocate a new record.
215 */
216 PDBGFREGSET pRegRec = (PDBGFREGSET)MMR3HeapAlloc(pVM, MM_TAG_DBGF_REG, RT_OFFSETOF(DBGFREGSET, szPrefix[cchPrefix + 4 + 1]));
217 if (!pRegRec)
218 return VERR_NO_MEMORY;
219
220 pRegRec->Core.pszString = pRegRec->szPrefix;
221 pRegRec->enmType = enmType;
222 pRegRec->uUserArg.pv = pvUserArg;
223 pRegRec->paDescs = paRegisters;
224 pRegRec->cDescs = iDesc;
225 if (fNeedUnderscore)
226 RTStrPrintf(pRegRec->szPrefix, cchPrefix + 4 + 1, "%s_%u", pszPrefix, iInstance);
227 else
228 RTStrPrintf(pRegRec->szPrefix, cchPrefix + 4 + 1, "%s%u", pszPrefix, iInstance);
229
230 DBGF_REG_DB_LOCK_WRITE(pVM);
231 bool fInserted = RTStrSpaceInsert(&pVM->dbgf.s.RegSetSpace, &pRegRec->Core);
232 DBGF_REG_DB_UNLOCK_WRITE(pVM);
233 if (fInserted)
234 return VINF_SUCCESS;
235
236 MMR3HeapFree(pRegRec);
237 return VERR_DUPLICATE;
238}
239
240
241/**
242 * Registers a set of registers for a CPU.
243 *
244 * @returns VBox status code.
245 * @param pVCpu The virtual CPU handle.
246 * @param paRegisters The register descriptors.
247 */
248VMMR3_INT_DECL(int) DBGFR3RegRegisterDevice(PVMCPU pVCpu, PCDBGFREGDESC paRegisters)
249{
250 return dbgfR3RegRegisterCommon(pVCpu->pVMR3, paRegisters, DBGFREGSETTYPE_CPU, pVCpu, "cpu", pVCpu->idCpu);
251}
252
253
254/**
255 * Registers a set of registers for a device.
256 *
257 * @returns VBox status code.
258 * @param enmReg The register identifier.
259 * @param enmType The register type. This is for sort out
260 * aliases. Pass DBGFREGVALTYPE_INVALID to get
261 * the standard name.
262 */
263VMMR3DECL(int) DBGFR3RegRegisterDevice(PVM pVM, PCDBGFREGDESC paRegisters, PPDMDEVINS pDevIns, const char *pszPrefix, uint32_t iInstance)
264{
265 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
266 AssertPtrReturn(paRegisters, VERR_INVALID_POINTER);
267 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
268 AssertPtrReturn(pszPrefix, VERR_INVALID_POINTER);
269
270 return dbgfR3RegRegisterCommon(pVM, paRegisters, DBGFREGSETTYPE_DEVICE, pDevIns, pszPrefix, iInstance);
271}
272
273
274/**
275 * Clears the register value variable.
276 *
277 * @param pValue The variable to clear.
278 */
279DECLINLINE(void) dbgfR3RegValClear(PDBGFREGVAL pValue)
280{
281 pValue->au64[0] = 0;
282 pValue->au64[1] = 0;
283}
284
285
286/**
287 * Performs a cast between register value types.
288 *
289 * @retval VINF_SUCCESS
290 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
291 * @retval VINF_DBGF_TRUNCATED_REGISTER
292 * @retval VERR_DBGF_UNSUPPORTED_CAST
293 *
294 * @param pValue The value to cast (input + output).
295 * @param enmFromType The input value.
296 * @param enmToType The desired output value.
297 */
298static int dbgfR3RegValCast(PDBGFREGVAL pValue, DBGFREGVALTYPE enmFromType, DBGFREGVALTYPE enmToType)
299{
300 DBGFREGVAL const InVal = *pValue;
301 dbgfR3RegValClear(pValue);
302
303 switch (enmFromType)
304 {
305 case DBGFREGVALTYPE_U8:
306 switch (enmToType)
307 {
308 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u8; return VINF_SUCCESS;
309 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
310 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
311 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
312 case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
313 case DBGFREGVALTYPE_80: return VERR_DBGF_UNSUPPORTED_CAST;
314 case DBGFREGVALTYPE_LRD: pValue->lrd = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
315 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
316
317 case DBGFREGVALTYPE_32BIT_HACK:
318 case DBGFREGVALTYPE_END:
319 case DBGFREGVALTYPE_INVALID:
320 break;
321 }
322 break;
323
324 case DBGFREGVALTYPE_U16:
325 switch (enmToType)
326 {
327 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u16; return VINF_DBGF_TRUNCATED_REGISTER;
328 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u16; return VINF_SUCCESS;
329 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u16; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
330 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u16; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
331 case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.u16; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
332 case DBGFREGVALTYPE_80: return VERR_DBGF_UNSUPPORTED_CAST;
333 case DBGFREGVALTYPE_LRD: pValue->lrd = InVal.u16; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
334 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
335
336 case DBGFREGVALTYPE_32BIT_HACK:
337 case DBGFREGVALTYPE_END:
338 case DBGFREGVALTYPE_INVALID:
339 break;
340 }
341 break;
342
343 case DBGFREGVALTYPE_U32:
344 switch (enmToType)
345 {
346 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u32; return VINF_DBGF_TRUNCATED_REGISTER;
347 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u32; return VINF_DBGF_TRUNCATED_REGISTER;
348 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u32; return VINF_SUCCESS;
349 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u32; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
350 case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.u32; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
351 case DBGFREGVALTYPE_80: return VERR_DBGF_UNSUPPORTED_CAST;
352 case DBGFREGVALTYPE_LRD: pValue->lrd = InVal.u32; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
353 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
354
355 case DBGFREGVALTYPE_32BIT_HACK:
356 case DBGFREGVALTYPE_END:
357 case DBGFREGVALTYPE_INVALID:
358 break;
359 }
360 break;
361
362 case DBGFREGVALTYPE_U64:
363 switch (enmToType)
364 {
365 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
366 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
367 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
368 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u64; return VINF_SUCCESS;
369 case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
370 case DBGFREGVALTYPE_80: return VERR_DBGF_UNSUPPORTED_CAST;
371 case DBGFREGVALTYPE_LRD: pValue->lrd = InVal.u64; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
372 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
373
374 case DBGFREGVALTYPE_32BIT_HACK:
375 case DBGFREGVALTYPE_END:
376 case DBGFREGVALTYPE_INVALID:
377 break;
378 }
379 break;
380
381 case DBGFREGVALTYPE_U128:
382 switch (enmToType)
383 {
384 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u128.s.Lo; return VINF_DBGF_TRUNCATED_REGISTER;
385 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u128.s.Lo; return VINF_DBGF_TRUNCATED_REGISTER;
386 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u128.s.Lo; return VINF_DBGF_TRUNCATED_REGISTER;
387 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u128.s.Lo; return VINF_DBGF_TRUNCATED_REGISTER;
388 case DBGFREGVALTYPE_U128: pValue->u128 = InVal.u128; return VINF_SUCCESS;
389 case DBGFREGVALTYPE_80: return VERR_DBGF_UNSUPPORTED_CAST;
390 case DBGFREGVALTYPE_LRD: pValue->lrd = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
391 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
392
393 case DBGFREGVALTYPE_32BIT_HACK:
394 case DBGFREGVALTYPE_END:
395 case DBGFREGVALTYPE_INVALID:
396 break;
397 }
398 break;
399
400 case DBGFREGVALTYPE_80:
401 return VERR_DBGF_UNSUPPORTED_CAST;
402
403 case DBGFREGVALTYPE_LRD:
404 switch (enmToType)
405 {
406 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.lrd; return VINF_DBGF_TRUNCATED_REGISTER;
407 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.lrd; return VINF_DBGF_TRUNCATED_REGISTER;
408 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.lrd; return VINF_DBGF_TRUNCATED_REGISTER;
409 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.lrd; return VINF_DBGF_TRUNCATED_REGISTER;
410 case DBGFREGVALTYPE_U128:
411 pValue->u128.s.Lo = (uint64_t)InVal.lrd;
412 pValue->u128.s.Hi = InVal.lrd / _4G / _4G;
413 return VINF_DBGF_TRUNCATED_REGISTER;
414 case DBGFREGVALTYPE_80: return VERR_DBGF_UNSUPPORTED_CAST;
415 case DBGFREGVALTYPE_LRD: pValue->lrd = InVal.lrd; return VINF_SUCCESS;
416 case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
417
418 case DBGFREGVALTYPE_32BIT_HACK:
419 case DBGFREGVALTYPE_END:
420 case DBGFREGVALTYPE_INVALID:
421 break;
422 }
423 break;
424
425 case DBGFREGVALTYPE_DTR:
426 switch (enmToType)
427 {
428 case DBGFREGVALTYPE_U8: pValue->u8 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
429 case DBGFREGVALTYPE_U16: pValue->u16 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
430 case DBGFREGVALTYPE_U32: pValue->u32 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
431 case DBGFREGVALTYPE_U64: pValue->u64 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
432 case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
433 case DBGFREGVALTYPE_80: return VERR_DBGF_UNSUPPORTED_CAST;
434 case DBGFREGVALTYPE_LRD: pValue->lrd = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
435 case DBGFREGVALTYPE_DTR: pValue->dtr = InVal.dtr; return VINF_SUCCESS;
436
437 case DBGFREGVALTYPE_32BIT_HACK:
438 case DBGFREGVALTYPE_END:
439 case DBGFREGVALTYPE_INVALID:
440 break;
441 }
442 break;
443
444 case DBGFREGVALTYPE_INVALID:
445 case DBGFREGVALTYPE_END:
446 case DBGFREGVALTYPE_32BIT_HACK:
447 break;
448 }
449
450 AssertMsgFailed(("%d / %d\n", enmFromType, enmToType));
451 return VERR_DBGF_UNSUPPORTED_CAST;
452}
453
454
455/**
456 * Worker for the CPU register queries.
457 *
458 * @returns VBox status code.
459 * @retval VINF_SUCCESS
460 * @retval VERR_INVALID_VM_HANDLE
461 * @retval VERR_INVALID_CPU_ID
462 * @retval VERR_DBGF_INVALID_REGISTER
463 * @retval VERR_DBGF_UNSUPPORTED_CAST
464 * @retval VINF_DBGF_TRUNCATED_REGISTER
465 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
466 *
467 * @param pVM The VM handle.
468 * @param idCpu The virtual CPU ID.
469 * @param enmReg The register to query.
470 * @param enmType The desired return type.
471 * @param puValue Where to return the register value.
472 */
473static DECLCALLBACK(int) dbgfR3RegCpuQueryWorker(PVM pVM, VMCPUID idCpu, DBGFREG enmReg, DBGFREGVALTYPE enmType, PDBGFREGVAL puValue)
474{
475 int rc = VINF_SUCCESS;
476 DBGF_REG_DB_LOCK_READ(pVM);
477
478 /*
479 * Look up the register set of the CPU.
480 */
481 /** @todo optimize this by adding a cpu register set array to DBGF. */
482 char szSetName[16];
483 RTStrPrintf(szSetName, sizeof(szSetName), "cpu%u", idCpu);
484 PDBGFREGSET pSet = (PDBGFREGSET)RTStrSpaceGet(&pVM->dbgf.s.RegSetSpace, szSetName);
485 if (RT_LIKELY(pSet))
486 {
487 /*
488 * Look up the register and get the register value.
489 */
490 if (RT_LIKELY(pSet->cDescs > (size_t)enmReg))
491 {
492 PCDBGFREGDESC pDesc = &pSet->paDescs[enmReg];
493
494 puValue->au64[0] = puValue->au64[1] = 0;
495 rc = pDesc->pfnGet(pSet->uUserArg.pv, pDesc, puValue);
496 if (RT_SUCCESS(rc))
497 {
498 /*
499 * Do the cast if the desired return type doesn't match what
500 * the getter returned.
501 */
502 if (pDesc->enmType == enmType)
503 rc = VINF_SUCCESS;
504 else
505 rc = dbgfR3RegValCast(puValue, pDesc->enmType, enmType);
506 }
507 }
508 else
509 rc = VERR_DBGF_INVALID_REGISTER;
510 }
511 else
512 rc = VERR_INVALID_CPU_ID;
513
514 DBGF_REG_DB_UNLOCK_READ(pVM);
515 return rc;
516}
517
518
519/**
520 * Queries a 8-bit CPU register value.
521 *
522 * @retval VINF_SUCCESS
523 * @retval VERR_INVALID_VM_HANDLE
524 * @retval VERR_INVALID_CPU_ID
525 * @retval VERR_DBGF_INVALID_REGISTER
526 * @retval VERR_DBGF_UNSUPPORTED_CAST
527 * @retval VINF_DBGF_TRUNCATED_REGISTER
528 *
529 * @param pVM The VM handle.
530 * @param idCpu The target CPU ID.
531 * @param enmReg The register that's being queried.
532 * @param pu8 Where to store the register value.
533 */
534VMMR3DECL(int) DBGFR3RegCpuQueryU8(PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint8_t *pu8)
535{
536 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
537 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
538
539 DBGFREGVAL Value;
540 int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryWorker, 5, pVM, idCpu, enmReg, DBGFREGVALTYPE_U8, &Value);
541 if (RT_SUCCESS(rc))
542 *pu8 = Value.u8;
543 else
544 *pu8 = 0;
545
546 return rc;
547}
548
549
550/**
551 * Queries a 16-bit CPU register value.
552 *
553 * @retval VINF_SUCCESS
554 * @retval VERR_INVALID_VM_HANDLE
555 * @retval VERR_INVALID_CPU_ID
556 * @retval VERR_DBGF_INVALID_REGISTER
557 * @retval VERR_DBGF_UNSUPPORTED_CAST
558 * @retval VINF_DBGF_TRUNCATED_REGISTER
559 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
560 *
561 * @param pVM The VM handle.
562 * @param idCpu The target CPU ID.
563 * @param enmReg The register that's being queried.
564 * @param pu16 Where to store the register value.
565 */
566VMMR3DECL(int) DBGFR3RegCpuQueryU16(PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint16_t *pu16)
567{
568 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
569 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
570
571 DBGFREGVAL Value;
572 int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryWorker, 5, pVM, idCpu, enmReg, DBGFREGVALTYPE_U16, &Value);
573 if (RT_SUCCESS(rc))
574 *pu16 = Value.u16;
575 else
576 *pu16 = 0;
577
578 return rc;
579}
580
581
582/**
583 * Queries a 32-bit CPU register value.
584 *
585 * @retval VINF_SUCCESS
586 * @retval VERR_INVALID_VM_HANDLE
587 * @retval VERR_INVALID_CPU_ID
588 * @retval VERR_DBGF_INVALID_REGISTER
589 * @retval VERR_DBGF_UNSUPPORTED_CAST
590 * @retval VINF_DBGF_TRUNCATED_REGISTER
591 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
592 *
593 * @param pVM The VM handle.
594 * @param idCpu The target CPU ID.
595 * @param enmReg The register that's being queried.
596 * @param pu32 Where to store the register value.
597 */
598VMMR3DECL(int) DBGFR3RegCpuQueryU32(PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint32_t *pu32)
599{
600 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
601 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
602
603 DBGFREGVAL Value;
604 int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryWorker, 5, pVM, idCpu, enmReg, DBGFREGVALTYPE_U32, &Value);
605 if (RT_SUCCESS(rc))
606 *pu32 = Value.u32;
607 else
608 *pu32 = 0;
609
610 return rc;
611}
612
613
614/**
615 * Queries a 64-bit CPU register value.
616 *
617 * @retval VINF_SUCCESS
618 * @retval VERR_INVALID_VM_HANDLE
619 * @retval VERR_INVALID_CPU_ID
620 * @retval VERR_DBGF_INVALID_REGISTER
621 * @retval VERR_DBGF_UNSUPPORTED_CAST
622 * @retval VINF_DBGF_TRUNCATED_REGISTER
623 * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
624 *
625 * @param pVM The VM handle.
626 * @param idCpu The target CPU ID.
627 * @param enmReg The register that's being queried.
628 * @param pu64 Where to store the register value.
629 */
630VMMR3DECL(int) DBGFR3RegCpuQueryU64(PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint64_t *pu64)
631{
632 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
633 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
634
635 DBGFREGVAL Value;
636 int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryWorker, 5, pVM, idCpu, enmReg, DBGFREGVALTYPE_U64, &Value);
637 if (RT_SUCCESS(rc))
638 *pu64 = Value.u64;
639 else
640 *pu64 = 0;
641
642 return rc;
643}
644
645
646/**
647 * Wrapper around CPUMQueryGuestMsr for dbgfR3RegCpuQueryBatchWorker.
648 *
649 * @retval VINF_SUCCESS
650 * @retval VERR_DBGF_INVALID_REGISTER
651 *
652 * @param pVCpu The current CPU.
653 * @param pReg The where to store the register value and
654 * size.
655 * @param idMsr The MSR to get.
656 */
657static void dbgfR3RegGetMsrBatch(PVMCPU pVCpu, PDBGFREGENTRY pReg, uint32_t idMsr)
658{
659 pReg->enmType = DBGFREGVALTYPE_U64;
660 int rc = CPUMQueryGuestMsr(pVCpu, idMsr, &pReg->Val.u64);
661 if (RT_FAILURE(rc))
662 {
663 AssertMsg(rc == VERR_CPUM_RAISE_GP_0, ("%Rrc\n", rc));
664 pReg->Val.u64 = 0;
665 }
666}
667
668
669static DECLCALLBACK(int) dbgfR3RegCpuQueryBatchWorker(PVM pVM, VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs)
670{
671#if 0
672 PVMCPU pVCpu = &pVM->aCpus[idCpu];
673 PCCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
674
675 PDBGFREGENTRY pReg = paRegs - 1;
676 while (cRegs-- > 0)
677 {
678 pReg++;
679 pReg->Val.au64[0] = 0;
680 pReg->Val.au64[1] = 0;
681
682 DBGFREG const enmReg = pReg->enmReg;
683 AssertMsgReturn(enmReg >= 0 && enmReg <= DBGFREG_END, ("%d (%#x)\n", enmReg, enmReg), VERR_DBGF_INVALID_REGISTER);
684 if (enmReg != DBGFREG_END)
685 {
686 PCDBGFREGDESC pDesc = &g_aDbgfRegDescs[enmReg];
687 if (!pDesc->pfnGet)
688 {
689 PCRTUINT128U pu = (PCRTUINT128U)((uintptr_t)pCtx + pDesc->offCtx);
690 pReg->enmType = pDesc->enmType;
691 switch (pDesc->enmType)
692 {
693 case DBGFREGVALTYPE_U8: pReg->Val.u8 = pu->au8[0]; break;
694 case DBGFREGVALTYPE_U16: pReg->Val.u16 = pu->au16[0]; break;
695 case DBGFREGVALTYPE_U32: pReg->Val.u32 = pu->au32[0]; break;
696 case DBGFREGVALTYPE_U64: pReg->Val.u64 = pu->au64[0]; break;
697 case DBGFREGVALTYPE_U128:
698 pReg->Val.au64[0] = pu->au64[0];
699 pReg->Val.au64[1] = pu->au64[1];
700 break;
701 case DBGFREGVALTYPE_LRD:
702 pReg->Val.au64[0] = pu->au64[0];
703 pReg->Val.au16[5] = pu->au16[5];
704 break;
705 default:
706 AssertMsgFailedReturn(("%s %d\n", pDesc->pszName, pDesc->enmType), VERR_INTERNAL_ERROR_3);
707 }
708 }
709 else
710 {
711 int rc = pDesc->pfnGet(pVCpu, pDesc, pCtx, &pReg->Val.u);
712 if (RT_FAILURE(rc))
713 return rc;
714 }
715 }
716 }
717 return VINF_SUCCESS;
718#else
719 return VERR_NOT_IMPLEMENTED;
720#endif
721}
722
723
724/**
725 * Query a batch of registers.
726 *
727 * @retval VINF_SUCCESS
728 * @retval VERR_INVALID_VM_HANDLE
729 * @retval VERR_INVALID_CPU_ID
730 * @retval VERR_DBGF_INVALID_REGISTER
731 *
732 * @param pVM The VM handle.
733 * @param idCpu The target CPU ID.
734 * @param paRegs Pointer to an array of @a cRegs elements. On
735 * input the enmReg members indicates which
736 * registers to query. On successful return the
737 * other members are set. DBGFREG_END can be used
738 * as a filler.
739 * @param cRegs The number of entries in @a paRegs.
740 */
741VMMR3DECL(int) DBGFR3RegCpuQueryBatch(PVM pVM, VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs)
742{
743 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
744 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
745 if (!cRegs)
746 return VINF_SUCCESS;
747 AssertReturn(cRegs < _1M, VERR_OUT_OF_RANGE);
748 AssertPtrReturn(paRegs, VERR_INVALID_POINTER);
749 size_t iReg = cRegs;
750 while (iReg-- > 0)
751 {
752 DBGFREG enmReg = paRegs[iReg].enmReg;
753 AssertMsgReturn(enmReg < DBGFREG_END && enmReg >= DBGFREG_AL, ("%d (%#x)", enmReg, enmReg), VERR_DBGF_INVALID_REGISTER);
754 }
755
756 return VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryBatchWorker, 4, pVM, idCpu, paRegs, cRegs);
757}
758
759
760/**
761 * Query a all registers for a Virtual CPU.
762 *
763 * @retval VINF_SUCCESS
764 * @retval VERR_INVALID_VM_HANDLE
765 * @retval VERR_INVALID_CPU_ID
766 *
767 * @param pVM The VM handle.
768 * @param idCpu The target CPU ID.
769 * @param paRegs Pointer to an array of @a cRegs elements.
770 * These will be filled with the CPU register
771 * values. Overflowing entries will be set to
772 * DBGFREG_END. The returned registers can be
773 * accessed by using the DBGFREG values as index.
774 * @param cRegs The number of entries in @a paRegs. The
775 * recommended value is DBGFREG_ALL_COUNT.
776 */
777VMMR3DECL(int) DBGFR3RegCpuQueryAll(PVM pVM, VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs)
778{
779 /*
780 * Validate input.
781 */
782 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
783 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
784 if (!cRegs)
785 return VINF_SUCCESS;
786 AssertReturn(cRegs < _1M, VERR_OUT_OF_RANGE);
787 AssertPtrReturn(paRegs, VERR_INVALID_POINTER);
788
789 /*
790 * Convert it into a batch query (lazy bird).
791 */
792 unsigned iReg = 0;
793 while (iReg < cRegs && iReg < DBGFREG_ALL_COUNT)
794 {
795 paRegs[iReg].enmReg = (DBGFREG)iReg;
796 iReg++;
797 }
798 while (iReg < cRegs)
799 paRegs[iReg++].enmReg = DBGFREG_END;
800
801 return VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryBatchWorker, 4, pVM, idCpu, paRegs, cRegs);
802}
803
804
805
806/**
807 * Gets the name of a register.
808 *
809 * @returns Pointer to read-only register name (lower case). NULL if the
810 * parameters are invalid.
811 * @param enmReg The register identifier.
812 * @param enmType The register type. This is for sort out
813 * aliases. Pass DBGFREGVALTYPE_INVALID to get
814 * the standard name.
815 */
816VMMR3DECL(const char *) DBGFR3RegCpuName(DBGFREG enmReg, DBGFREGVALTYPE enmType)
817{
818 AssertReturn(enmReg >= DBGFREG_AL && enmReg < DBGFREG_END, NULL);
819 AssertReturn(enmType >= DBGFREGVALTYPE_INVALID && enmType < DBGFREGVALTYPE_END, NULL);
820
821#if 0 /** @todo need the optimization */
822 PCDBGFREGDESC pDesc = &g_aDbgfRegDescs[enmReg];
823 PCDBGFREGALIAS pAlias = pDesc->paAliases;
824 if ( pAlias
825 && pDesc->enmType != enmType
826 && enmType != DBGFREGVALTYPE_INVALID)
827 {
828 while (pAlias->pszName)
829 {
830 if (pAlias->enmType == enmType)
831 return pAlias->pszName;
832 pAlias++;
833 }
834 }
835
836 return pDesc->pszName;
837#else
838 return NULL;
839#endif
840}
841
842/** @todo Implementing missing APIs. */
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