VirtualBox

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

Last change on this file since 84044 was 82968, checked in by vboxsync, 4 years ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use