VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFR3Flow.cpp@ 80239

Last change on this file since 80239 was 80191, checked in by vboxsync, 5 years ago

VMM/r3: Refactored VMCPU enumeration in preparation that aCpus will be replaced with a pointer array. Removed two raw-mode offset members from the CPUM and CPUMCPU sub-structures. bugref:9217 bugref:9517

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 79.7 KB
Line 
1/* $Id: DBGFR3Flow.cpp 80191 2019-08-08 00:36:57Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Control Flow Graph Interface (CFG).
4 */
5
6/*
7 * Copyright (C) 2016-2019 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_cfg DBGFR3Flow - Control Flow Graph Interface
20 *
21 * The control flow graph interface provides an API to disassemble
22 * guest code providing the result in a control flow graph.
23 */
24
25
26/*********************************************************************************************************************************
27* Header Files *
28*********************************************************************************************************************************/
29#define VBOX_BUGREF_9217_PART_I
30#define LOG_GROUP LOG_GROUP_DBGF
31#include <VBox/vmm/dbgf.h>
32#include "DBGFInternal.h"
33#include <VBox/vmm/mm.h>
34#include <VBox/vmm/uvm.h>
35#include <VBox/vmm/vm.h>
36#include <VBox/err.h>
37#include <VBox/log.h>
38
39#include <iprt/assert.h>
40#include <iprt/thread.h>
41#include <iprt/param.h>
42#include <iprt/list.h>
43#include <iprt/mem.h>
44#include <iprt/sort.h>
45#include <iprt/strcache.h>
46
47
48/*********************************************************************************************************************************
49* Structures and Typedefs *
50*********************************************************************************************************************************/
51
52/**
53 * Internal control flow graph state.
54 */
55typedef struct DBGFFLOWINT
56{
57 /** Reference counter. */
58 uint32_t volatile cRefs;
59 /** Internal reference counter for basic blocks. */
60 uint32_t volatile cRefsBb;
61 /** Flags during creation. */
62 uint32_t fFlags;
63 /** List of all basic blocks. */
64 RTLISTANCHOR LstFlowBb;
65 /** List of identified branch tables. */
66 RTLISTANCHOR LstBranchTbl;
67 /** Number of basic blocks in this control flow graph. */
68 uint32_t cBbs;
69 /** Number of branch tables in this control flow graph. */
70 uint32_t cBranchTbls;
71 /** The lowest addres of a basic block. */
72 DBGFADDRESS AddrLowest;
73 /** The highest address of a basic block. */
74 DBGFADDRESS AddrHighest;
75 /** String cache for disassembled instructions. */
76 RTSTRCACHE hStrCacheInstr;
77} DBGFFLOWINT;
78/** Pointer to an internal control flow graph state. */
79typedef DBGFFLOWINT *PDBGFFLOWINT;
80
81/**
82 * Instruction record
83 */
84typedef struct DBGFFLOWBBINSTR
85{
86 /** Instruction address. */
87 DBGFADDRESS AddrInstr;
88 /** Size of instruction. */
89 uint32_t cbInstr;
90 /** Disassembled instruction string. */
91 const char *pszInstr;
92} DBGFFLOWBBINSTR;
93/** Pointer to an instruction record. */
94typedef DBGFFLOWBBINSTR *PDBGFFLOWBBINSTR;
95
96
97/**
98 * A branch table identified by the graph processor.
99 */
100typedef struct DBGFFLOWBRANCHTBLINT
101{
102 /** Node for the list of branch tables. */
103 RTLISTNODE NdBranchTbl;
104 /** The owning control flow graph. */
105 PDBGFFLOWINT pFlow;
106 /** Reference counter. */
107 uint32_t volatile cRefs;
108 /** The general register index holding the bracnh table base. */
109 uint8_t idxGenRegBase;
110 /** Start address of the branch table. */
111 DBGFADDRESS AddrStart;
112 /** Number of valid entries in the branch table. */
113 uint32_t cSlots;
114 /** The addresses contained in the branch table - variable in size. */
115 DBGFADDRESS aAddresses[1];
116} DBGFFLOWBRANCHTBLINT;
117/** Pointer to a branch table structure. */
118typedef DBGFFLOWBRANCHTBLINT *PDBGFFLOWBRANCHTBLINT;
119
120
121/**
122 * Internal control flow graph basic block state.
123 */
124typedef struct DBGFFLOWBBINT
125{
126 /** Node for the list of all basic blocks. */
127 RTLISTNODE NdFlowBb;
128 /** The control flow graph the basic block belongs to. */
129 PDBGFFLOWINT pFlow;
130 /** Reference counter. */
131 uint32_t volatile cRefs;
132 /** Basic block end type. */
133 DBGFFLOWBBENDTYPE enmEndType;
134 /** Start address of this basic block. */
135 DBGFADDRESS AddrStart;
136 /** End address of this basic block. */
137 DBGFADDRESS AddrEnd;
138 /** Address of the block succeeding.
139 * This is valid for conditional jumps
140 * (the other target is referenced by AddrEnd+1) and
141 * unconditional jumps (not ret, iret, etc.) except
142 * if we can't infer the jump target (jmp *eax for example). */
143 DBGFADDRESS AddrTarget;
144 /** The indirect branch table identified for indirect branches. */
145 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl;
146 /** Last status error code if DBGF_FLOW_BB_F_INCOMPLETE_ERR is set. */
147 int rcError;
148 /** Error message if DBGF_FLOW_BB_F_INCOMPLETE_ERR is set. */
149 char *pszErr;
150 /** Flags for this basic block. */
151 uint32_t fFlags;
152 /** Number of instructions in this basic block. */
153 uint32_t cInstr;
154 /** Maximum number of instruction records for this basic block. */
155 uint32_t cInstrMax;
156 /** Instruction records, variable in size. */
157 DBGFFLOWBBINSTR aInstr[1];
158} DBGFFLOWBBINT;
159/** Pointer to an internal control flow graph basic block state. */
160typedef DBGFFLOWBBINT *PDBGFFLOWBBINT;
161
162
163/**
164 * Control flow graph iterator state.
165 */
166typedef struct DBGFFLOWITINT
167{
168 /** Pointer to the control flow graph (holding a reference). */
169 PDBGFFLOWINT pFlow;
170 /** Next basic block to return. */
171 uint32_t idxBbNext;
172 /** Array of basic blocks sorted by the specified order - variable in size. */
173 PDBGFFLOWBBINT apBb[1];
174} DBGFFLOWITINT;
175/** Pointer to the internal control flow graph iterator state. */
176typedef DBGFFLOWITINT *PDBGFFLOWITINT;
177
178
179/**
180 * Control flow graph branch table iterator state.
181 */
182typedef struct DBGFFLOWBRANCHTBLITINT
183{
184 /** Pointer to the control flow graph (holding a reference). */
185 PDBGFFLOWINT pFlow;
186 /** Next branch table to return. */
187 uint32_t idxTblNext;
188 /** Array of branch table pointers sorted by the specified order - variable in size. */
189 PDBGFFLOWBRANCHTBLINT apBranchTbl[1];
190} DBGFFLOWBRANCHTBLITINT;
191/** Pointer to the internal control flow graph branch table iterator state. */
192typedef DBGFFLOWBRANCHTBLITINT *PDBGFFLOWBRANCHTBLITINT;
193
194
195/*********************************************************************************************************************************
196* Internal Functions *
197*********************************************************************************************************************************/
198
199static uint32_t dbgfR3FlowBbReleaseInt(PDBGFFLOWBBINT pFlowBb, bool fMayDestroyFlow);
200static void dbgfR3FlowBranchTblDestroy(PDBGFFLOWBRANCHTBLINT pFlowBranchTbl);
201
202
203/**
204 * Checks whether both addresses are equal.
205 *
206 * @returns true if both addresses point to the same location, false otherwise.
207 * @param pAddr1 First address.
208 * @param pAddr2 Second address.
209 */
210static bool dbgfR3FlowAddrEqual(PDBGFADDRESS pAddr1, PDBGFADDRESS pAddr2)
211{
212 return pAddr1->Sel == pAddr2->Sel
213 && pAddr1->off == pAddr2->off;
214}
215
216
217/**
218 * Checks whether the first given address is lower than the second one.
219 *
220 * @returns true if both addresses point to the same location, false otherwise.
221 * @param pAddr1 First address.
222 * @param pAddr2 Second address.
223 */
224static bool dbgfR3FlowAddrLower(PDBGFADDRESS pAddr1, PDBGFADDRESS pAddr2)
225{
226 return pAddr1->Sel == pAddr2->Sel
227 && pAddr1->off < pAddr2->off;
228}
229
230
231/**
232 * Checks whether the given basic block and address intersect.
233 *
234 * @returns true if they intersect, false otherwise.
235 * @param pFlowBb The basic block to check.
236 * @param pAddr The address to check for.
237 */
238static bool dbgfR3FlowAddrIntersect(PDBGFFLOWBBINT pFlowBb, PDBGFADDRESS pAddr)
239{
240 return (pFlowBb->AddrStart.Sel == pAddr->Sel)
241 && (pFlowBb->AddrStart.off <= pAddr->off)
242 && (pFlowBb->AddrEnd.off >= pAddr->off);
243}
244
245
246/**
247 * Returns the distance of the two given addresses.
248 *
249 * @returns Distance of the addresses.
250 * @param pAddr1 The first address.
251 * @param pAddr2 The second address.
252 */
253static RTGCUINTPTR dbgfR3FlowAddrGetDistance(PDBGFADDRESS pAddr1, PDBGFADDRESS pAddr2)
254{
255 if (pAddr1->Sel == pAddr2->Sel)
256 {
257 if (pAddr1->off >= pAddr2->off)
258 return pAddr1->off - pAddr2->off;
259 else
260 return pAddr2->off - pAddr1->off;
261 }
262 else
263 AssertFailed();
264
265 return 0;
266}
267
268
269/**
270 * Creates a new basic block.
271 *
272 * @returns Pointer to the basic block on success or NULL if out of memory.
273 * @param pThis The control flow graph.
274 * @param pAddrStart The start of the basic block.
275 * @param fFlowBbFlags Additional flags for this bascic block.
276 * @param cInstrMax Maximum number of instructions this block can hold initially.
277 */
278static PDBGFFLOWBBINT dbgfR3FlowBbCreate(PDBGFFLOWINT pThis, PDBGFADDRESS pAddrStart, uint32_t fFlowBbFlags,
279 uint32_t cInstrMax)
280{
281 PDBGFFLOWBBINT pFlowBb = (PDBGFFLOWBBINT)RTMemAllocZ(RT_UOFFSETOF_DYN(DBGFFLOWBBINT, aInstr[cInstrMax]));
282 if (RT_LIKELY(pFlowBb))
283 {
284 RTListInit(&pFlowBb->NdFlowBb);
285 pFlowBb->cRefs = 1;
286 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_INVALID;
287 pFlowBb->pFlow = pThis;
288 pFlowBb->fFlags = DBGF_FLOW_BB_F_EMPTY | fFlowBbFlags;
289 pFlowBb->AddrStart = *pAddrStart;
290 pFlowBb->AddrEnd = *pAddrStart;
291 pFlowBb->rcError = VINF_SUCCESS;
292 pFlowBb->pszErr = NULL;
293 pFlowBb->cInstr = 0;
294 pFlowBb->cInstrMax = cInstrMax;
295 pFlowBb->pFlowBranchTbl = NULL;
296 ASMAtomicIncU32(&pThis->cRefsBb);
297 }
298
299 return pFlowBb;
300}
301
302
303/**
304 * Creates an empty branch table with the given size.
305 *
306 * @returns Pointer to the empty branch table on success or NULL if out of memory.
307 * @param pThis The control flow graph.
308 * @param pAddrStart The start of the branch table.
309 * @param idxGenRegBase The general register index holding the base address.
310 * @param cSlots Number of slots the table has.
311 */
312static PDBGFFLOWBRANCHTBLINT
313dbgfR3FlowBranchTblCreate(PDBGFFLOWINT pThis, PDBGFADDRESS pAddrStart, uint8_t idxGenRegBase, uint32_t cSlots)
314{
315 PDBGFFLOWBRANCHTBLINT pBranchTbl = (PDBGFFLOWBRANCHTBLINT)RTMemAllocZ(RT_UOFFSETOF_DYN(DBGFFLOWBRANCHTBLINT,
316 aAddresses[cSlots]));
317 if (RT_LIKELY(pBranchTbl))
318 {
319 RTListInit(&pBranchTbl->NdBranchTbl);
320 pBranchTbl->pFlow = pThis;
321 pBranchTbl->idxGenRegBase = idxGenRegBase;
322 pBranchTbl->AddrStart = *pAddrStart;
323 pBranchTbl->cSlots = cSlots;
324 pBranchTbl->cRefs = 1;
325 }
326
327 return pBranchTbl;
328}
329
330
331/**
332 * Destroys a control flow graph.
333 *
334 * @returns nothing.
335 * @param pThis The control flow graph to destroy.
336 */
337static void dbgfR3FlowDestroy(PDBGFFLOWINT pThis)
338{
339 /* Defer destruction if there are still basic blocks referencing us. */
340 PDBGFFLOWBBINT pFlowBb;
341 PDBGFFLOWBBINT pFlowBbNext;
342 RTListForEachSafe(&pThis->LstFlowBb, pFlowBb, pFlowBbNext, DBGFFLOWBBINT, NdFlowBb)
343 {
344 dbgfR3FlowBbReleaseInt(pFlowBb, false /*fMayDestroyFlow*/);
345 }
346
347 Assert(!pThis->cRefs);
348 if (!pThis->cRefsBb)
349 {
350 /* Destroy the branch tables. */
351 PDBGFFLOWBRANCHTBLINT pTbl = NULL;
352 PDBGFFLOWBRANCHTBLINT pTblNext = NULL;
353 RTListForEachSafe(&pThis->LstBranchTbl, pTbl, pTblNext, DBGFFLOWBRANCHTBLINT, NdBranchTbl)
354 {
355 dbgfR3FlowBranchTblDestroy(pTbl);
356 }
357
358 RTStrCacheDestroy(pThis->hStrCacheInstr);
359 RTMemFree(pThis);
360 }
361}
362
363
364/**
365 * Destroys a basic block.
366 *
367 * @returns nothing.
368 * @param pFlowBb The basic block to destroy.
369 * @param fMayDestroyFlow Flag whether the control flow graph container
370 * should be destroyed when there is nothing referencing it.
371 */
372static void dbgfR3FlowBbDestroy(PDBGFFLOWBBINT pFlowBb, bool fMayDestroyFlow)
373{
374 PDBGFFLOWINT pThis = pFlowBb->pFlow;
375
376 RTListNodeRemove(&pFlowBb->NdFlowBb);
377 pThis->cBbs--;
378 for (uint32_t idxInstr = 0; idxInstr < pFlowBb->cInstr; idxInstr++)
379 RTStrCacheRelease(pThis->hStrCacheInstr, pFlowBb->aInstr[idxInstr].pszInstr);
380 uint32_t cRefsBb = ASMAtomicDecU32(&pThis->cRefsBb);
381 RTMemFree(pFlowBb);
382
383 if (!cRefsBb && !pThis->cRefs && fMayDestroyFlow)
384 dbgfR3FlowDestroy(pThis);
385}
386
387
388/**
389 * Destroys a given branch table.
390 *
391 * @returns nothing.
392 * @param pFlowBranchTbl The flow branch table to destroy.
393 */
394static void dbgfR3FlowBranchTblDestroy(PDBGFFLOWBRANCHTBLINT pFlowBranchTbl)
395{
396 RTListNodeRemove(&pFlowBranchTbl->NdBranchTbl);
397 RTMemFree(pFlowBranchTbl);
398}
399
400
401/**
402 * Internal basic block release worker.
403 *
404 * @returns New reference count of the released basic block, on 0
405 * it is destroyed.
406 * @param pFlowBb The basic block to release.
407 * @param fMayDestroyFlow Flag whether the control flow graph container
408 * should be destroyed when there is nothing referencing it.
409 */
410static uint32_t dbgfR3FlowBbReleaseInt(PDBGFFLOWBBINT pFlowBb, bool fMayDestroyFlow)
411{
412 uint32_t cRefs = ASMAtomicDecU32(&pFlowBb->cRefs);
413 AssertMsg(cRefs < _1M, ("%#x %p %d\n", cRefs, pFlowBb, pFlowBb->enmEndType));
414 if (cRefs == 0)
415 dbgfR3FlowBbDestroy(pFlowBb, fMayDestroyFlow);
416 return cRefs;
417}
418
419
420/**
421 * Links the given basic block into the control flow graph.
422 *
423 * @returns nothing.
424 * @param pThis The control flow graph to link into.
425 * @param pFlowBb The basic block to link.
426 */
427DECLINLINE(void) dbgfR3FlowLink(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb)
428{
429 RTListAppend(&pThis->LstFlowBb, &pFlowBb->NdFlowBb);
430 pThis->cBbs++;
431}
432
433
434/**
435 * Links the given branch table into the control flow graph.
436 *
437 * @returns nothing.
438 * @param pThis The control flow graph to link into.
439 * @param pBranchTbl The branch table to link.
440 */
441DECLINLINE(void) dbgfR3FlowBranchTblLink(PDBGFFLOWINT pThis, PDBGFFLOWBRANCHTBLINT pBranchTbl)
442{
443 RTListAppend(&pThis->LstBranchTbl, &pBranchTbl->NdBranchTbl);
444 pThis->cBranchTbls++;
445}
446
447
448/**
449 * Returns the first unpopulated basic block of the given control flow graph.
450 *
451 * @returns The first unpopulated control flow graph or NULL if not found.
452 * @param pThis The control flow graph.
453 */
454DECLINLINE(PDBGFFLOWBBINT) dbgfR3FlowGetUnpopulatedBb(PDBGFFLOWINT pThis)
455{
456 PDBGFFLOWBBINT pFlowBb;
457 RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
458 {
459 if (pFlowBb->fFlags & DBGF_FLOW_BB_F_EMPTY)
460 return pFlowBb;
461 }
462
463 return NULL;
464}
465
466
467/**
468 * Returns the branch table with the given address if it exists.
469 *
470 * @returns Pointer to the branch table record or NULL if not found.
471 * @param pThis The control flow graph.
472 * @param pAddrTbl The branch table address.
473 */
474DECLINLINE(PDBGFFLOWBRANCHTBLINT) dbgfR3FlowBranchTblFindByAddr(PDBGFFLOWINT pThis, PDBGFADDRESS pAddrTbl)
475{
476 PDBGFFLOWBRANCHTBLINT pTbl;
477 RTListForEach(&pThis->LstBranchTbl, pTbl, DBGFFLOWBRANCHTBLINT, NdBranchTbl)
478 {
479 if (dbgfR3FlowAddrEqual(&pTbl->AddrStart, pAddrTbl))
480 return pTbl;
481 }
482
483 return NULL;
484}
485
486
487/**
488 * Sets the given error status for the basic block.
489 *
490 * @returns nothing.
491 * @param pFlowBb The basic block causing the error.
492 * @param rcError The error to set.
493 * @param pszFmt Format string of the error description.
494 * @param ... Arguments for the format string.
495 */
496static void dbgfR3FlowBbSetError(PDBGFFLOWBBINT pFlowBb, int rcError, const char *pszFmt, ...)
497{
498 va_list va;
499 va_start(va, pszFmt);
500
501 Assert(!(pFlowBb->fFlags & DBGF_FLOW_BB_F_INCOMPLETE_ERR));
502 pFlowBb->fFlags |= DBGF_FLOW_BB_F_INCOMPLETE_ERR;
503 pFlowBb->fFlags &= ~DBGF_FLOW_BB_F_EMPTY;
504 pFlowBb->rcError = rcError;
505 pFlowBb->pszErr = RTStrAPrintf2V(pszFmt, va);
506 va_end(va);
507}
508
509
510/**
511 * Checks whether the given control flow graph contains a basic block
512 * with the given start address.
513 *
514 * @returns true if there is a basic block with the start address, false otherwise.
515 * @param pThis The control flow graph.
516 * @param pAddr The address to check for.
517 */
518static bool dbgfR3FlowHasBbWithStartAddr(PDBGFFLOWINT pThis, PDBGFADDRESS pAddr)
519{
520 PDBGFFLOWBBINT pFlowBb;
521 RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
522 {
523 if (dbgfR3FlowAddrEqual(&pFlowBb->AddrStart, pAddr))
524 return true;
525 }
526 return false;
527}
528
529
530/**
531 * Splits a given basic block into two at the given address.
532 *
533 * @returns VBox status code.
534 * @param pThis The control flow graph.
535 * @param pFlowBb The basic block to split.
536 * @param pAddr The address to split at.
537 */
538static int dbgfR3FlowBbSplit(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb, PDBGFADDRESS pAddr)
539{
540 int rc = VINF_SUCCESS;
541 uint32_t idxInstrSplit;
542
543 /* If the block is empty it will get populated later so there is nothing to split,
544 * same if the start address equals. */
545 if ( pFlowBb->fFlags & DBGF_FLOW_BB_F_EMPTY
546 || dbgfR3FlowAddrEqual(&pFlowBb->AddrStart, pAddr))
547 return VINF_SUCCESS;
548
549 /* Find the instruction to split at. */
550 for (idxInstrSplit = 1; idxInstrSplit < pFlowBb->cInstr; idxInstrSplit++)
551 if (dbgfR3FlowAddrEqual(&pFlowBb->aInstr[idxInstrSplit].AddrInstr, pAddr))
552 break;
553
554 Assert(idxInstrSplit > 0);
555
556 /*
557 * Given address might not be on instruction boundary, this is not supported
558 * so far and results in an error.
559 */
560 if (idxInstrSplit < pFlowBb->cInstr)
561 {
562 /* Create new basic block. */
563 uint32_t cInstrNew = pFlowBb->cInstr - idxInstrSplit;
564 PDBGFFLOWBBINT pFlowBbNew = dbgfR3FlowBbCreate(pThis, &pFlowBb->aInstr[idxInstrSplit].AddrInstr,
565 0 /*fFlowBbFlags*/, cInstrNew);
566 if (pFlowBbNew)
567 {
568 /* Move instructions over. */
569 pFlowBbNew->cInstr = cInstrNew;
570 pFlowBbNew->AddrEnd = pFlowBb->AddrEnd;
571 pFlowBbNew->enmEndType = pFlowBb->enmEndType;
572 pFlowBbNew->AddrTarget = pFlowBb->AddrTarget;
573 pFlowBbNew->fFlags = pFlowBb->fFlags & ~DBGF_FLOW_BB_F_ENTRY;
574 pFlowBbNew->pFlowBranchTbl = pFlowBb->pFlowBranchTbl;
575 pFlowBb->pFlowBranchTbl = NULL;
576
577 /* Move any error to the new basic block and clear them in the old basic block. */
578 pFlowBbNew->rcError = pFlowBb->rcError;
579 pFlowBbNew->pszErr = pFlowBb->pszErr;
580 pFlowBb->rcError = VINF_SUCCESS;
581 pFlowBb->pszErr = NULL;
582 pFlowBb->fFlags &= ~DBGF_FLOW_BB_F_INCOMPLETE_ERR;
583
584 memcpy(&pFlowBbNew->aInstr[0], &pFlowBb->aInstr[idxInstrSplit], cInstrNew * sizeof(DBGFFLOWBBINSTR));
585 pFlowBb->cInstr = idxInstrSplit;
586 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND;
587 pFlowBb->AddrEnd = pFlowBb->aInstr[idxInstrSplit-1].AddrInstr;
588 pFlowBb->AddrTarget = pFlowBbNew->AddrStart;
589 DBGFR3AddrAdd(&pFlowBb->AddrEnd, pFlowBb->aInstr[idxInstrSplit-1].cbInstr - 1);
590 RT_BZERO(&pFlowBb->aInstr[idxInstrSplit], cInstrNew * sizeof(DBGFFLOWBBINSTR));
591
592 dbgfR3FlowLink(pThis, pFlowBbNew);
593 }
594 else
595 rc = VERR_NO_MEMORY;
596 }
597 else
598 AssertFailedStmt(rc = VERR_INVALID_STATE); /** @todo Proper status code. */
599
600 return rc;
601}
602
603
604/**
605 * Makes sure there is an successor at the given address splitting already existing
606 * basic blocks if they intersect.
607 *
608 * @returns VBox status code.
609 * @param pThis The control flow graph.
610 * @param pAddrSucc The guest address the new successor should start at.
611 * @param fNewBbFlags Flags for the new basic block.
612 * @param pBranchTbl Branch table candidate for this basic block.
613 */
614static int dbgfR3FlowBbSuccessorAdd(PDBGFFLOWINT pThis, PDBGFADDRESS pAddrSucc,
615 uint32_t fNewBbFlags, PDBGFFLOWBRANCHTBLINT pBranchTbl)
616{
617 PDBGFFLOWBBINT pFlowBb;
618 RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
619 {
620 /*
621 * The basic block must be split if it intersects with the given address
622 * and the start address does not equal the given one.
623 */
624 if (dbgfR3FlowAddrIntersect(pFlowBb, pAddrSucc))
625 return dbgfR3FlowBbSplit(pThis, pFlowBb, pAddrSucc);
626 }
627
628 int rc = VINF_SUCCESS;
629 pFlowBb = dbgfR3FlowBbCreate(pThis, pAddrSucc, fNewBbFlags, 10);
630 if (pFlowBb)
631 {
632 pFlowBb->pFlowBranchTbl = pBranchTbl;
633 dbgfR3FlowLink(pThis, pFlowBb);
634 }
635 else
636 rc = VERR_NO_MEMORY;
637
638 return rc;
639}
640
641
642/**
643 * Returns whether the parameter indicates an indirect branch.
644 *
645 * @returns Flag whether this is an indirect branch.
646 * @param pDisParam The parameter from the disassembler.
647 */
648DECLINLINE(bool) dbgfR3FlowBranchTargetIsIndirect(PDISOPPARAM pDisParam)
649{
650 bool fIndirect = true;
651
652 if ( pDisParam->fUse & (DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32 | DISUSE_IMMEDIATE64)
653 || pDisParam->fUse & (DISUSE_IMMEDIATE8_REL | DISUSE_IMMEDIATE16_REL | DISUSE_IMMEDIATE32_REL | DISUSE_IMMEDIATE64_REL))
654 fIndirect = false;
655
656 return fIndirect;
657}
658
659
660/**
661 * Resolves the direct branch target address if possible from the given instruction address
662 * and instruction parameter.
663 *
664 * @returns VBox status code.
665 * @param pUVM The usermode VM handle.
666 * @param idCpu CPU id for resolving the address.
667 * @param pDisParam The parameter from the disassembler.
668 * @param pAddrInstr The instruction address.
669 * @param cbInstr Size of instruction in bytes.
670 * @param fRelJmp Flag whether this is a reltive jump.
671 * @param pAddrJmpTarget Where to store the address to the jump target on success.
672 */
673static int dbgfR3FlowQueryDirectBranchTarget(PUVM pUVM, VMCPUID idCpu, PDISOPPARAM pDisParam, PDBGFADDRESS pAddrInstr,
674 uint32_t cbInstr, bool fRelJmp, PDBGFADDRESS pAddrJmpTarget)
675{
676 int rc = VINF_SUCCESS;
677
678 Assert(!dbgfR3FlowBranchTargetIsIndirect(pDisParam));
679
680 /* Relative jumps are always from the beginning of the next instruction. */
681 *pAddrJmpTarget = *pAddrInstr;
682 DBGFR3AddrAdd(pAddrJmpTarget, cbInstr);
683
684 if (fRelJmp)
685 {
686 RTGCINTPTR iRel = 0;
687 if (pDisParam->fUse & DISUSE_IMMEDIATE8_REL)
688 iRel = (int8_t)pDisParam->uValue;
689 else if (pDisParam->fUse & DISUSE_IMMEDIATE16_REL)
690 iRel = (int16_t)pDisParam->uValue;
691 else if (pDisParam->fUse & DISUSE_IMMEDIATE32_REL)
692 iRel = (int32_t)pDisParam->uValue;
693 else if (pDisParam->fUse & DISUSE_IMMEDIATE64_REL)
694 iRel = (int64_t)pDisParam->uValue;
695 else
696 AssertFailedStmt(rc = VERR_NOT_SUPPORTED);
697
698 if (iRel < 0)
699 DBGFR3AddrSub(pAddrJmpTarget, -iRel);
700 else
701 DBGFR3AddrAdd(pAddrJmpTarget, iRel);
702 }
703 else
704 {
705 if (pDisParam->fUse & (DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32 | DISUSE_IMMEDIATE64))
706 {
707 if (DBGFADDRESS_IS_FLAT(pAddrInstr))
708 DBGFR3AddrFromFlat(pUVM, pAddrJmpTarget, pDisParam->uValue);
709 else
710 DBGFR3AddrFromSelOff(pUVM, idCpu, pAddrJmpTarget, pAddrInstr->Sel, pDisParam->uValue);
711 }
712 else
713 AssertFailedStmt(rc = VERR_INVALID_STATE);
714 }
715
716 return rc;
717}
718
719
720/**
721 * Returns the CPU mode based on the given assembler flags.
722 *
723 * @returns CPU mode.
724 * @param pUVM The user mode VM handle.
725 * @param idCpu CPU id for disassembling.
726 * @param fFlagsDisasm The flags used for disassembling.
727 */
728static CPUMMODE dbgfR3FlowGetDisasCpuMode(PUVM pUVM, VMCPUID idCpu, uint32_t fFlagsDisasm)
729{
730 CPUMMODE enmMode = CPUMMODE_INVALID;
731 uint32_t fDisasMode = fFlagsDisasm & DBGF_DISAS_FLAGS_MODE_MASK;
732 if (fDisasMode == DBGF_DISAS_FLAGS_DEFAULT_MODE)
733 enmMode = DBGFR3CpuGetMode(pUVM, idCpu);
734 else if ( fDisasMode == DBGF_DISAS_FLAGS_16BIT_MODE
735 || fDisasMode == DBGF_DISAS_FLAGS_16BIT_REAL_MODE)
736 enmMode = CPUMMODE_REAL;
737 else if (fDisasMode == DBGF_DISAS_FLAGS_32BIT_MODE)
738 enmMode = CPUMMODE_PROTECTED;
739 else if (fDisasMode == DBGF_DISAS_FLAGS_64BIT_MODE)
740 enmMode = CPUMMODE_LONG;
741 else
742 AssertFailed();
743
744 return enmMode;
745}
746
747
748/**
749 * Searches backwards in the given basic block starting the given instruction index for
750 * a mov instruction with the given register as the target where the constant looks like
751 * a pointer.
752 *
753 * @returns Flag whether a candidate was found.
754 * @param pFlowBb The basic block containing the indirect branch.
755 * @param idxRegTgt The general register the mov targets.
756 * @param cbPtr The pointer size to look for.
757 * @param pUVM The user mode VM handle.
758 * @param idCpu CPU id for disassembling.
759 * @param fFlagsDisasm The flags to use for disassembling.
760 * @param pidxInstrStart The instruction index to start searching for on input,
761 * The last instruction evaluated on output.
762 * @param pAddrDest Where to store the candidate address on success.
763 */
764static bool dbgfR3FlowSearchMovWithConstantPtrSizeBackwards(PDBGFFLOWBBINT pFlowBb, uint8_t idxRegTgt, uint32_t cbPtr,
765 PUVM pUVM, VMCPUID idCpu, uint32_t fFlagsDisasm,
766 uint32_t *pidxInstrStart, PDBGFADDRESS pAddrDest)
767{
768 bool fFound = false;
769 uint32_t idxInstrCur = *pidxInstrStart;
770 uint32_t cInstrCheck = idxInstrCur + 1;
771
772 for (;;)
773 {
774 /** @todo Avoid to disassemble again. */
775 PDBGFFLOWBBINSTR pInstr = &pFlowBb->aInstr[idxInstrCur];
776 DBGFDISSTATE DisState;
777 char szOutput[_4K];
778
779 int rc = dbgfR3DisasInstrStateEx(pUVM, idCpu, &pInstr->AddrInstr, fFlagsDisasm,
780 &szOutput[0], sizeof(szOutput), &DisState);
781 if (RT_SUCCESS(rc))
782 {
783 if ( DisState.pCurInstr->uOpcode == OP_MOV
784 && (DisState.Param1.fUse & (DISUSE_REG_GEN16 | DISUSE_REG_GEN32 | DISUSE_REG_GEN64))
785 && DisState.Param1.Base.idxGenReg == idxRegTgt
786 /*&& DisState.Param1.cb == cbPtr*/
787 && DisState.Param2.cb == cbPtr
788 && (DisState.Param2.fUse & (DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32 | DISUSE_IMMEDIATE64)))
789 {
790 /* Found possible candidate. */
791 fFound = true;
792 if (DBGFADDRESS_IS_FLAT(&pInstr->AddrInstr))
793 DBGFR3AddrFromFlat(pUVM, pAddrDest, DisState.Param2.uValue);
794 else
795 DBGFR3AddrFromSelOff(pUVM, idCpu, pAddrDest, pInstr->AddrInstr.Sel, DisState.Param2.uValue);
796 break;
797 }
798 }
799 else
800 break;
801
802 cInstrCheck--;
803 if (!cInstrCheck)
804 break;
805
806 idxInstrCur--;
807 }
808
809 *pidxInstrStart = idxInstrCur;
810 return fFound;
811}
812
813
814/**
815 * Verifies the given branch table candidate and adds it to the control flow graph on success.
816 *
817 * @returns VBox status code.
818 * @param pThis The flow control graph.
819 * @param pFlowBb The basic block causing the indirect branch.
820 * @param pAddrBranchTbl Address of the branch table location.
821 * @param idxGenRegBase The general register holding the base address.
822 * @param cbPtr Guest pointer size.
823 * @param pUVM The user mode VM handle.
824 * @param idCpu CPU id for disassembling.
825 *
826 * @todo Handle branch tables greater than 4KB (lazy coder).
827 */
828static int dbgfR3FlowBranchTblVerifyAdd(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb, PDBGFADDRESS pAddrBranchTbl,
829 uint8_t idxGenRegBase, uint32_t cbPtr, PUVM pUVM, VMCPUID idCpu)
830{
831 int rc = VINF_SUCCESS;
832 PDBGFFLOWBRANCHTBLINT pBranchTbl = dbgfR3FlowBranchTblFindByAddr(pThis, pAddrBranchTbl);
833
834 if (!pBranchTbl)
835 {
836 uint32_t cSlots = 0;
837 uint8_t abBuf[_4K];
838
839 rc = DBGFR3MemRead(pUVM, idCpu, pAddrBranchTbl, &abBuf[0], sizeof(abBuf));
840 if (RT_SUCCESS(rc))
841 {
842 uint8_t *pbBuf = &abBuf[0];
843 while (pbBuf < &abBuf[0] + sizeof(abBuf))
844 {
845 DBGFADDRESS AddrDest;
846 RTGCUINTPTR GCPtr = cbPtr == sizeof(uint64_t)
847 ? *(uint64_t *)pbBuf
848 : cbPtr == sizeof(uint32_t)
849 ? *(uint32_t *)pbBuf
850 : *(uint16_t *)pbBuf;
851 pbBuf += cbPtr;
852
853 if (DBGFADDRESS_IS_FLAT(pAddrBranchTbl))
854 DBGFR3AddrFromFlat(pUVM, &AddrDest, GCPtr);
855 else
856 DBGFR3AddrFromSelOff(pUVM, idCpu, &AddrDest, pAddrBranchTbl->Sel, GCPtr);
857
858 if (dbgfR3FlowAddrGetDistance(&AddrDest, &pFlowBb->AddrEnd) > _512K)
859 break;
860
861 cSlots++;
862 }
863
864 /* If there are any slots use it. */
865 if (cSlots)
866 {
867 pBranchTbl = dbgfR3FlowBranchTblCreate(pThis, pAddrBranchTbl, idxGenRegBase, cSlots);
868 if (pBranchTbl)
869 {
870 /* Get the addresses. */
871 for (unsigned i = 0; i < cSlots && RT_SUCCESS(rc); i++)
872 {
873 RTGCUINTPTR GCPtr = cbPtr == sizeof(uint64_t)
874 ? *(uint64_t *)&abBuf[i * cbPtr]
875 : cbPtr == sizeof(uint32_t)
876 ? *(uint32_t *)&abBuf[i * cbPtr]
877 : *(uint16_t *)&abBuf[i * cbPtr];
878
879 if (DBGFADDRESS_IS_FLAT(pAddrBranchTbl))
880 DBGFR3AddrFromFlat(pUVM, &pBranchTbl->aAddresses[i], GCPtr);
881 else
882 DBGFR3AddrFromSelOff(pUVM, idCpu, &pBranchTbl->aAddresses[i],
883 pAddrBranchTbl->Sel, GCPtr);
884 rc = dbgfR3FlowBbSuccessorAdd(pThis, &pBranchTbl->aAddresses[i], DBGF_FLOW_BB_F_BRANCH_TABLE,
885 pBranchTbl);
886 }
887 dbgfR3FlowBranchTblLink(pThis, pBranchTbl);
888 }
889 else
890 rc = VERR_NO_MEMORY;
891 }
892 }
893 }
894
895 if (pBranchTbl)
896 pFlowBb->pFlowBranchTbl = pBranchTbl;
897
898 return rc;
899}
900
901
902/**
903 * Checks whether the location for the branch target candidate contains a valid code address.
904 *
905 * @returns VBox status code.
906 * @param pThis The flow control graph.
907 * @param pFlowBb The basic block causing the indirect branch.
908 * @param pAddrBranchTgt Address of the branch target location.
909 * @param idxGenRegBase The general register holding the address of the location.
910 * @param cbPtr Guest pointer size.
911 * @param pUVM The user mode VM handle.
912 * @param idCpu CPU id for disassembling.
913 * @param fBranchTbl Flag whether this is a possible branch table containing multiple
914 * targets.
915 */
916static int dbgfR3FlowCheckBranchTargetLocation(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb, PDBGFADDRESS pAddrBranchTgt,
917 uint8_t idxGenRegBase, uint32_t cbPtr, PUVM pUVM, VMCPUID idCpu, bool fBranchTbl)
918{
919 int rc = VINF_SUCCESS;
920
921 if (!fBranchTbl)
922 {
923 union { uint16_t u16Val; uint32_t u32Val; uint64_t u64Val; } uVal;
924 rc = DBGFR3MemRead(pUVM, idCpu, pAddrBranchTgt, &uVal, cbPtr);
925 if (RT_SUCCESS(rc))
926 {
927 DBGFADDRESS AddrTgt;
928 RTGCUINTPTR GCPtr = cbPtr == sizeof(uint64_t)
929 ? uVal.u64Val
930 : cbPtr == sizeof(uint32_t)
931 ? uVal.u32Val
932 : uVal.u16Val;
933 if (DBGFADDRESS_IS_FLAT(pAddrBranchTgt))
934 DBGFR3AddrFromFlat(pUVM, &AddrTgt, GCPtr);
935 else
936 DBGFR3AddrFromSelOff(pUVM, idCpu, &AddrTgt, pAddrBranchTgt->Sel, GCPtr);
937
938 if (dbgfR3FlowAddrGetDistance(&AddrTgt, &pFlowBb->AddrEnd) <= _128K)
939 {
940 /* Finish the basic block. */
941 pFlowBb->AddrTarget = AddrTgt;
942 rc = dbgfR3FlowBbSuccessorAdd(pThis, &AddrTgt,
943 (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
944 pFlowBb->pFlowBranchTbl);
945 }
946 else
947 rc = VERR_NOT_FOUND;
948 }
949 }
950 else
951 rc = dbgfR3FlowBranchTblVerifyAdd(pThis, pFlowBb, pAddrBranchTgt,
952 idxGenRegBase, cbPtr, pUVM, idCpu);
953
954 return rc;
955}
956
957
958/**
959 * Tries to resolve the indirect branch.
960 *
961 * @returns VBox status code.
962 * @param pThis The flow control graph.
963 * @param pFlowBb The basic block causing the indirect branch.
964 * @param pUVM The user mode VM handle.
965 * @param idCpu CPU id for disassembling.
966 * @param pDisParam The parameter from the disassembler.
967 * @param fFlagsDisasm Flags for the disassembler.
968 */
969static int dbgfR3FlowTryResolveIndirectBranch(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb, PUVM pUVM,
970 VMCPUID idCpu, PDISOPPARAM pDisParam, uint32_t fFlagsDisasm)
971{
972 Assert(dbgfR3FlowBranchTargetIsIndirect(pDisParam));
973
974 uint32_t cbPtr = 0;
975 CPUMMODE enmMode = dbgfR3FlowGetDisasCpuMode(pUVM, idCpu, fFlagsDisasm);
976
977 switch (enmMode)
978 {
979 case CPUMMODE_REAL:
980 cbPtr = sizeof(uint16_t);
981 break;
982 case CPUMMODE_PROTECTED:
983 cbPtr = sizeof(uint32_t);
984 break;
985 case CPUMMODE_LONG:
986 cbPtr = sizeof(uint64_t);
987 break;
988 default:
989 AssertMsgFailed(("Invalid CPU mode %u\n", enmMode));
990 }
991
992 if (pDisParam->fUse & DISUSE_BASE)
993 {
994 uint8_t idxRegBase = pDisParam->Base.idxGenReg;
995
996 /* Check that the used register size and the pointer size match. */
997 if ( ((pDisParam->fUse & DISUSE_REG_GEN16) && cbPtr == sizeof(uint16_t))
998 || ((pDisParam->fUse & DISUSE_REG_GEN32) && cbPtr == sizeof(uint32_t))
999 || ((pDisParam->fUse & DISUSE_REG_GEN64) && cbPtr == sizeof(uint64_t)))
1000 {
1001 /*
1002 * Search all instructions backwards until a move to the used general register
1003 * is detected with a constant using the pointer size.
1004 */
1005 uint32_t idxInstrStart = pFlowBb->cInstr - 1 - 1; /* Don't look at the branch. */
1006 bool fCandidateFound = false;
1007 bool fBranchTbl = RT_BOOL(pDisParam->fUse & DISUSE_INDEX);
1008 DBGFADDRESS AddrBranchTgt;
1009 do
1010 {
1011 fCandidateFound = dbgfR3FlowSearchMovWithConstantPtrSizeBackwards(pFlowBb, idxRegBase, cbPtr,
1012 pUVM, idCpu, fFlagsDisasm,
1013 &idxInstrStart, &AddrBranchTgt);
1014 if (fCandidateFound)
1015 {
1016 /* Check that the address is not too far away from the instruction address. */
1017 RTGCUINTPTR offPtr = dbgfR3FlowAddrGetDistance(&AddrBranchTgt, &pFlowBb->AddrEnd);
1018 if (offPtr <= 20 * _1M)
1019 {
1020 /* Read the content at the address and check that it is near this basic block too. */
1021 int rc = dbgfR3FlowCheckBranchTargetLocation(pThis, pFlowBb, &AddrBranchTgt, idxRegBase,
1022 cbPtr, pUVM, idCpu, fBranchTbl);
1023 if (RT_SUCCESS(rc))
1024 break;
1025 fCandidateFound = false;
1026 }
1027
1028 if (idxInstrStart > 0)
1029 idxInstrStart--;
1030 }
1031 } while (idxInstrStart > 0 && !fCandidateFound);
1032 }
1033 else
1034 dbgfR3FlowBbSetError(pFlowBb, VERR_INVALID_STATE,
1035 "The base register size and selected pointer size do not match (fUse=%#x cbPtr=%u)",
1036 pDisParam->fUse, cbPtr);
1037 }
1038
1039 return VINF_SUCCESS;
1040}
1041
1042
1043/**
1044 * Tries to resolve the indirect branch.
1045 *
1046 * @returns VBox status code.
1047 * @param pThis The flow control graph.
1048 * @param pFlowBb The basic block causing the indirect branch.
1049 * @param pUVM The user mode VM handle.
1050 * @param idCpu CPU id for disassembling.
1051 * @param pDisParam The parameter from the disassembler.
1052 * @param fFlagsDisasm Flags for the disassembler.
1053 */
1054static int dbgfR3FlowBbCheckBranchTblCandidate(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb, PUVM pUVM,
1055 VMCPUID idCpu, PDISOPPARAM pDisParam, uint32_t fFlagsDisasm)
1056{
1057 int rc = VINF_SUCCESS;
1058
1059 Assert(pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE && pFlowBb->pFlowBranchTbl);
1060
1061 uint32_t cbPtr = 0;
1062 CPUMMODE enmMode = dbgfR3FlowGetDisasCpuMode(pUVM, idCpu, fFlagsDisasm);
1063
1064 switch (enmMode)
1065 {
1066 case CPUMMODE_REAL:
1067 cbPtr = sizeof(uint16_t);
1068 break;
1069 case CPUMMODE_PROTECTED:
1070 cbPtr = sizeof(uint32_t);
1071 break;
1072 case CPUMMODE_LONG:
1073 cbPtr = sizeof(uint64_t);
1074 break;
1075 default:
1076 AssertMsgFailed(("Invalid CPU mode %u\n", enmMode));
1077 }
1078
1079 if (pDisParam->fUse & DISUSE_BASE)
1080 {
1081 uint8_t idxRegBase = pDisParam->Base.idxGenReg;
1082
1083 /* Check that the used register size and the pointer size match. */
1084 if ( ((pDisParam->fUse & DISUSE_REG_GEN16) && cbPtr == sizeof(uint16_t))
1085 || ((pDisParam->fUse & DISUSE_REG_GEN32) && cbPtr == sizeof(uint32_t))
1086 || ((pDisParam->fUse & DISUSE_REG_GEN64) && cbPtr == sizeof(uint64_t)))
1087 {
1088 if (idxRegBase != pFlowBb->pFlowBranchTbl->idxGenRegBase)
1089 {
1090 /* Try to find the new branch table. */
1091 pFlowBb->pFlowBranchTbl = NULL;
1092 rc = dbgfR3FlowTryResolveIndirectBranch(pThis, pFlowBb, pUVM, idCpu, pDisParam, fFlagsDisasm);
1093 }
1094 /** @todo else check that the base register is not modified in this basic block. */
1095 }
1096 else
1097 dbgfR3FlowBbSetError(pFlowBb, VERR_INVALID_STATE,
1098 "The base register size and selected pointer size do not match (fUse=%#x cbPtr=%u)",
1099 pDisParam->fUse, cbPtr);
1100 }
1101 else
1102 dbgfR3FlowBbSetError(pFlowBb, VERR_INVALID_STATE,
1103 "The instruction does not use a register");
1104
1105 return rc;
1106}
1107
1108
1109/**
1110 * Processes and fills one basic block.
1111 *
1112 * @returns VBox status code.
1113 * @param pUVM The user mode VM handle.
1114 * @param idCpu CPU id for disassembling.
1115 * @param pThis The control flow graph to populate.
1116 * @param pFlowBb The basic block to fill.
1117 * @param cbDisasmMax The maximum amount to disassemble.
1118 * @param fFlags Combination of DBGF_DISAS_FLAGS_*.
1119 */
1120static int dbgfR3FlowBbProcess(PUVM pUVM, VMCPUID idCpu, PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb,
1121 uint32_t cbDisasmMax, uint32_t fFlags)
1122{
1123 int rc = VINF_SUCCESS;
1124 uint32_t cbDisasmLeft = cbDisasmMax ? cbDisasmMax : UINT32_MAX;
1125 DBGFADDRESS AddrDisasm = pFlowBb->AddrEnd;
1126
1127 Assert(pFlowBb->fFlags & DBGF_FLOW_BB_F_EMPTY);
1128
1129 /*
1130 * Disassemble instruction by instruction until we get a conditional or
1131 * unconditional jump or some sort of return.
1132 */
1133 while ( cbDisasmLeft
1134 && RT_SUCCESS(rc))
1135 {
1136 DBGFDISSTATE DisState;
1137 char szOutput[_4K];
1138
1139 /*
1140 * Before disassembling we have to check whether the address belongs
1141 * to another basic block and stop here.
1142 */
1143 if ( !(pFlowBb->fFlags & DBGF_FLOW_BB_F_EMPTY)
1144 && dbgfR3FlowHasBbWithStartAddr(pThis, &AddrDisasm))
1145 {
1146 pFlowBb->AddrTarget = AddrDisasm;
1147 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND;
1148 break;
1149 }
1150
1151 pFlowBb->fFlags &= ~DBGF_FLOW_BB_F_EMPTY;
1152
1153 rc = dbgfR3DisasInstrStateEx(pUVM, idCpu, &AddrDisasm, fFlags,
1154 &szOutput[0], sizeof(szOutput), &DisState);
1155 if (RT_SUCCESS(rc))
1156 {
1157 cbDisasmLeft -= DisState.cbInstr;
1158
1159 if (pFlowBb->cInstr == pFlowBb->cInstrMax)
1160 {
1161 /* Reallocate. */
1162 RTListNodeRemove(&pFlowBb->NdFlowBb);
1163 PDBGFFLOWBBINT pFlowBbNew = (PDBGFFLOWBBINT)RTMemRealloc(pFlowBb,
1164 RT_UOFFSETOF_DYN(DBGFFLOWBBINT, aInstr[pFlowBb->cInstrMax + 10]));
1165 if (pFlowBbNew)
1166 {
1167 pFlowBbNew->cInstrMax += 10;
1168 pFlowBb = pFlowBbNew;
1169 }
1170 else
1171 rc = VERR_NO_MEMORY;
1172 RTListAppend(&pThis->LstFlowBb, &pFlowBb->NdFlowBb);
1173 }
1174
1175 if (RT_SUCCESS(rc))
1176 {
1177 PDBGFFLOWBBINSTR pInstr = &pFlowBb->aInstr[pFlowBb->cInstr];
1178
1179 pInstr->AddrInstr = AddrDisasm;
1180 pInstr->cbInstr = DisState.cbInstr;
1181 pInstr->pszInstr = RTStrCacheEnter(pThis->hStrCacheInstr, &szOutput[0]);
1182 pFlowBb->cInstr++;
1183
1184 pFlowBb->AddrEnd = AddrDisasm;
1185 DBGFR3AddrAdd(&pFlowBb->AddrEnd, pInstr->cbInstr - 1);
1186 DBGFR3AddrAdd(&AddrDisasm, pInstr->cbInstr);
1187
1188 /*
1189 * Check control flow instructions and create new basic blocks
1190 * marking the current one as complete.
1191 */
1192 if (DisState.pCurInstr->fOpType & DISOPTYPE_CONTROLFLOW)
1193 {
1194 uint16_t uOpc = DisState.pCurInstr->uOpcode;
1195
1196 if ( uOpc == OP_RETN || uOpc == OP_RETF || uOpc == OP_IRET
1197 || uOpc == OP_SYSEXIT || uOpc == OP_SYSRET)
1198 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_EXIT;
1199 else if (uOpc == OP_JMP)
1200 {
1201 Assert(DisState.pCurInstr->fOpType & DISOPTYPE_UNCOND_CONTROLFLOW);
1202
1203 if (dbgfR3FlowBranchTargetIsIndirect(&DisState.Param1))
1204 {
1205 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP;
1206
1207 if (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE)
1208 {
1209 Assert(pThis->fFlags & DBGF_FLOW_CREATE_F_TRY_RESOLVE_INDIRECT_BRANCHES);
1210
1211 /*
1212 * This basic block was already discovered by parsing a jump table and
1213 * there should be a candidate for the branch table. Check whether it uses the
1214 * same branch table.
1215 */
1216 rc = dbgfR3FlowBbCheckBranchTblCandidate(pThis, pFlowBb, pUVM, idCpu,
1217 &DisState.Param1, fFlags);
1218 }
1219 else
1220 {
1221 if (pThis->fFlags & DBGF_FLOW_CREATE_F_TRY_RESOLVE_INDIRECT_BRANCHES)
1222 rc = dbgfR3FlowTryResolveIndirectBranch(pThis, pFlowBb, pUVM, idCpu,
1223 &DisState.Param1, fFlags);
1224 else
1225 dbgfR3FlowBbSetError(pFlowBb, VERR_NOT_SUPPORTED,
1226 "Detected indirect branch and resolving it not being enabled");
1227 }
1228 }
1229 else
1230 {
1231 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND_JMP;
1232
1233 /* Create one new basic block with the jump target address. */
1234 rc = dbgfR3FlowQueryDirectBranchTarget(pUVM, idCpu, &DisState.Param1, &pInstr->AddrInstr, pInstr->cbInstr,
1235 RT_BOOL(DisState.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW),
1236 &pFlowBb->AddrTarget);
1237 if (RT_SUCCESS(rc))
1238 rc = dbgfR3FlowBbSuccessorAdd(pThis, &pFlowBb->AddrTarget,
1239 (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
1240 pFlowBb->pFlowBranchTbl);
1241 }
1242 }
1243 else if (uOpc != OP_CALL)
1244 {
1245 Assert(DisState.pCurInstr->fOpType & DISOPTYPE_COND_CONTROLFLOW);
1246 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_COND;
1247
1248 /*
1249 * Create two new basic blocks, one with the jump target address
1250 * and one starting after the current instruction.
1251 */
1252 rc = dbgfR3FlowBbSuccessorAdd(pThis, &AddrDisasm,
1253 (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
1254 pFlowBb->pFlowBranchTbl);
1255 if (RT_SUCCESS(rc))
1256 {
1257 rc = dbgfR3FlowQueryDirectBranchTarget(pUVM, idCpu, &DisState.Param1, &pInstr->AddrInstr, pInstr->cbInstr,
1258 RT_BOOL(DisState.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW),
1259 &pFlowBb->AddrTarget);
1260 if (RT_SUCCESS(rc))
1261 rc = dbgfR3FlowBbSuccessorAdd(pThis, &pFlowBb->AddrTarget,
1262 (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
1263 pFlowBb->pFlowBranchTbl);
1264 }
1265 }
1266
1267 if (RT_FAILURE(rc))
1268 dbgfR3FlowBbSetError(pFlowBb, rc, "Adding successor blocks failed with %Rrc", rc);
1269
1270 /* Quit disassembling. */
1271 if ( uOpc != OP_CALL
1272 || RT_FAILURE(rc))
1273 break;
1274 }
1275 }
1276 else
1277 dbgfR3FlowBbSetError(pFlowBb, rc, "Increasing basic block failed with %Rrc", rc);
1278 }
1279 else
1280 dbgfR3FlowBbSetError(pFlowBb, rc, "Disassembling the instruction failed with %Rrc", rc);
1281 }
1282
1283 return VINF_SUCCESS;
1284}
1285
1286/**
1287 * Populate all empty basic blocks.
1288 *
1289 * @returns VBox status code.
1290 * @param pUVM The user mode VM handle.
1291 * @param idCpu CPU id for disassembling.
1292 * @param pThis The control flow graph to populate.
1293 * @param pAddrStart The start address to disassemble at.
1294 * @param cbDisasmMax The maximum amount to disassemble.
1295 * @param fFlags Combination of DBGF_DISAS_FLAGS_*.
1296 */
1297static int dbgfR3FlowPopulate(PUVM pUVM, VMCPUID idCpu, PDBGFFLOWINT pThis, PDBGFADDRESS pAddrStart,
1298 uint32_t cbDisasmMax, uint32_t fFlags)
1299{
1300 int rc = VINF_SUCCESS;
1301 PDBGFFLOWBBINT pFlowBb = dbgfR3FlowGetUnpopulatedBb(pThis);
1302 DBGFADDRESS AddrEnd = *pAddrStart;
1303 DBGFR3AddrAdd(&AddrEnd, cbDisasmMax);
1304
1305 while (VALID_PTR(pFlowBb))
1306 {
1307 rc = dbgfR3FlowBbProcess(pUVM, idCpu, pThis, pFlowBb, cbDisasmMax, fFlags);
1308 if (RT_FAILURE(rc))
1309 break;
1310
1311 pFlowBb = dbgfR3FlowGetUnpopulatedBb(pThis);
1312 }
1313
1314 return rc;
1315}
1316
1317/**
1318 * Creates a new control flow graph from the given start address.
1319 *
1320 * @returns VBox status code.
1321 * @param pUVM The user mode VM handle.
1322 * @param idCpu CPU id for disassembling.
1323 * @param pAddressStart Where to start creating the control flow graph.
1324 * @param cbDisasmMax Limit the amount of bytes to disassemble, 0 for no limit.
1325 * @param fFlagsFlow Combination of DBGF_FLOW_CREATE_F_* to control the creation of the flow graph.
1326 * @param fFlagsDisasm Combination of DBGF_DISAS_FLAGS_* controlling the style of the disassembled
1327 * instructions.
1328 * @param phFlow Where to store the handle to the control flow graph on success.
1329 */
1330VMMR3DECL(int) DBGFR3FlowCreate(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddressStart, uint32_t cbDisasmMax,
1331 uint32_t fFlagsFlow, uint32_t fFlagsDisasm, PDBGFFLOW phFlow)
1332{
1333 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1334 PVM pVM = pUVM->pVM;
1335 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1336 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
1337 AssertPtrReturn(pAddressStart, VERR_INVALID_POINTER);
1338 AssertReturn(!(fFlagsDisasm & ~DBGF_DISAS_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
1339 AssertReturn((fFlagsDisasm & DBGF_DISAS_FLAGS_MODE_MASK) <= DBGF_DISAS_FLAGS_64BIT_MODE, VERR_INVALID_PARAMETER);
1340
1341 /* Create the control flow graph container. */
1342 int rc = VINF_SUCCESS;
1343 PDBGFFLOWINT pThis = (PDBGFFLOWINT)RTMemAllocZ(sizeof(DBGFFLOWINT));
1344 if (RT_LIKELY(pThis))
1345 {
1346 rc = RTStrCacheCreate(&pThis->hStrCacheInstr, "DBGFFLOW");
1347 if (RT_SUCCESS(rc))
1348 {
1349 pThis->cRefs = 1;
1350 pThis->cRefsBb = 0;
1351 pThis->cBbs = 0;
1352 pThis->cBranchTbls = 0;
1353 pThis->fFlags = fFlagsFlow;
1354 RTListInit(&pThis->LstFlowBb);
1355 RTListInit(&pThis->LstBranchTbl);
1356 /* Create the entry basic block and start the work. */
1357
1358 PDBGFFLOWBBINT pFlowBb = dbgfR3FlowBbCreate(pThis, pAddressStart, DBGF_FLOW_BB_F_ENTRY, 10);
1359 if (RT_LIKELY(pFlowBb))
1360 {
1361 dbgfR3FlowLink(pThis, pFlowBb);
1362 rc = dbgfR3FlowPopulate(pUVM, idCpu, pThis, pAddressStart, cbDisasmMax, fFlagsDisasm);
1363 if (RT_SUCCESS(rc))
1364 {
1365 *phFlow = pThis;
1366 return VINF_SUCCESS;
1367 }
1368 }
1369 else
1370 rc = VERR_NO_MEMORY;
1371 }
1372
1373 ASMAtomicDecU32(&pThis->cRefs);
1374 dbgfR3FlowDestroy(pThis);
1375 }
1376 else
1377 rc = VERR_NO_MEMORY;
1378
1379 return rc;
1380}
1381
1382
1383/**
1384 * Retains the control flow graph handle.
1385 *
1386 * @returns Current reference count.
1387 * @param hFlow The control flow graph handle to retain.
1388 */
1389VMMR3DECL(uint32_t) DBGFR3FlowRetain(DBGFFLOW hFlow)
1390{
1391 PDBGFFLOWINT pThis = hFlow;
1392 AssertPtrReturn(pThis, UINT32_MAX);
1393
1394 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1395 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1396 return cRefs;
1397}
1398
1399
1400/**
1401 * Releases the control flow graph handle.
1402 *
1403 * @returns Current reference count, on 0 the control flow graph will be destroyed.
1404 * @param hFlow The control flow graph handle to release.
1405 */
1406VMMR3DECL(uint32_t) DBGFR3FlowRelease(DBGFFLOW hFlow)
1407{
1408 PDBGFFLOWINT pThis = hFlow;
1409 if (!pThis)
1410 return 0;
1411 AssertPtrReturn(pThis, UINT32_MAX);
1412
1413 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1414 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1415 if (cRefs == 0)
1416 dbgfR3FlowDestroy(pThis);
1417 return cRefs;
1418}
1419
1420
1421/**
1422 * Queries the basic block denoting the entry point into the control flow graph.
1423 *
1424 * @returns VBox status code.
1425 * @param hFlow The control flow graph handle.
1426 * @param phFlowBb Where to store the basic block handle on success.
1427 */
1428VMMR3DECL(int) DBGFR3FlowQueryStartBb(DBGFFLOW hFlow, PDBGFFLOWBB phFlowBb)
1429{
1430 PDBGFFLOWINT pThis = hFlow;
1431 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1432
1433 PDBGFFLOWBBINT pFlowBb;
1434 RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
1435 {
1436 if (pFlowBb->fFlags & DBGF_FLOW_BB_F_ENTRY)
1437 {
1438 *phFlowBb = pFlowBb;
1439 return VINF_SUCCESS;
1440 }
1441 }
1442
1443 AssertFailed(); /* Should never get here. */
1444 return VERR_INTERNAL_ERROR;
1445}
1446
1447
1448/**
1449 * Queries a basic block in the given control flow graph which covers the given
1450 * address.
1451 *
1452 * @returns VBox status code.
1453 * @retval VERR_NOT_FOUND if there is no basic block intersecting with the address.
1454 * @param hFlow The control flow graph handle.
1455 * @param pAddr The address to look for.
1456 * @param phFlowBb Where to store the basic block handle on success.
1457 */
1458VMMR3DECL(int) DBGFR3FlowQueryBbByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBB phFlowBb)
1459{
1460 PDBGFFLOWINT pThis = hFlow;
1461 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1462 AssertPtrReturn(pAddr, VERR_INVALID_POINTER);
1463 AssertPtrReturn(phFlowBb, VERR_INVALID_POINTER);
1464
1465 PDBGFFLOWBBINT pFlowBb;
1466 RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
1467 {
1468 if (dbgfR3FlowAddrIntersect(pFlowBb, pAddr))
1469 {
1470 DBGFR3FlowBbRetain(pFlowBb);
1471 *phFlowBb = pFlowBb;
1472 return VINF_SUCCESS;
1473 }
1474 }
1475
1476 return VERR_NOT_FOUND;
1477}
1478
1479
1480/**
1481 * Queries a branch table in the given control flow graph by the given address.
1482 *
1483 * @returns VBox status code.
1484 * @retval VERR_NOT_FOUND if there is no branch table with the given address.
1485 * @param hFlow The control flow graph handle.
1486 * @param pAddr The address of the branch table.
1487 * @param phFlowBranchTbl Where to store the handle to branch table on success.
1488 *
1489 * @note Call DBGFR3FlowBranchTblRelease() when the handle is not required anymore.
1490 */
1491VMMR3DECL(int) DBGFR3FlowQueryBranchTblByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBRANCHTBL phFlowBranchTbl)
1492{
1493 PDBGFFLOWINT pThis = hFlow;
1494 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1495 AssertPtrReturn(pAddr, VERR_INVALID_POINTER);
1496 AssertPtrReturn(phFlowBranchTbl, VERR_INVALID_POINTER);
1497
1498 PDBGFFLOWBRANCHTBLINT pBranchTbl = dbgfR3FlowBranchTblFindByAddr(pThis, pAddr);
1499 if (pBranchTbl)
1500 {
1501 DBGFR3FlowBranchTblRetain(pBranchTbl);
1502 *phFlowBranchTbl = pBranchTbl;
1503 return VINF_SUCCESS;
1504 }
1505
1506 return VERR_NOT_FOUND;
1507}
1508
1509
1510/**
1511 * Returns the number of basic blcoks inside the control flow graph.
1512 *
1513 * @returns Number of basic blocks.
1514 * @param hFlow The control flow graph handle.
1515 */
1516VMMR3DECL(uint32_t) DBGFR3FlowGetBbCount(DBGFFLOW hFlow)
1517{
1518 PDBGFFLOWINT pThis = hFlow;
1519 AssertPtrReturn(pThis, 0);
1520
1521 return pThis->cBbs;
1522}
1523
1524
1525/**
1526 * Returns the number of branch tables inside the control flow graph.
1527 *
1528 * @returns Number of basic blocks.
1529 * @param hFlow The control flow graph handle.
1530 */
1531VMMR3DECL(uint32_t) DBGFR3FlowGetBranchTblCount(DBGFFLOW hFlow)
1532{
1533 PDBGFFLOWINT pThis = hFlow;
1534 AssertPtrReturn(pThis, 0);
1535
1536 return pThis->cBranchTbls;
1537}
1538
1539
1540/**
1541 * Retains the basic block handle.
1542 *
1543 * @returns Current reference count.
1544 * @param hFlowBb The basic block handle to retain.
1545 */
1546VMMR3DECL(uint32_t) DBGFR3FlowBbRetain(DBGFFLOWBB hFlowBb)
1547{
1548 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1549 AssertPtrReturn(pFlowBb, UINT32_MAX);
1550
1551 uint32_t cRefs = ASMAtomicIncU32(&pFlowBb->cRefs);
1552 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p %d\n", cRefs, pFlowBb, pFlowBb->enmEndType));
1553 return cRefs;
1554}
1555
1556
1557/**
1558 * Releases the basic block handle.
1559 *
1560 * @returns Current reference count, on 0 the basic block will be destroyed.
1561 * @param hFlowBb The basic block handle to release.
1562 */
1563VMMR3DECL(uint32_t) DBGFR3FlowBbRelease(DBGFFLOWBB hFlowBb)
1564{
1565 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1566 if (!pFlowBb)
1567 return 0;
1568
1569 return dbgfR3FlowBbReleaseInt(pFlowBb, true /* fMayDestroyFlow */);
1570}
1571
1572
1573/**
1574 * Returns the start address of the basic block.
1575 *
1576 * @returns Pointer to DBGF adress containing the start address of the basic block.
1577 * @param hFlowBb The basic block handle.
1578 * @param pAddrStart Where to store the start address of the basic block.
1579 */
1580VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetStartAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrStart)
1581{
1582 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1583 AssertPtrReturn(pFlowBb, NULL);
1584 AssertPtrReturn(pAddrStart, NULL);
1585
1586 *pAddrStart = pFlowBb->AddrStart;
1587 return pAddrStart;
1588}
1589
1590
1591/**
1592 * Returns the end address of the basic block (inclusive).
1593 *
1594 * @returns Pointer to DBGF adress containing the end address of the basic block.
1595 * @param hFlowBb The basic block handle.
1596 * @param pAddrEnd Where to store the end address of the basic block.
1597 */
1598VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetEndAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrEnd)
1599{
1600 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1601 AssertPtrReturn(pFlowBb, NULL);
1602 AssertPtrReturn(pAddrEnd, NULL);
1603
1604 *pAddrEnd = pFlowBb->AddrEnd;
1605 return pAddrEnd;
1606}
1607
1608
1609/**
1610 * Returns the address the last instruction in the basic block branches to.
1611 *
1612 * @returns Pointer to DBGF adress containing the branch address of the basic block.
1613 * @param hFlowBb The basic block handle.
1614 * @param pAddrTarget Where to store the branch address of the basic block.
1615 *
1616 * @note This is only valid for unconditional or conditional branches and will assert
1617 * for every other basic block type.
1618 * @note For indirect unconditional branches using a branch table this will return the start address
1619 * of the branch table.
1620 */
1621VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetBranchAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrTarget)
1622{
1623 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1624 AssertPtrReturn(pFlowBb, NULL);
1625 AssertPtrReturn(pAddrTarget, NULL);
1626 AssertReturn( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_JMP
1627 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_COND
1628 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP,
1629 NULL);
1630
1631 if ( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP
1632 && pFlowBb->pFlowBranchTbl)
1633 *pAddrTarget = pFlowBb->pFlowBranchTbl->AddrStart;
1634 else
1635 *pAddrTarget = pFlowBb->AddrTarget;
1636 return pAddrTarget;
1637}
1638
1639
1640/**
1641 * Returns the address of the next block following this one in the instruction stream.
1642 * (usually end address + 1).
1643 *
1644 * @returns Pointer to DBGF adress containing the following address of the basic block.
1645 * @param hFlowBb The basic block handle.
1646 * @param pAddrFollow Where to store the following address of the basic block.
1647 *
1648 * @note This is only valid for conditional branches and if the last instruction in the
1649 * given basic block doesn't change the control flow but the blocks were split
1650 * because the successor is referenced by multiple other blocks as an entry point.
1651 */
1652VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetFollowingAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrFollow)
1653{
1654 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1655 AssertPtrReturn(pFlowBb, NULL);
1656 AssertPtrReturn(pAddrFollow, NULL);
1657 AssertReturn( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND
1658 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_COND,
1659 NULL);
1660
1661 *pAddrFollow = pFlowBb->AddrEnd;
1662 DBGFR3AddrAdd(pAddrFollow, 1);
1663 return pAddrFollow;
1664}
1665
1666
1667/**
1668 * Returns the type of the last instruction in the basic block.
1669 *
1670 * @returns Last instruction type.
1671 * @param hFlowBb The basic block handle.
1672 */
1673VMMR3DECL(DBGFFLOWBBENDTYPE) DBGFR3FlowBbGetType(DBGFFLOWBB hFlowBb)
1674{
1675 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1676 AssertPtrReturn(pFlowBb, DBGFFLOWBBENDTYPE_INVALID);
1677
1678 return pFlowBb->enmEndType;
1679}
1680
1681
1682/**
1683 * Get the number of instructions contained in the basic block.
1684 *
1685 * @returns Number of instructions in the basic block.
1686 * @param hFlowBb The basic block handle.
1687 */
1688VMMR3DECL(uint32_t) DBGFR3FlowBbGetInstrCount(DBGFFLOWBB hFlowBb)
1689{
1690 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1691 AssertPtrReturn(pFlowBb, 0);
1692
1693 return pFlowBb->cInstr;
1694}
1695
1696
1697/**
1698 * Get flags for the given basic block.
1699 *
1700 * @returns Combination of DBGF_FLOW_BB_F_*
1701 * @param hFlowBb The basic block handle.
1702 */
1703VMMR3DECL(uint32_t) DBGFR3FlowBbGetFlags(DBGFFLOWBB hFlowBb)
1704{
1705 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1706 AssertPtrReturn(pFlowBb, 0);
1707
1708 return pFlowBb->fFlags;
1709}
1710
1711
1712/**
1713 * Queries the branch table used if the given basic block ends with an indirect branch
1714 * and has a branch table referenced.
1715 *
1716 * @returns VBox status code.
1717 * @param hFlowBb The basic block handle.
1718 * @param phBranchTbl Where to store the branch table handle on success.
1719 *
1720 * @note Release the branch table reference with DBGFR3FlowBranchTblRelease() when not required
1721 * anymore.
1722 */
1723VMMR3DECL(int) DBGFR3FlowBbQueryBranchTbl(DBGFFLOWBB hFlowBb, PDBGFFLOWBRANCHTBL phBranchTbl)
1724{
1725 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1726 AssertPtrReturn(pFlowBb, VERR_INVALID_HANDLE);
1727 AssertReturn(pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP, VERR_INVALID_STATE);
1728 AssertPtrReturn(pFlowBb->pFlowBranchTbl, VERR_INVALID_STATE);
1729 AssertPtrReturn(phBranchTbl, VERR_INVALID_POINTER);
1730
1731 DBGFR3FlowBranchTblRetain(pFlowBb->pFlowBranchTbl);
1732 *phBranchTbl = pFlowBb->pFlowBranchTbl;
1733 return VINF_SUCCESS;
1734}
1735
1736
1737/**
1738 * Returns the error status and message if the given basic block has an error.
1739 *
1740 * @returns VBox status code of the error for the basic block.
1741 * @param hFlowBb The basic block handle.
1742 * @param ppszErr Where to store the pointer to the error message - optional.
1743 */
1744VMMR3DECL(int) DBGFR3FlowBbQueryError(DBGFFLOWBB hFlowBb, const char **ppszErr)
1745{
1746 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1747 AssertPtrReturn(pFlowBb, VERR_INVALID_HANDLE);
1748
1749 if (ppszErr)
1750 *ppszErr = pFlowBb->pszErr;
1751
1752 return pFlowBb->rcError;
1753}
1754
1755
1756/**
1757 * Store the disassembled instruction as a string in the given output buffer.
1758 *
1759 * @returns VBox status code.
1760 * @param hFlowBb The basic block handle.
1761 * @param idxInstr The instruction to query.
1762 * @param pAddrInstr Where to store the guest instruction address on success, optional.
1763 * @param pcbInstr Where to store the instruction size on success, optional.
1764 * @param ppszInstr Where to store the pointer to the disassembled instruction string, optional.
1765 */
1766VMMR3DECL(int) DBGFR3FlowBbQueryInstr(DBGFFLOWBB hFlowBb, uint32_t idxInstr, PDBGFADDRESS pAddrInstr,
1767 uint32_t *pcbInstr, const char **ppszInstr)
1768{
1769 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1770 AssertPtrReturn(pFlowBb, VERR_INVALID_POINTER);
1771 AssertReturn(idxInstr < pFlowBb->cInstr, VERR_INVALID_PARAMETER);
1772
1773 if (pAddrInstr)
1774 *pAddrInstr = pFlowBb->aInstr[idxInstr].AddrInstr;
1775 if (pcbInstr)
1776 *pcbInstr = pFlowBb->aInstr[idxInstr].cbInstr;
1777 if (ppszInstr)
1778 *ppszInstr = pFlowBb->aInstr[idxInstr].pszInstr;
1779
1780 return VINF_SUCCESS;
1781}
1782
1783
1784/**
1785 * Queries the successors of the basic block.
1786 *
1787 * @returns VBox status code.
1788 * @param hFlowBb The basic block handle.
1789 * @param phFlowBbFollow Where to store the handle to the basic block following
1790 * this one (optional).
1791 * @param phFlowBbTarget Where to store the handle to the basic block being the
1792 * branch target for this one (optional).
1793 */
1794VMMR3DECL(int) DBGFR3FlowBbQuerySuccessors(DBGFFLOWBB hFlowBb, PDBGFFLOWBB phFlowBbFollow, PDBGFFLOWBB phFlowBbTarget)
1795{
1796 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1797 AssertPtrReturn(pFlowBb, VERR_INVALID_POINTER);
1798
1799 if ( phFlowBbFollow
1800 && ( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND
1801 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_COND))
1802 {
1803 DBGFADDRESS AddrStart = pFlowBb->AddrEnd;
1804 DBGFR3AddrAdd(&AddrStart, 1);
1805 int rc = DBGFR3FlowQueryBbByAddress(pFlowBb->pFlow, &AddrStart, phFlowBbFollow);
1806 AssertRC(rc);
1807 }
1808
1809 if ( phFlowBbTarget
1810 && ( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_JMP
1811 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_COND))
1812 {
1813 int rc = DBGFR3FlowQueryBbByAddress(pFlowBb->pFlow, &pFlowBb->AddrTarget, phFlowBbTarget);
1814 AssertRC(rc);
1815 }
1816
1817 return VINF_SUCCESS;
1818}
1819
1820
1821/**
1822 * Returns the number of basic blocks referencing this basic block as a target.
1823 *
1824 * @returns Number of other basic blocks referencing this one.
1825 * @param hFlowBb The basic block handle.
1826 *
1827 * @note If the given basic block references itself (loop, etc.) this will be counted as well.
1828 */
1829VMMR3DECL(uint32_t) DBGFR3FlowBbGetRefBbCount(DBGFFLOWBB hFlowBb)
1830{
1831 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1832 AssertPtrReturn(pFlowBb, 0);
1833
1834 uint32_t cRefsBb = 0;
1835 PDBGFFLOWBBINT pFlowBbCur;
1836 RTListForEach(&pFlowBb->pFlow->LstFlowBb, pFlowBbCur, DBGFFLOWBBINT, NdFlowBb)
1837 {
1838 if (pFlowBbCur->fFlags & DBGF_FLOW_BB_F_INCOMPLETE_ERR)
1839 continue;
1840
1841 if ( pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_UNCOND
1842 || pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_COND)
1843 {
1844 DBGFADDRESS AddrStart = pFlowBb->AddrEnd;
1845 DBGFR3AddrAdd(&AddrStart, 1);
1846 if (dbgfR3FlowAddrEqual(&pFlowBbCur->AddrStart, &AddrStart))
1847 cRefsBb++;
1848 }
1849
1850 if ( ( pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_JMP
1851 || pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_COND)
1852 && dbgfR3FlowAddrEqual(&pFlowBbCur->AddrStart, &pFlowBb->AddrTarget))
1853 cRefsBb++;
1854 }
1855 return cRefsBb;
1856}
1857
1858
1859/**
1860 * Returns the basic block handles referencing the given basic block.
1861 *
1862 * @returns VBox status code.
1863 * @retval VERR_BUFFER_OVERFLOW if the array can't hold all the basic blocks.
1864 * @param hFlowBb The basic block handle.
1865 * @param paFlowBbRef Pointer to the array containing the referencing basic block handles on success.
1866 * @param cRef Number of entries in the given array.
1867 */
1868VMMR3DECL(int) DBGFR3FlowBbGetRefBb(DBGFFLOWBB hFlowBb, PDBGFFLOWBB paFlowBbRef, uint32_t cRef)
1869{
1870 RT_NOREF3(hFlowBb, paFlowBbRef, cRef);
1871 return VERR_NOT_IMPLEMENTED;
1872}
1873
1874
1875/**
1876 * Retains a reference for the given control flow graph branch table.
1877 *
1878 * @returns new reference count.
1879 * @param hFlowBranchTbl The branch table handle.
1880 */
1881VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRetain(DBGFFLOWBRANCHTBL hFlowBranchTbl)
1882{
1883 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
1884 AssertPtrReturn(pFlowBranchTbl, UINT32_MAX);
1885
1886 uint32_t cRefs = ASMAtomicIncU32(&pFlowBranchTbl->cRefs);
1887 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pFlowBranchTbl));
1888 return cRefs;
1889}
1890
1891
1892/**
1893 * Releases a given branch table handle.
1894 *
1895 * @returns the new reference count of the given branch table, on 0 it is destroyed.
1896 * @param hFlowBranchTbl The branch table handle.
1897 */
1898VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRelease(DBGFFLOWBRANCHTBL hFlowBranchTbl)
1899{
1900 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
1901 if (!pFlowBranchTbl)
1902 return 0;
1903 AssertPtrReturn(pFlowBranchTbl, UINT32_MAX);
1904
1905 uint32_t cRefs = ASMAtomicDecU32(&pFlowBranchTbl->cRefs);
1906 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pFlowBranchTbl));
1907 if (cRefs == 0)
1908 dbgfR3FlowBranchTblDestroy(pFlowBranchTbl);
1909 return cRefs;
1910}
1911
1912
1913/**
1914 * Return the number of slots the branch table has.
1915 *
1916 * @returns Number of slots in the branch table.
1917 * @param hFlowBranchTbl The branch table handle.
1918 */
1919VMMR3DECL(uint32_t) DBGFR3FlowBranchTblGetSlots(DBGFFLOWBRANCHTBL hFlowBranchTbl)
1920{
1921 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
1922 AssertPtrReturn(pFlowBranchTbl, 0);
1923
1924 return pFlowBranchTbl->cSlots;
1925}
1926
1927
1928/**
1929 * Returns the start address of the branch table in the guest.
1930 *
1931 * @returns Pointer to start address of the branch table (pAddrStart).
1932 * @param hFlowBranchTbl The branch table handle.
1933 * @param pAddrStart Where to store the branch table address.
1934 */
1935VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetStartAddress(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS pAddrStart)
1936{
1937 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
1938 AssertPtrReturn(pFlowBranchTbl, NULL);
1939 AssertPtrReturn(pAddrStart, NULL);
1940
1941 *pAddrStart = pFlowBranchTbl->AddrStart;
1942 return pAddrStart;
1943}
1944
1945
1946/**
1947 * Returns one address in the branch table at the given slot index.
1948 *
1949 * @return Pointer to the address at the given slot in the given branch table.
1950 * @param hFlowBranchTbl The branch table handle.
1951 * @param idxSlot The slot the address should be returned from.
1952 * @param pAddrSlot Where to store the address.
1953 */
1954VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetAddrAtSlot(DBGFFLOWBRANCHTBL hFlowBranchTbl, uint32_t idxSlot, PDBGFADDRESS pAddrSlot)
1955{
1956 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
1957 AssertPtrReturn(pFlowBranchTbl, NULL);
1958 AssertPtrReturn(pAddrSlot, NULL);
1959 AssertReturn(idxSlot < pFlowBranchTbl->cSlots, NULL);
1960
1961 *pAddrSlot = pFlowBranchTbl->aAddresses[idxSlot];
1962 return pAddrSlot;
1963}
1964
1965
1966/**
1967 * Query all addresses contained in the given branch table.
1968 *
1969 * @returns VBox status code.
1970 * @retval VERR_BUFFER_OVERFLOW if there is not enough space in the array to hold all addresses.
1971 * @param hFlowBranchTbl The branch table handle.
1972 * @param paAddrs Where to store the addresses on success.
1973 * @param cAddrs Number of entries the array can hold.
1974 */
1975VMMR3DECL(int) DBGFR3FlowBranchTblQueryAddresses(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS paAddrs, uint32_t cAddrs)
1976{
1977 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
1978 AssertPtrReturn(pFlowBranchTbl, VERR_INVALID_HANDLE);
1979 AssertPtrReturn(paAddrs, VERR_INVALID_POINTER);
1980 AssertReturn(cAddrs > 0, VERR_INVALID_PARAMETER);
1981
1982 if (cAddrs < pFlowBranchTbl->cSlots)
1983 return VERR_BUFFER_OVERFLOW;
1984
1985 memcpy(paAddrs, &pFlowBranchTbl->aAddresses[0], pFlowBranchTbl->cSlots * sizeof(DBGFADDRESS));
1986 return VINF_SUCCESS;
1987}
1988
1989
1990/**
1991 * @callback_method_impl{FNRTSORTCMP}
1992 */
1993static DECLCALLBACK(int) dbgfR3FlowItSortCmp(void const *pvElement1, void const *pvElement2, void *pvUser)
1994{
1995 PDBGFFLOWITORDER penmOrder = (PDBGFFLOWITORDER)pvUser;
1996 PDBGFFLOWBBINT pFlowBb1 = *(PDBGFFLOWBBINT *)pvElement1;
1997 PDBGFFLOWBBINT pFlowBb2 = *(PDBGFFLOWBBINT *)pvElement2;
1998
1999 if (dbgfR3FlowAddrEqual(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
2000 return 0;
2001
2002 if (*penmOrder == DBGFFLOWITORDER_BY_ADDR_LOWEST_FIRST)
2003 {
2004 if (dbgfR3FlowAddrLower(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
2005 return -1;
2006 else
2007 return 1;
2008 }
2009 else
2010 {
2011 if (dbgfR3FlowAddrLower(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
2012 return 1;
2013 else
2014 return -1;
2015 }
2016}
2017
2018
2019/**
2020 * Creates a new iterator for the given control flow graph.
2021 *
2022 * @returns VBox status code.
2023 * @param hFlow The control flow graph handle.
2024 * @param enmOrder The order in which the basic blocks are enumerated.
2025 * @param phFlowIt Where to store the handle to the iterator on success.
2026 */
2027VMMR3DECL(int) DBGFR3FlowItCreate(DBGFFLOW hFlow, DBGFFLOWITORDER enmOrder, PDBGFFLOWIT phFlowIt)
2028{
2029 int rc = VINF_SUCCESS;
2030 PDBGFFLOWINT pFlow = hFlow;
2031 AssertPtrReturn(pFlow, VERR_INVALID_POINTER);
2032 AssertPtrReturn(phFlowIt, VERR_INVALID_POINTER);
2033 AssertReturn(enmOrder > DBGFFLOWITORDER_INVALID && enmOrder < DBGFFLOWITORDER_BREADTH_FIRST,
2034 VERR_INVALID_PARAMETER);
2035 AssertReturn(enmOrder < DBGFFLOWITORDER_DEPTH_FRIST, VERR_NOT_IMPLEMENTED); /** @todo */
2036
2037 PDBGFFLOWITINT pIt = (PDBGFFLOWITINT)RTMemAllocZ(RT_UOFFSETOF_DYN(DBGFFLOWITINT, apBb[pFlow->cBbs]));
2038 if (RT_LIKELY(pIt))
2039 {
2040 DBGFR3FlowRetain(hFlow);
2041 pIt->pFlow = pFlow;
2042 pIt->idxBbNext = 0;
2043 /* Fill the list and then sort. */
2044 uint32_t idxBb = 0;
2045 PDBGFFLOWBBINT pFlowBb;
2046 RTListForEach(&pFlow->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
2047 {
2048 DBGFR3FlowBbRetain(pFlowBb);
2049 pIt->apBb[idxBb++] = pFlowBb;
2050 }
2051
2052 /* Sort the blocks by address. */
2053 RTSortShell(&pIt->apBb[0], pFlow->cBbs, sizeof(PDBGFFLOWBBINT), dbgfR3FlowItSortCmp, &enmOrder);
2054
2055 *phFlowIt = pIt;
2056 }
2057 else
2058 rc = VERR_NO_MEMORY;
2059
2060 return rc;
2061}
2062
2063
2064/**
2065 * Destroys a given control flow graph iterator.
2066 *
2067 * @returns nothing.
2068 * @param hFlowIt The control flow graph iterator handle.
2069 */
2070VMMR3DECL(void) DBGFR3FlowItDestroy(DBGFFLOWIT hFlowIt)
2071{
2072 PDBGFFLOWITINT pIt = hFlowIt;
2073 AssertPtrReturnVoid(pIt);
2074
2075 for (unsigned i = 0; i < pIt->pFlow->cBbs; i++)
2076 DBGFR3FlowBbRelease(pIt->apBb[i]);
2077
2078 DBGFR3FlowRelease(pIt->pFlow);
2079 RTMemFree(pIt);
2080}
2081
2082
2083/**
2084 * Returns the next basic block in the iterator or NULL if there is no
2085 * basic block left.
2086 *
2087 * @returns Handle to the next basic block in the iterator or NULL if the end
2088 * was reached.
2089 * @param hFlowIt The iterator handle.
2090 *
2091 * @note If a valid handle is returned it must be release with DBGFR3FlowBbRelease()
2092 * when not required anymore.
2093 */
2094VMMR3DECL(DBGFFLOWBB) DBGFR3FlowItNext(DBGFFLOWIT hFlowIt)
2095{
2096 PDBGFFLOWITINT pIt = hFlowIt;
2097 AssertPtrReturn(pIt, NULL);
2098
2099 PDBGFFLOWBBINT pFlowBb = NULL;
2100 if (pIt->idxBbNext < pIt->pFlow->cBbs)
2101 {
2102 pFlowBb = pIt->apBb[pIt->idxBbNext++];
2103 DBGFR3FlowBbRetain(pFlowBb);
2104 }
2105
2106 return pFlowBb;
2107}
2108
2109
2110/**
2111 * Resets the given iterator to the beginning.
2112 *
2113 * @returns VBox status code.
2114 * @param hFlowIt The iterator handle.
2115 */
2116VMMR3DECL(int) DBGFR3FlowItReset(DBGFFLOWIT hFlowIt)
2117{
2118 PDBGFFLOWITINT pIt = hFlowIt;
2119 AssertPtrReturn(pIt, VERR_INVALID_HANDLE);
2120
2121 pIt->idxBbNext = 0;
2122 return VINF_SUCCESS;
2123}
2124
2125
2126/**
2127 * @callback_method_impl{FNRTSORTCMP}
2128 */
2129static DECLCALLBACK(int) dbgfR3FlowBranchTblItSortCmp(void const *pvElement1, void const *pvElement2, void *pvUser)
2130{
2131 PDBGFFLOWITORDER penmOrder = (PDBGFFLOWITORDER)pvUser;
2132 PDBGFFLOWBRANCHTBLINT pTbl1 = *(PDBGFFLOWBRANCHTBLINT *)pvElement1;
2133 PDBGFFLOWBRANCHTBLINT pTbl2 = *(PDBGFFLOWBRANCHTBLINT *)pvElement2;
2134
2135 if (dbgfR3FlowAddrEqual(&pTbl1->AddrStart, &pTbl2->AddrStart))
2136 return 0;
2137
2138 if (*penmOrder == DBGFFLOWITORDER_BY_ADDR_LOWEST_FIRST)
2139 {
2140 if (dbgfR3FlowAddrLower(&pTbl1->AddrStart, &pTbl2->AddrStart))
2141 return -1;
2142 else
2143 return 1;
2144 }
2145 else
2146 {
2147 if (dbgfR3FlowAddrLower(&pTbl1->AddrStart, &pTbl2->AddrStart))
2148 return 1;
2149 else
2150 return -1;
2151 }
2152}
2153
2154
2155/**
2156 * Creates a new branch table iterator for the given control flow graph.
2157 *
2158 * @returns VBox status code.
2159 * @param hFlow The control flow graph handle.
2160 * @param enmOrder The order in which the basic blocks are enumerated.
2161 * @param phFlowBranchTblIt Where to store the handle to the iterator on success.
2162 */
2163VMMR3DECL(int) DBGFR3FlowBranchTblItCreate(DBGFFLOW hFlow, DBGFFLOWITORDER enmOrder,
2164 PDBGFFLOWBRANCHTBLIT phFlowBranchTblIt)
2165{
2166 int rc = VINF_SUCCESS;
2167 PDBGFFLOWINT pFlow = hFlow;
2168 AssertPtrReturn(pFlow, VERR_INVALID_POINTER);
2169 AssertPtrReturn(phFlowBranchTblIt, VERR_INVALID_POINTER);
2170 AssertReturn(enmOrder > DBGFFLOWITORDER_INVALID && enmOrder < DBGFFLOWITORDER_BREADTH_FIRST,
2171 VERR_INVALID_PARAMETER);
2172 AssertReturn(enmOrder < DBGFFLOWITORDER_DEPTH_FRIST, VERR_NOT_SUPPORTED);
2173
2174 PDBGFFLOWBRANCHTBLITINT pIt = (PDBGFFLOWBRANCHTBLITINT)RTMemAllocZ(RT_UOFFSETOF_DYN(DBGFFLOWBRANCHTBLITINT,
2175 apBranchTbl[pFlow->cBranchTbls]));
2176 if (RT_LIKELY(pIt))
2177 {
2178 DBGFR3FlowRetain(hFlow);
2179 pIt->pFlow = pFlow;
2180 pIt->idxTblNext = 0;
2181 /* Fill the list and then sort. */
2182 uint32_t idxTbl = 0;
2183 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl;
2184 RTListForEach(&pFlow->LstBranchTbl, pFlowBranchTbl, DBGFFLOWBRANCHTBLINT, NdBranchTbl)
2185 {
2186 DBGFR3FlowBranchTblRetain(pFlowBranchTbl);
2187 pIt->apBranchTbl[idxTbl++] = pFlowBranchTbl;
2188 }
2189
2190 /* Sort the blocks by address. */
2191 RTSortShell(&pIt->apBranchTbl[0], pFlow->cBranchTbls, sizeof(PDBGFFLOWBRANCHTBLINT), dbgfR3FlowBranchTblItSortCmp, &enmOrder);
2192
2193 *phFlowBranchTblIt = pIt;
2194 }
2195 else
2196 rc = VERR_NO_MEMORY;
2197
2198 return rc;
2199}
2200
2201
2202/**
2203 * Destroys a given control flow graph branch table iterator.
2204 *
2205 * @returns nothing.
2206 * @param hFlowBranchTblIt The control flow graph branch table iterator handle.
2207 */
2208VMMR3DECL(void) DBGFR3FlowBranchTblItDestroy(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt)
2209{
2210 PDBGFFLOWBRANCHTBLITINT pIt = hFlowBranchTblIt;
2211 AssertPtrReturnVoid(pIt);
2212
2213 for (unsigned i = 0; i < pIt->pFlow->cBranchTbls; i++)
2214 DBGFR3FlowBranchTblRelease(pIt->apBranchTbl[i]);
2215
2216 DBGFR3FlowRelease(pIt->pFlow);
2217 RTMemFree(pIt);
2218}
2219
2220
2221/**
2222 * Returns the next branch table in the iterator or NULL if there is no
2223 * branch table left.
2224 *
2225 * @returns Handle to the next basic block in the iterator or NULL if the end
2226 * was reached.
2227 * @param hFlowBranchTblIt The iterator handle.
2228 *
2229 * @note If a valid handle is returned it must be release with DBGFR3FlowBranchTblRelease()
2230 * when not required anymore.
2231 */
2232VMMR3DECL(DBGFFLOWBRANCHTBL) DBGFR3FlowBranchTblItNext(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt)
2233{
2234 PDBGFFLOWBRANCHTBLITINT pIt = hFlowBranchTblIt;
2235 AssertPtrReturn(pIt, NULL);
2236
2237 PDBGFFLOWBRANCHTBLINT pTbl = NULL;
2238 if (pIt->idxTblNext < pIt->pFlow->cBranchTbls)
2239 {
2240 pTbl = pIt->apBranchTbl[pIt->idxTblNext++];
2241 DBGFR3FlowBranchTblRetain(pTbl);
2242 }
2243
2244 return pTbl;
2245}
2246
2247
2248/**
2249 * Resets the given iterator to the beginning.
2250 *
2251 * @returns VBox status code.
2252 * @param hFlowBranchTblIt The iterator handle.
2253 */
2254VMMR3DECL(int) DBGFR3FlowBranchTblItReset(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt)
2255{
2256 PDBGFFLOWBRANCHTBLITINT pIt = hFlowBranchTblIt;
2257 AssertPtrReturn(pIt, VERR_INVALID_HANDLE);
2258
2259 pIt->idxTblNext = 0;
2260 return VINF_SUCCESS;
2261}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette