VirtualBox

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

Last change on this file since 74795 was 73097, checked in by vboxsync, 6 years ago

*: Made RT_UOFFSETOF, RT_OFFSETOF, RT_UOFFSETOF_ADD and RT_OFFSETOF_ADD work like builtin_offsetof() and require compile time resolvable requests, adding RT_UOFFSETOF_DYN for the dynamic questions that can only be answered at runtime.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use