VirtualBox

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

Last change on this file since 72358 was 69221, checked in by vboxsync, 7 years ago

VMM: scm cleanups

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