VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFR3Type.cpp

Last change on this file was 99739, checked in by vboxsync, 12 months ago

*: doxygen corrections (mostly about removing @returns from functions returning void).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.2 KB
Line 
1/* $Id: DBGFR3Type.cpp 99739 2023-05-11 01:01:08Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Type Management.
4 */
5
6/*
7 * Copyright (C) 2016-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/** @page pg_dbgf_type DBGFType - Type Management
30 *
31 * The type management system is intended to ease retrieval of values from
32 * structures in the guest OS without having to take care of the size of pointers.
33 *
34 * @todo r=bird: We need to join this up with modules and address spaces. It
35 * cannot be standalone like this. Also, it must be comming from IPRT as
36 * there is no point in duplicating code (been there, done that with
37 * symbols and debug info already). This unfortunately means we need to
38 * find some common way of abstracting DWARF and Codeview type info so we
39 * can extend those debug info parsers to make type information available.
40 */
41
42
43/*********************************************************************************************************************************
44* Header Files *
45*********************************************************************************************************************************/
46#define LOG_GROUP LOG_GROUP_DBGF
47#include <VBox/vmm/dbgf.h>
48#include "DBGFInternal.h"
49#include <VBox/vmm/mm.h>
50#include <VBox/vmm/uvm.h>
51#include <VBox/err.h>
52#include <VBox/log.h>
53
54#include <iprt/assert.h>
55#include <iprt/thread.h>
56#include <iprt/param.h>
57
58
59/*********************************************************************************************************************************
60* Defined Constants And Macros *
61*********************************************************************************************************************************/
62
63/** Locks the type database for writing. */
64#define DBGF_TYPE_DB_LOCK_WRITE(pUVM) \
65 do { \
66 int rcSem = RTSemRWRequestWrite((pUVM)->dbgf.s.hTypeDbLock, RT_INDEFINITE_WAIT); \
67 AssertRC(rcSem); \
68 } while (0)
69
70/** Unlocks the type database after writing. */
71#define DBGF_TYPE_DB_UNLOCK_WRITE(pUVM) \
72 do { \
73 int rcSem = RTSemRWReleaseWrite((pUVM)->dbgf.s.hTypeDbLock); \
74 AssertRC(rcSem); \
75 } while (0)
76
77/** Locks the type database for reading. */
78#define DBGF_TYPE_DB_LOCK_READ(pUVM) \
79 do { \
80 int rcSem = RTSemRWRequestRead((pUVM)->dbgf.s.hTypeDbLock, RT_INDEFINITE_WAIT); \
81 AssertRC(rcSem); \
82 } while (0)
83
84/** Unlocks the type database after reading. */
85#define DBGF_TYPE_DB_UNLOCK_READ(pUVM) \
86 do { \
87 int rcSem = RTSemRWReleaseRead((pUVM)->dbgf.s.hTypeDbLock); \
88 AssertRC(rcSem); \
89 } while (0)
90
91
92/*********************************************************************************************************************************
93* Structures and Typedefs *
94*********************************************************************************************************************************/
95/**
96 * DBGF registered type.
97 */
98typedef struct DBGFTYPE
99{
100 /** String space core. */
101 RTSTRSPACECORE Core;
102 /** Pointer to the registration structure, NULL means builtin type. */
103 PCDBGFTYPEREG pReg;
104 /** How often the type is referenced by other types. */
105 volatile uint32_t cRefs;
106 /** Size of the type. */
107 size_t cbType;
108 /** Builtin type if pReg is NULL (otherwise it is invalid). */
109 DBGFTYPEBUILTIN enmTypeBuiltin;
110} DBGFTYPE;
111/** Pointer to a DBGF type. */
112typedef DBGFTYPE *PDBGFTYPE;
113
114
115/*********************************************************************************************************************************
116* Internal Functions *
117*********************************************************************************************************************************/
118static int dbgfR3TypeParseBufferByType(PUVM pUVM, PDBGFTYPE pType, uint8_t *pbBuf, size_t cbBuf,
119 PDBGFTYPEVAL *ppVal, size_t *pcbParsed);
120
121
122/**
123 * Looks up a type by the identifier.
124 *
125 * @returns Pointer to the type structure on success, NULL otherwise.
126 * @param pUVM The user mode VM handle.
127 * @param pszType The type identifier.
128 */
129static PDBGFTYPE dbgfR3TypeLookup(PUVM pUVM, const char *pszType)
130{
131 PRTSTRSPACE pTypeSpace = &pUVM->dbgf.s.TypeSpace;
132 return (PDBGFTYPE)RTStrSpaceGet(pTypeSpace, pszType);
133}
134
135
136/**
137 * Calculate the size of the given type.
138 *
139 * @returns VBox status code.
140 * @param pUVM The user mode VM handle.
141 * @param pType The type to calculate the size for.
142 * @param fCalcNested Flag whether to calculate the size for nested
143 * structs if the sizes are 0.
144 */
145static int dbgfR3TypeCalcSize(PUVM pUVM, PDBGFTYPE pType, bool fCalcNested)
146{
147 int rc = VINF_SUCCESS;
148
149 /* Builtin types are never recalculated. */
150 if (pType->pReg)
151 {
152 switch (pType->pReg->enmVariant)
153 {
154 case DBGFTYPEVARIANT_STRUCT:
155 {
156 size_t cbType = 0;
157
158 /* Go through the members and update size. */
159 for (uint32_t i = 0; i < pType->pReg->cMembers && RT_SUCCESS(rc); i++)
160 {
161 PCDBGFTYPEREGMEMBER pMember = &pType->pReg->paMembers[i];
162
163 if (pMember->fFlags & DBGFTYPEREGMEMBER_F_POINTER)
164 {
165 /* Use the current pointer size. */
166 PDBGFTYPE pTypeMember = dbgfR3TypeLookup(pUVM, "ptr_t");
167 if (RT_LIKELY(pTypeMember))
168 {
169 if (pMember->fFlags & DBGFTYPEREGMEMBER_F_ARRAY)
170 cbType += pMember->cElements * pTypeMember->cbType;
171 else
172 cbType += pTypeMember->cbType;
173 }
174 }
175 else
176 {
177 PDBGFTYPE pTypeMember = dbgfR3TypeLookup(pUVM, pMember->pszType);
178 if (RT_LIKELY(pTypeMember))
179 {
180 if ( pTypeMember->cbType == 0
181 && fCalcNested)
182 rc = dbgfR3TypeCalcSize(pUVM, pTypeMember, fCalcNested);
183
184 if (RT_SUCCESS(rc))
185 {
186 if (pMember->fFlags & DBGFTYPEREGMEMBER_F_ARRAY)
187 cbType += pMember->cElements * pTypeMember->cbType;
188 else
189 cbType += pTypeMember->cbType;
190 }
191 }
192 else
193 rc = VERR_INVALID_STATE;
194 }
195 }
196
197 if (RT_SUCCESS(rc))
198 pType->cbType = cbType;
199 break;
200 }
201
202 case DBGFTYPEVARIANT_UNION:
203 {
204 /* Get size of the biggest member and use that one. */
205 size_t cbType = 0;
206
207 for (uint32_t i = 0; i < pType->pReg->cMembers && RT_SUCCESS(rc); i++)
208 {
209 PCDBGFTYPEREGMEMBER pMember = &pType->pReg->paMembers[i];
210
211 if (pMember->fFlags & DBGFTYPEREGMEMBER_F_POINTER)
212 {
213 /* Use the current pointer size. */
214 PDBGFTYPE pTypeMember = dbgfR3TypeLookup(pUVM, "ptr_t");
215 if (RT_LIKELY(pTypeMember))
216 {
217 if (pMember->fFlags & DBGFTYPEREGMEMBER_F_ARRAY)
218 cbType = RT_MAX(cbType, pMember->cElements * pTypeMember->cbType);
219 else
220 cbType = RT_MAX(cbType, pTypeMember->cbType);
221 }
222 }
223 else
224 {
225 PDBGFTYPE pTypeMember = dbgfR3TypeLookup(pUVM, pMember->pszType);
226 if (RT_LIKELY(pTypeMember))
227 {
228 if ( pTypeMember->cbType == 0
229 && fCalcNested)
230 rc = dbgfR3TypeCalcSize(pUVM, pTypeMember, fCalcNested);
231
232 if (RT_SUCCESS(rc))
233 {
234 if (pMember->fFlags & DBGFTYPEREGMEMBER_F_ARRAY)
235 cbType = RT_MAX(cbType, pMember->cElements * pTypeMember->cbType);
236 else
237 cbType = RT_MAX(cbType, pTypeMember->cbType);
238 }
239 }
240 else
241 rc = VERR_INVALID_STATE;
242 }
243 }
244
245 if (RT_SUCCESS(rc))
246 pType->cbType = cbType;
247 break;
248 }
249
250 case DBGFTYPEVARIANT_ALIAS:
251 {
252 /* Get the size of the alias. */
253 PDBGFTYPE pAliased = dbgfR3TypeLookup(pUVM, pType->pReg->pszAliasedType);
254 if (RT_LIKELY(pAliased))
255 {
256 if ( pAliased->cbType == 0
257 && fCalcNested)
258 rc = dbgfR3TypeCalcSize(pUVM, pAliased, fCalcNested);
259
260 if (RT_SUCCESS(rc))
261 pType->cbType = pAliased->cbType;
262 }
263 else
264 rc = VERR_INVALID_STATE;
265 break;
266 }
267
268 default:
269 AssertMsgFailedReturn(("Invalid type variant: %d", pType->pReg->enmVariant), VERR_INVALID_STATE);
270 }
271 }
272
273 return rc;
274}
275
276
277/**
278 * Callback for clearing the size of all non built-in types.
279 *
280 * @returns VBox status code.
281 * @param pStr The type structure.
282 * @param pvUser The user mode VM handle.
283 */
284static DECLCALLBACK(int) dbgfR3TypeTraverseClearSize(PRTSTRSPACECORE pStr, void *pvUser)
285{
286 PDBGFTYPE pType = (PDBGFTYPE)pStr;
287
288 if (pType->pReg)
289 pType->cbType = 0;
290
291 NOREF(pvUser);
292 return VINF_SUCCESS;
293}
294
295
296/**
297 * Callback for calculating the size of all non built-in types.
298 *
299 * @returns VBox status code.
300 * @param pStr The type structure.
301 * @param pvUser The user mode VM handle.
302 */
303static DECLCALLBACK(int) dbgfR3TypeTraverseCalcSize(PRTSTRSPACECORE pStr, void *pvUser)
304{
305 PDBGFTYPE pType = (PDBGFTYPE)pStr;
306
307 if ( pType->pReg
308 && !pType->cbType)
309 dbgfR3TypeCalcSize((PUVM)pvUser, pType, true /* fCalcNested */);
310
311 return VINF_SUCCESS;
312}
313
314
315/**
316 * Recalculate the sizes of all registered non builtin types.
317 *
318 * @returns VBox status code.
319 * @param pUVM The user mode VM handle.
320 */
321static int dbgfR3TypeRecalculateAllSizes(PUVM pUVM)
322{
323 int rc = VINF_SUCCESS;
324
325 /*
326 * Clear the sizes of all non builtin types to 0 first so we know which type we
327 * visited later on.
328 */
329 rc = RTStrSpaceEnumerate(&pUVM->dbgf.s.TypeSpace, dbgfR3TypeTraverseClearSize, pUVM);
330 if (RT_SUCCESS(rc))
331 {
332 /* Now recalculate the size. */
333 rc = RTStrSpaceEnumerate(&pUVM->dbgf.s.TypeSpace, dbgfR3TypeTraverseCalcSize, pUVM);
334 }
335
336 return rc;
337}
338
339/**
340 * Validates a given type registration.
341 *
342 * @returns VBox status code.
343 * @param pUVM The user mode VM handle.
344 * @param pReg The type registration structure.
345 */
346static int dbgfR3TypeValidate(PUVM pUVM, PCDBGFTYPEREG pReg)
347{
348 int rc = VINF_SUCCESS;
349
350 switch (pReg->enmVariant)
351 {
352 case DBGFTYPEVARIANT_ALIAS:
353 if ( pReg->cMembers > 0
354 || pReg->paMembers
355 || !pReg->pszAliasedType)
356 rc = VERR_INVALID_PARAMETER;
357 else
358 {
359 PDBGFTYPE pAlias = dbgfR3TypeLookup(pUVM, pReg->pszAliasedType);
360 if (RT_UNLIKELY(!pAlias))
361 rc = VERR_NOT_FOUND;
362 }
363 break;
364 case DBGFTYPEVARIANT_STRUCT:
365 case DBGFTYPEVARIANT_UNION:
366 if (!pReg->pszAliasedType)
367 {
368 for (uint32_t i = 0; i < pReg->cMembers; i++)
369 {
370 PCDBGFTYPEREGMEMBER pMember = &pReg->paMembers[i];
371
372 /* Use the current pointer size. */
373 PDBGFTYPE pTypeMember = dbgfR3TypeLookup(pUVM, pMember->pszType);
374 if (RT_UNLIKELY(!pTypeMember))
375 {
376 rc = VERR_NOT_FOUND;
377 break;
378 }
379
380 if (pMember->fFlags & DBGFTYPEREGMEMBER_F_ARRAY)
381 {
382 if (pMember->cElements == 0)
383 rc = VERR_INVALID_PARAMETER;
384 }
385 else if (pMember->cElements != 0)
386 rc = VERR_INVALID_PARAMETER;
387 }
388 }
389 else
390 rc = VERR_INVALID_PARAMETER;
391 break;
392 default:
393 AssertMsgFailedBreakStmt(("Invalid type variant: %d", pReg->enmVariant),
394 rc = VERR_INVALID_PARAMETER);
395 }
396
397 return rc;
398}
399
400/**
401 * Retains or releases the reference counters to referenced types for the given
402 * type registration structure.
403 *
404 * @returns VBox status code.
405 * @param pUVM The user mode VM handle.
406 * @param pReg The type registration structure.
407 * @param fRetain Flag whether to retain or release references.
408 */
409static int dbgfR3TypeUpdateRefCnts(PUVM pUVM, PCDBGFTYPEREG pReg, bool fRetain)
410{
411 int rc = VINF_SUCCESS;
412
413 switch (pReg->enmVariant)
414 {
415 case DBGFTYPEVARIANT_ALIAS:
416 {
417 AssertPtr(pReg->pszAliasedType);
418
419 PDBGFTYPE pAlias = dbgfR3TypeLookup(pUVM, pReg->pszAliasedType);
420 AssertPtr(pAlias);
421
422 if (fRetain)
423 pAlias->cRefs++;
424 else
425 pAlias->cRefs--;
426 break;
427 }
428 case DBGFTYPEVARIANT_STRUCT:
429 case DBGFTYPEVARIANT_UNION:
430 {
431 for (uint32_t i = 0; i < pReg->cMembers; i++)
432 {
433 PCDBGFTYPEREGMEMBER pMember = &pReg->paMembers[i];
434
435 /* Use the current pointer size. */
436 PDBGFTYPE pTypeMember = dbgfR3TypeLookup(pUVM, pMember->pszType);
437 AssertPtr(pTypeMember);
438
439 if (fRetain)
440 pTypeMember->cRefs++;
441 else
442 pTypeMember->cRefs--;
443 }
444 break;
445 }
446 default:
447 AssertMsgFailedBreakStmt(("Invalid type variant: %d", pReg->enmVariant),
448 rc = VERR_INVALID_PARAMETER);
449 }
450
451 return rc;
452}
453
454
455/**
456 * Registers a single type in the database.
457 *
458 * @returns VBox status code.
459 * @retval VERR_ALREADY_EXISTS if the type exists already.
460 * @param pUVM The user mode VM handle.
461 * @param pReg The type registration structure.
462 */
463static int dbgfR3TypeRegister(PUVM pUVM, PCDBGFTYPEREG pReg)
464{
465 int rc = VINF_SUCCESS;
466
467 LogFlowFunc(("pUVM=%#p pReg=%#p{%s}\n", pUVM, pReg, pReg->pszType));
468
469 if (dbgfR3TypeLookup(pUVM, pReg->pszType) == NULL)
470 {
471 rc = dbgfR3TypeValidate(pUVM, pReg);
472 if (RT_SUCCESS(rc))
473 {
474 PDBGFTYPE pType = (PDBGFTYPE)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF_TYPE, sizeof(DBGFTYPE));
475 if (RT_LIKELY(pType))
476 {
477 pType->Core.pszString = pReg->pszType;
478 pType->pReg = pReg;
479 pType->cRefs = 0;
480 pType->enmTypeBuiltin = DBGFTYPEBUILTIN_INVALID;
481 rc = dbgfR3TypeCalcSize(pUVM, pType, false /* fCalcNested */);
482 if (RT_SUCCESS(rc))
483 {
484 rc = dbgfR3TypeUpdateRefCnts(pUVM, pReg, true /* fRetain */);
485 if (RT_SUCCESS(rc))
486 {
487 bool fSucc = RTStrSpaceInsert(&pUVM->dbgf.s.TypeSpace, &pType->Core);
488 Assert(fSucc);
489 if (!fSucc)
490 {
491 dbgfR3TypeUpdateRefCnts(pUVM, pReg, false /* fRetain */);
492 rc = VERR_ALREADY_EXISTS;
493 }
494 }
495 }
496
497 if (RT_FAILURE(rc))
498 MMR3HeapFree(pType);
499 }
500 else
501 rc = VERR_NO_MEMORY;
502 }
503 }
504 else
505 rc = VERR_ALREADY_EXISTS;
506
507 LogFlowFunc(("-> rc=%Rrc\n", rc));
508 return rc;
509}
510
511
512/**
513 * Registers a new built-in type
514 *
515 * @returns VBox status code.
516 * @param pUVM The user mode VM handle.
517 * @param enmTypeBuiltin The builtin type enum.
518 * @param cbType Size of the type in bytes.
519 * @param pszType The type identifier for the builtin type.
520 */
521static int dbgfR3TypeRegisterBuiltin(PUVM pUVM, DBGFTYPEBUILTIN enmTypeBuiltin,
522 size_t cbType, const char *pszType)
523{
524 LogFlowFunc(("pUVM=%#p enmBuiltin=%d pszType=%s\n", pUVM, enmTypeBuiltin, pszType));
525
526 AssertReturn(!dbgfR3TypeLookup(pUVM, pszType), VERR_INVALID_STATE);
527
528 int rc = VINF_SUCCESS;
529 PDBGFTYPE pType = (PDBGFTYPE)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF_TYPE, sizeof(DBGFTYPE));
530 if (RT_LIKELY(pType))
531 {
532 pType->Core.pszString = pszType;
533 pType->pReg = NULL;
534 pType->cRefs = 0;
535 pType->cbType = cbType;
536 pType->enmTypeBuiltin = enmTypeBuiltin;
537 bool fSucc = RTStrSpaceInsert(&pUVM->dbgf.s.TypeSpace, &pType->Core);
538 Assert(fSucc);
539 if (!fSucc)
540 rc = VERR_ALREADY_EXISTS;
541
542 if (RT_FAILURE(rc))
543 MMR3HeapFree(pType);
544 }
545 else
546 rc = VERR_NO_MEMORY;
547
548 return rc;
549}
550
551
552/**
553 * Registers builtin types.
554 *
555 * @returns VBox status code.
556 * @param pUVM The user mode VM handle.
557 */
558static int dbgfTypeRegisterBuiltinTypes(PUVM pUVM)
559{
560 int rc = dbgfR3TypeRegisterBuiltin(pUVM, DBGFTYPEBUILTIN_UINT8, sizeof(uint8_t), "uint8_t");
561 if (RT_SUCCESS(rc))
562 rc = dbgfR3TypeRegisterBuiltin(pUVM, DBGFTYPEBUILTIN_INT8, sizeof(int8_t), "int8_t");
563 if (RT_SUCCESS(rc))
564 rc = dbgfR3TypeRegisterBuiltin(pUVM, DBGFTYPEBUILTIN_UINT16, sizeof(uint16_t), "uint16_t");
565 if (RT_SUCCESS(rc))
566 rc = dbgfR3TypeRegisterBuiltin(pUVM, DBGFTYPEBUILTIN_INT16, sizeof(int16_t), "int16_t");
567 if (RT_SUCCESS(rc))
568 rc = dbgfR3TypeRegisterBuiltin(pUVM, DBGFTYPEBUILTIN_UINT32, sizeof(uint32_t), "uint32_t");
569 if (RT_SUCCESS(rc))
570 rc = dbgfR3TypeRegisterBuiltin(pUVM, DBGFTYPEBUILTIN_INT32, sizeof(int32_t), "int32_t");
571 if (RT_SUCCESS(rc))
572 rc = dbgfR3TypeRegisterBuiltin(pUVM, DBGFTYPEBUILTIN_UINT64, sizeof(uint64_t), "uint64_t");
573 if (RT_SUCCESS(rc))
574 rc = dbgfR3TypeRegisterBuiltin(pUVM, DBGFTYPEBUILTIN_INT64, sizeof(int64_t), "int64_t");
575 if (RT_SUCCESS(rc))
576 rc = dbgfR3TypeRegisterBuiltin(pUVM, DBGFTYPEBUILTIN_PTR32, sizeof(uint32_t), "ptr32_t");
577 if (RT_SUCCESS(rc))
578 rc = dbgfR3TypeRegisterBuiltin(pUVM, DBGFTYPEBUILTIN_PTR64, sizeof(uint64_t), "ptr64_t");
579 if (RT_SUCCESS(rc))
580 rc = dbgfR3TypeRegisterBuiltin(pUVM, DBGFTYPEBUILTIN_PTR, 0, "ptr_t");
581 if (RT_SUCCESS(rc))
582 rc = dbgfR3TypeRegisterBuiltin(pUVM, DBGFTYPEBUILTIN_SIZE, 0, "size_t");
583
584 return rc;
585}
586
587
588/**
589 * Parses a single entry for a given type and assigns the value from the byte buffer
590 * to the value entry.
591 *
592 * @returns VBox status code.
593 * @param pUVM The user mode VM handle.
594 * @param pMember The type member.
595 * @param pValEntry The value entry holding the value on success.
596 * @param pbBuf The raw byte buffer.
597 * @param cbBuf Size of the byte buffer.
598 * @param pcbParsed Where to store the amount of consumed bytes on success.
599 */
600static int dbgfR3TypeParseEntry(PUVM pUVM, PCDBGFTYPEREGMEMBER pMember, PDBGFTYPEVALENTRY pValEntry,
601 uint8_t *pbBuf, size_t cbBuf, size_t *pcbParsed)
602{
603 int rc = VINF_SUCCESS;
604 PDBGFTYPE pTypeMember = dbgfR3TypeLookup(pUVM, pMember->pszType);
605 uint32_t cValBufs = 1;
606 size_t cbParsed = 0;
607 PDBGFTYPEVALBUF pValBuf = &pValEntry->Buf.Val;
608
609 AssertPtrReturn(pTypeMember, VERR_INVALID_STATE);
610
611 if (pMember->fFlags & DBGFTYPEREGMEMBER_F_ARRAY)
612 {
613 cValBufs = pMember->cElements;
614 pValBuf = (PDBGFTYPEVALBUF)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF_TYPE, cValBufs * sizeof(DBGFTYPEVALBUF));
615 if (RT_UNLIKELY(!pValBuf))
616 rc = VERR_NO_MEMORY;
617
618 pValEntry->Buf.pVal = pValBuf;
619 pValEntry->cEntries = cValBufs;
620 pValEntry->cbType = pTypeMember->cbType;
621 }
622
623 if (RT_SUCCESS(rc))
624 {
625 for (uint32_t iValBuf = 0; iValBuf < cValBufs && RT_SUCCESS(rc); iValBuf++)
626 {
627 size_t cbThisParsed = 0;
628
629 if (pTypeMember->pReg)
630 {
631 /* Compound or aliased type */
632 rc = dbgfR3TypeParseBufferByType(pUVM, pTypeMember, pbBuf, cbBuf,
633 &pValBuf->pVal, &cbThisParsed);
634 if (RT_SUCCESS(rc))
635 pValEntry->enmType = DBGFTYPEBUILTIN_COMPOUND;
636 }
637 else
638 {
639 void *pvVal = NULL;
640
641 switch (pTypeMember->enmTypeBuiltin)
642 {
643 case DBGFTYPEBUILTIN_UINT8:
644 pvVal = &pValBuf->u8;
645 cbThisParsed = 1;
646 break;
647 case DBGFTYPEBUILTIN_INT8:
648 pvVal = &pValBuf->i8;
649 cbThisParsed = 1;
650 break;
651 case DBGFTYPEBUILTIN_UINT16:
652 pvVal = &pValBuf->u16;
653 cbThisParsed = 2;
654 break;
655 case DBGFTYPEBUILTIN_INT16:
656 pvVal = &pValBuf->i16;
657 cbThisParsed = 2;
658 break;
659 case DBGFTYPEBUILTIN_UINT32:
660 pvVal = &pValBuf->u32;
661 cbThisParsed = 4;
662 break;
663 case DBGFTYPEBUILTIN_INT32:
664 pvVal = &pValBuf->i32;
665 cbThisParsed = 4;
666 break;
667 case DBGFTYPEBUILTIN_UINT64:
668 pvVal = &pValBuf->u64;
669 cbThisParsed = 8;
670 break;
671 case DBGFTYPEBUILTIN_INT64:
672 pvVal = &pValBuf->i64;
673 cbThisParsed = 8;
674 break;
675 case DBGFTYPEBUILTIN_PTR32:
676 pvVal = &pValBuf->GCPtr;
677 cbThisParsed = 4;
678 break;
679 case DBGFTYPEBUILTIN_PTR64:
680 pvVal = &pValBuf->GCPtr;
681 cbThisParsed = 8;
682 break;
683 case DBGFTYPEBUILTIN_PTR:
684 pvVal = &pValBuf->GCPtr;
685 cbThisParsed = pTypeMember->cbType;
686 break;
687 case DBGFTYPEBUILTIN_SIZE:
688 pvVal = &pValBuf->size;
689 cbThisParsed = pTypeMember->cbType;
690 break;
691 case DBGFTYPEBUILTIN_FLOAT32:
692 case DBGFTYPEBUILTIN_FLOAT64:
693 case DBGFTYPEBUILTIN_COMPOUND:
694 default:
695 AssertMsgFailedBreakStmt(("Invalid built-in type specified: %d\n", pTypeMember->enmTypeBuiltin),
696 rc = VERR_INVALID_STATE);
697 }
698
699 if (RT_SUCCESS(rc))
700 {
701 pValEntry->enmType = pTypeMember->enmTypeBuiltin;
702 if (cbBuf >= cbThisParsed)
703 memcpy(pvVal, pbBuf, cbThisParsed);
704 else
705 rc = VERR_BUFFER_OVERFLOW;
706 }
707 }
708
709 pValBuf++;
710
711 cbParsed += cbThisParsed;
712 pbBuf += cbThisParsed;
713 cbBuf -= cbThisParsed;
714 }
715 }
716
717 if ( RT_FAILURE(rc)
718 && cValBufs > 1)
719 MMR3HeapFree(pValBuf);
720
721 if (RT_SUCCESS(rc))
722 {
723 pValEntry->cEntries = cValBufs;
724 *pcbParsed = cbParsed;
725 }
726
727 return rc;
728}
729
730
731/**
732 * Parses the given byte buffer and returns the value based no the type information.
733 *
734 * @returns VBox status code.
735 * @param pUVM The user mode VM handle.
736 * @param pType The type information.
737 * @param pbBuf The byte buffer to parse.
738 * @param cbBuf Size of the buffer.
739 * @param ppVal Where to store the pointer to the value on success.
740 * @param pcbParsed How many bytes of the buffer we consumed.
741 */
742static int dbgfR3TypeParseBufferByType(PUVM pUVM, PDBGFTYPE pType, uint8_t *pbBuf, size_t cbBuf,
743 PDBGFTYPEVAL *ppVal, size_t *pcbParsed)
744{
745 int rc = VINF_SUCCESS;
746 uint32_t cEntries = pType->pReg ? pType->pReg->cMembers : 1;
747 PDBGFTYPEVAL pVal = (PDBGFTYPEVAL)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF_TYPE,
748 RT_UOFFSETOF_DYN(DBGFTYPEVAL, aEntries[cEntries]));
749 if (RT_LIKELY(pVal))
750 {
751 size_t cbParsed = 0;
752
753 pVal->pTypeReg = pType->pReg;
754 for (uint32_t i = 0; i < cEntries && RT_SUCCESS(rc); i++)
755 {
756 PCDBGFTYPEREGMEMBER pMember = &pType->pReg->paMembers[i];
757 PDBGFTYPEVALENTRY pValEntry = &pVal->aEntries[i];
758 rc = dbgfR3TypeParseEntry(pUVM, pMember, pValEntry, pbBuf, cbBuf, &cbParsed);
759 if (RT_SUCCESS(rc))
760 {
761 pbBuf += cbParsed;
762 cbBuf -= cbParsed;
763 }
764 }
765
766 if (RT_SUCCESS(rc))
767 {
768 pVal->cEntries = cEntries;
769 *pcbParsed = cbParsed;
770 *ppVal = pVal;
771 }
772 else
773 MMR3HeapFree(pVal); /** @todo Leak for embedded structs. */
774 }
775 else
776 rc = VERR_NO_MEMORY;
777
778 return rc;
779}
780
781
782/**
783 * Dumps one level of a typed value.
784 *
785 * @returns VBox status code.
786 * @param pVal The value to dump.
787 * @param iLvl The current level.
788 * @param cLvlMax The maximum level.
789 * @param pfnDump The dumper callback.
790 * @param pvUser The opaque user data to pass to the dumper callback.
791 */
792static int dbgfR3TypeValDump(PDBGFTYPEVAL pVal, uint32_t iLvl, uint32_t cLvlMax,
793 PFNDBGFR3TYPEVALDUMP pfnDump, void *pvUser)
794{
795 int rc = VINF_SUCCESS;
796 PCDBGFTYPEREG pType = pVal->pTypeReg;
797
798 for (uint32_t i = 0; i < pVal->cEntries && rc == VINF_SUCCESS; i++)
799 {
800 PCDBGFTYPEREGMEMBER pTypeMember = &pType->paMembers[i];
801 PDBGFTYPEVALENTRY pValEntry = &pVal->aEntries[i];
802 PDBGFTYPEVALBUF pValBuf = pValEntry->cEntries > 1 ? pValEntry->Buf.pVal : &pValEntry->Buf.Val;
803
804 rc = pfnDump(0 /* off */, pTypeMember->pszName, iLvl, pValEntry->enmType, pValEntry->cbType,
805 pValBuf, pValEntry->cEntries, pvUser);
806 if ( rc == VINF_SUCCESS
807 && pValEntry->enmType == DBGFTYPEBUILTIN_COMPOUND
808 && iLvl < cLvlMax)
809 {
810 /* Print embedded structs. */
811 for (uint32_t iValBuf = 0; iValBuf < pValEntry->cEntries && rc == VINF_SUCCESS; iValBuf++)
812 rc = dbgfR3TypeValDump(pValBuf[iValBuf].pVal, iLvl + 1, cLvlMax, pfnDump, pvUser);
813 }
814 }
815
816 return rc;
817}
818
819
820/**
821 * Dumps one level of a type.
822 *
823 * @returns VBox status code.
824 * @param pUVM The user mode VM handle.
825 * @param pType The type to dump.
826 * @param iLvl The current level.
827 * @param cLvlMax The maximum level.
828 * @param pfnDump The dumper callback.
829 * @param pvUser The opaque user data to pass to the dumper callback.
830 */
831static int dbgfR3TypeDump(PUVM pUVM, PDBGFTYPE pType, uint32_t iLvl, uint32_t cLvlMax,
832 PFNDBGFR3TYPEDUMP pfnDump, void *pvUser)
833{
834 int rc = VINF_SUCCESS;
835 PCDBGFTYPEREG pTypeReg = pType->pReg;
836
837 switch (pTypeReg->enmVariant)
838 {
839 case DBGFTYPEVARIANT_ALIAS:
840 rc = VERR_NOT_IMPLEMENTED;
841 break;
842 case DBGFTYPEVARIANT_STRUCT:
843 case DBGFTYPEVARIANT_UNION:
844 for (uint32_t i = 0; i < pTypeReg->cMembers && rc == VINF_SUCCESS; i++)
845 {
846 PCDBGFTYPEREGMEMBER pTypeMember = &pTypeReg->paMembers[i];
847 PDBGFTYPE pTypeResolved = dbgfR3TypeLookup(pUVM, pTypeMember->pszType);
848
849 rc = pfnDump(0 /* off */, pTypeMember->pszName, iLvl, pTypeMember->pszType,
850 pTypeMember->fFlags, pTypeMember->cElements, pvUser);
851 if ( rc == VINF_SUCCESS
852 && pTypeResolved->pReg
853 && iLvl < cLvlMax)
854 {
855 /* Print embedded structs. */
856 rc = dbgfR3TypeDump(pUVM, pTypeResolved, iLvl + 1, cLvlMax, pfnDump, pvUser);
857 }
858 }
859 break;
860 default:
861 AssertMsgFailed(("Invalid type variant: %u\n", pTypeReg->enmVariant));
862 rc = VERR_INVALID_STATE;
863 }
864
865 return rc;
866}
867
868
869/**
870 * Initializes the type database.
871 *
872 * @returns VBox status code.
873 * @param pUVM The user mode VM handle.
874 */
875DECLHIDDEN(int) dbgfR3TypeInit(PUVM pUVM)
876{
877 int rc = VINF_SUCCESS;
878 if (!pUVM->dbgf.s.fTypeDbInitialized)
879 {
880 rc = RTSemRWCreate(&pUVM->dbgf.s.hTypeDbLock);
881 if (RT_SUCCESS(rc))
882 {
883 rc = dbgfTypeRegisterBuiltinTypes(pUVM);
884 if (RT_FAILURE(rc))
885 {
886 RTSemRWDestroy(pUVM->dbgf.s.hTypeDbLock);
887 pUVM->dbgf.s.hTypeDbLock = NIL_RTSEMRW;
888 }
889 }
890 pUVM->dbgf.s.fTypeDbInitialized = RT_SUCCESS(rc);
891 }
892 return rc;
893}
894
895
896/**
897 * Terminates the type database.
898 *
899 * @param pUVM The user mode VM handle.
900 */
901DECLHIDDEN(void) dbgfR3TypeTerm(PUVM pUVM)
902{
903 RTSemRWDestroy(pUVM->dbgf.s.hTypeDbLock);
904 pUVM->dbgf.s.hTypeDbLock = NIL_RTSEMRW;
905 pUVM->dbgf.s.fTypeDbInitialized = false;
906}
907
908
909/**
910 * Registers a new type for lookup.
911 *
912 * @returns VBox status code.
913 * @retval VERR_ALREADY_EXISTS if the type exists already.
914 * @param pUVM The user mode VM handle.
915 * @param cTypes Number of types to register.
916 * @param paTypes The array of type registration structures to register.
917 */
918VMMR3DECL(int) DBGFR3TypeRegister(PUVM pUVM, uint32_t cTypes, PCDBGFTYPEREG paTypes)
919{
920 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
921 AssertReturn(cTypes > 0, VERR_INVALID_PARAMETER);
922 AssertPtrReturn(paTypes, VERR_INVALID_POINTER);
923
924 int rc = VINF_SUCCESS;
925 if (!pUVM->dbgf.s.fTypeDbInitialized)
926 {
927 rc = dbgfR3TypeInit(pUVM);
928 if (RT_FAILURE(rc))
929 return rc;
930 }
931
932 DBGF_TYPE_DB_LOCK_WRITE(pUVM);
933 for (uint32_t i = 0; i < cTypes && RT_SUCCESS(rc); i++)
934 {
935 rc = dbgfR3TypeRegister(pUVM, &paTypes[i]);
936 if ( RT_FAILURE(rc)
937 && i > 0)
938 {
939 /* Deregister types in reverse order. */
940 do
941 {
942 int rc2 = DBGFR3TypeDeregister(pUVM, paTypes[i].pszType);
943 AssertRC(rc2);
944 i--;
945 } while (i > 0);
946
947 break;
948 }
949 }
950 DBGF_TYPE_DB_UNLOCK_WRITE(pUVM);
951
952 return rc;
953}
954
955
956/**
957 * Deregisters a previously registered type.
958 *
959 * @returns VBox status code.
960 * @retval VERR_NOT_FOUND if the type is not known.
961 * @retval VERR_RESOURCE_IN_USE if the type is used by another type.
962 * @param pUVM The user mode VM handle.
963 * @param pszType The type identifier to deregister.
964 */
965VMMR3DECL(int) DBGFR3TypeDeregister(PUVM pUVM, const char *pszType)
966{
967 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
968 AssertPtrReturn(pszType, VERR_INVALID_POINTER);
969
970 int rc = VINF_SUCCESS;
971 if (!pUVM->dbgf.s.fTypeDbInitialized)
972 {
973 rc = dbgfR3TypeInit(pUVM);
974 if (RT_FAILURE(rc))
975 return rc;
976 }
977
978 DBGF_TYPE_DB_LOCK_WRITE(pUVM);
979 PDBGFTYPE pType = dbgfR3TypeLookup(pUVM, pszType);
980 if (pType)
981 {
982 if (!pType->cRefs)
983 {
984
985 }
986 else
987 rc = VERR_RESOURCE_IN_USE;
988 }
989 else
990 rc = VERR_NOT_FOUND;
991 DBGF_TYPE_DB_UNLOCK_WRITE(pUVM);
992
993 return rc;
994}
995
996
997/**
998 * Return the type registration structure for the given type identifier.
999 *
1000 * @returns VBox status code.
1001 * @retval VERR_NOT_FOUND if the type is not known.
1002 * @param pUVM The user mode VM handle.
1003 * @param pszType The type identifier to get the registration structure from.
1004 * @param ppTypeReg Where to store the type registration structure on success.
1005 */
1006VMMR3DECL(int) DBGFR3TypeQueryReg(PUVM pUVM, const char *pszType, PCDBGFTYPEREG *ppTypeReg)
1007{
1008 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1009 AssertPtrReturn(pszType, VERR_INVALID_POINTER);
1010 AssertPtrReturn(ppTypeReg, VERR_INVALID_POINTER);
1011
1012 int rc = VINF_SUCCESS;
1013 if (!pUVM->dbgf.s.fTypeDbInitialized)
1014 {
1015 rc = dbgfR3TypeInit(pUVM);
1016 if (RT_FAILURE(rc))
1017 return rc;
1018 }
1019
1020 DBGF_TYPE_DB_LOCK_READ(pUVM);
1021 PDBGFTYPE pType = dbgfR3TypeLookup(pUVM, pszType);
1022 if (pType)
1023 *ppTypeReg = pType->pReg;
1024 else
1025 rc = VERR_NOT_FOUND;
1026 DBGF_TYPE_DB_UNLOCK_READ(pUVM);
1027
1028 LogFlowFunc(("-> rc=%Rrc\n", rc));
1029 return rc;
1030}
1031
1032
1033/**
1034 * Queries the size a given type would occupy in memory.
1035 *
1036 * @returns VBox status code.
1037 * @retval VERR_NOT_FOUND if the type is not known.
1038 * @param pUVM The user mode VM handle.
1039 * @param pszType The type identifier.
1040 * @param pcbType Where to store the amount of memory occupied in bytes.
1041 */
1042VMMR3DECL(int) DBGFR3TypeQuerySize(PUVM pUVM, const char *pszType, size_t *pcbType)
1043{
1044 LogFlowFunc(("pUVM=%#p pszType=%s pcbType=%#p\n", pUVM, pszType, pcbType));
1045 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1046 AssertPtrReturn(pszType, VERR_INVALID_POINTER);
1047 AssertPtrReturn(pcbType, VERR_INVALID_POINTER);
1048
1049 int rc = VINF_SUCCESS;
1050 if (!pUVM->dbgf.s.fTypeDbInitialized)
1051 {
1052 rc = dbgfR3TypeInit(pUVM);
1053 if (RT_FAILURE(rc))
1054 return rc;
1055 }
1056
1057 DBGF_TYPE_DB_LOCK_READ(pUVM);
1058 PDBGFTYPE pType = dbgfR3TypeLookup(pUVM, pszType);
1059 if (pType)
1060 *pcbType = pType->cbType;
1061 else
1062 rc = VERR_NOT_FOUND;
1063 DBGF_TYPE_DB_UNLOCK_READ(pUVM);
1064
1065 LogFlowFunc(("-> rc=%Rrc\n", rc));
1066 return rc;
1067}
1068
1069
1070/**
1071 * Sets the size of the given type in bytes.
1072 *
1073 * @returns VBox status code.
1074 * @retval VERR_NOT_FOUND if the type is not known.
1075 * @retval VERR_NOT_SUPPORTED if changing the size of this type is not supported.
1076 * @param pUVM The user mode VM handle.
1077 * @param pszType The type identifier.
1078 * @param cbType The size of the type in bytes.
1079 *
1080 * @note: This currently works only for the builtin pointer type without the explicit
1081 * size (ptr_t or DBGFTYPEBUILTIN_PTR).
1082 */
1083VMMR3DECL(int) DBGFR3TypeSetSize(PUVM pUVM, const char *pszType, size_t cbType)
1084{
1085 LogFlowFunc(("pUVM=%#p pszType=%s cbType=%zu\n", pUVM, pszType, cbType));
1086 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1087 AssertPtrReturn(pszType, VERR_INVALID_POINTER);
1088 AssertReturn(cbType > 0, VERR_INVALID_PARAMETER);
1089
1090 int rc = VINF_SUCCESS;
1091 if (!pUVM->dbgf.s.fTypeDbInitialized)
1092 {
1093 rc = dbgfR3TypeInit(pUVM);
1094 if (RT_FAILURE(rc))
1095 return rc;
1096 }
1097
1098 DBGF_TYPE_DB_LOCK_WRITE(pUVM);
1099 PDBGFTYPE pType = dbgfR3TypeLookup(pUVM, pszType);
1100 if (pType)
1101 {
1102 if ( !pType->pReg
1103 && ( pType->enmTypeBuiltin == DBGFTYPEBUILTIN_PTR
1104 || pType->enmTypeBuiltin == DBGFTYPEBUILTIN_SIZE))
1105 {
1106 if (pType->cbType != cbType)
1107 {
1108 pType->cbType = cbType;
1109 rc = dbgfR3TypeRecalculateAllSizes(pUVM);
1110 }
1111 }
1112 else
1113 rc = VERR_NOT_SUPPORTED;
1114 }
1115 else
1116 rc = VERR_NOT_FOUND;
1117 DBGF_TYPE_DB_UNLOCK_WRITE(pUVM);
1118
1119 LogFlowFunc(("-> rc=%Rrc\n", rc));
1120 return rc;
1121}
1122
1123
1124/**
1125 * Dumps the type information of the given type.
1126 *
1127 * @returns VBox status code.
1128 * @param pUVM The user mode VM handle.
1129 * @param pszType The type identifier.
1130 * @param fFlags Flags to control the dumping (reserved, MBZ).
1131 * @param cLvlMax Maximum levels to nest.
1132 * @param pfnDump The dumper callback.
1133 * @param pvUser Opaque user data.
1134 */
1135VMMR3DECL(int) DBGFR3TypeDumpEx(PUVM pUVM, const char *pszType, uint32_t fFlags,
1136 uint32_t cLvlMax, PFNDBGFR3TYPEDUMP pfnDump, void *pvUser)
1137{
1138 LogFlowFunc(("pUVM=%#p pszType=%s fFlags=%#x cLvlMax=%u pfnDump=%#p pvUser=%#p\n",
1139 pUVM, pszType, fFlags, cLvlMax, pfnDump, pvUser));
1140 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1141 AssertPtrReturn(pszType, VERR_INVALID_POINTER);
1142 AssertPtrReturn(pfnDump, VERR_INVALID_POINTER);
1143 RT_NOREF_PV(fFlags);
1144
1145 int rc = VINF_SUCCESS;
1146 if (!pUVM->dbgf.s.fTypeDbInitialized)
1147 {
1148 rc = dbgfR3TypeInit(pUVM);
1149 if (RT_FAILURE(rc))
1150 return rc;
1151 }
1152
1153 DBGF_TYPE_DB_LOCK_READ(pUVM);
1154 PDBGFTYPE pType = dbgfR3TypeLookup(pUVM, pszType);
1155 if (pType)
1156 rc = dbgfR3TypeDump(pUVM, pType, 0 /* iLvl */, cLvlMax, pfnDump, pvUser);
1157 else
1158 rc = VERR_NOT_FOUND;
1159 DBGF_TYPE_DB_UNLOCK_READ(pUVM);
1160
1161 LogFlowFunc(("-> rc=%Rrc\n", rc));
1162 return rc;
1163}
1164
1165
1166/**
1167 * Returns the value of a memory buffer at the given address formatted for the given
1168 * type.
1169 *
1170 * @returns VBox status code.
1171 * @retval VERR_NOT_FOUND if the type is not known.
1172 * @param pUVM The user mode VM handle.
1173 * @param pAddress The address to start reading from.
1174 * @param pszType The type identifier.
1175 * @param ppVal Where to store the pointer to the value structure
1176 * on success.
1177 */
1178VMMR3DECL(int) DBGFR3TypeQueryValByType(PUVM pUVM, PCDBGFADDRESS pAddress, const char *pszType,
1179 PDBGFTYPEVAL *ppVal)
1180{
1181 LogFlowFunc(("pUVM=%#p pAddress=%#p pszType=%s ppVal=%#p\n", pUVM, pAddress, pszType, ppVal));
1182 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1183 AssertPtrReturn(pAddress, VERR_INVALID_POINTER);
1184 AssertPtrReturn(pszType, VERR_INVALID_POINTER);
1185 AssertPtrReturn(ppVal, VERR_INVALID_POINTER);
1186
1187 int rc = VINF_SUCCESS;
1188 if (!pUVM->dbgf.s.fTypeDbInitialized)
1189 {
1190 rc = dbgfR3TypeInit(pUVM);
1191 if (RT_FAILURE(rc))
1192 return rc;
1193 }
1194
1195 DBGF_TYPE_DB_LOCK_READ(pUVM);
1196 PDBGFTYPE pType = dbgfR3TypeLookup(pUVM, pszType);
1197 if (pType)
1198 {
1199 uint8_t *pbBuf = (uint8_t *)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF_TYPE, pType->cbType);
1200 if (RT_LIKELY(pbBuf))
1201 {
1202 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, pAddress, pbBuf, pType->cbType);
1203 if (RT_SUCCESS(rc))
1204 {
1205 /* Parse the buffer based on the type. */
1206 size_t cbParsed = 0;
1207 rc = dbgfR3TypeParseBufferByType(pUVM, pType, pbBuf, pType->cbType,
1208 ppVal, &cbParsed);
1209 }
1210
1211 MMR3HeapFree(pbBuf);
1212 }
1213 else
1214 rc = VERR_NO_MEMORY;
1215 }
1216 else
1217 rc = VERR_NOT_FOUND;
1218 DBGF_TYPE_DB_UNLOCK_READ(pUVM);
1219
1220 LogFlowFunc(("-> rc=%Rrc\n", rc));
1221 return rc;
1222}
1223
1224
1225/**
1226 * Frees all acquired resources of a value previously obtained with
1227 * DBGFR3TypeQueryValByType().
1228 *
1229 * @param pVal The value to free.
1230 */
1231VMMR3DECL(void) DBGFR3TypeValFree(PDBGFTYPEVAL pVal)
1232{
1233 AssertPtrReturnVoid(pVal);
1234
1235 for (uint32_t i = 0; i < pVal->cEntries; i++)
1236 {
1237 PDBGFTYPEVALENTRY pValEntry = &pVal->aEntries[i];
1238 PDBGFTYPEVALBUF pValBuf = pValEntry->cEntries > 1 ? pValEntry->Buf.pVal : &pValEntry->Buf.Val;
1239
1240 if (pValEntry->enmType == DBGFTYPEBUILTIN_COMPOUND)
1241 for (uint32_t iBuf = 0; iBuf < pValEntry->cEntries; iBuf++)
1242 DBGFR3TypeValFree(pValBuf->pVal);
1243
1244 if (pValEntry->cEntries > 1)
1245 MMR3HeapFree(pValEntry->Buf.pVal);
1246 }
1247
1248 MMR3HeapFree(pVal);
1249}
1250
1251
1252/**
1253 * Reads the guest memory with the given type and dumps the content of the type.
1254 *
1255 * @returns VBox status code.
1256 * @param pUVM The user mode VM handle.
1257 * @param pAddress The address to start reading from.
1258 * @param pszType The type identifier.
1259 * @param fFlags Flags for tweaking (reserved, must be zero).
1260 * @param cLvlMax Maximum number of levels to expand embedded structs.
1261 * @param pfnDump The dumper callback.
1262 * @param pvUser The opaque user data to pass to the callback.
1263 */
1264VMMR3DECL(int) DBGFR3TypeValDumpEx(PUVM pUVM, PCDBGFADDRESS pAddress, const char *pszType, uint32_t fFlags,
1265 uint32_t cLvlMax, FNDBGFR3TYPEVALDUMP pfnDump, void *pvUser)
1266{
1267 LogFlowFunc(("pUVM=%#p pAddress=%#p pszType=%s fFlags=%#x pfnDump=%#p pvUser=%#p\n",
1268 pUVM, pAddress, pszType, fFlags,pfnDump, pvUser));
1269 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1270 AssertPtrReturn(pAddress, VERR_INVALID_POINTER);
1271 AssertPtrReturn(pszType, VERR_INVALID_POINTER);
1272 AssertPtrReturn(pfnDump, VERR_INVALID_POINTER);
1273 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
1274 AssertReturn(cLvlMax >= 1, VERR_INVALID_PARAMETER);
1275
1276 PDBGFTYPEVAL pVal = NULL;
1277 int rc = DBGFR3TypeQueryValByType(pUVM, pAddress, pszType, &pVal);
1278 if (RT_SUCCESS(rc))
1279 {
1280 rc = dbgfR3TypeValDump(pVal, 0 /* iLvl */, cLvlMax, pfnDump, pvUser);
1281 DBGFR3TypeValFree(pVal);
1282 }
1283
1284 LogFlowFunc(("-> rc=%Rrc\n", rc));
1285 return rc;
1286}
1287
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use