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 | */
|
---|
73 | typedef 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 | */
|
---|
89 | typedef 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. */
|
---|
115 | typedef 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 | */
|
---|
126 | static 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 | */
|
---|
152 | static 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 | */
|
---|
248 | VMMR3_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 | */
|
---|
263 | VMMR3DECL(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 | */
|
---|
279 | DECLINLINE(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 | */
|
---|
298 | static 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 | */
|
---|
473 | static 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 | */
|
---|
534 | VMMR3DECL(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 | */
|
---|
566 | VMMR3DECL(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 | */
|
---|
598 | VMMR3DECL(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 | */
|
---|
630 | VMMR3DECL(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 | */
|
---|
657 | static 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 |
|
---|
669 | static 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 | */
|
---|
741 | VMMR3DECL(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 | */
|
---|
777 | VMMR3DECL(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 | */
|
---|
816 | VMMR3DECL(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. */
|
---|