VirtualBox

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

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

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

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

© 2023 Oracle
ContactPrivacy policyTerms of Use