VirtualBox

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

Last change on this file since 102828 was 101539, checked in by vboxsync, 14 months ago

DIS,VMM,DBGC,IPRT,++: Some disassembler tweaks and TB disassembly work. bugref:10371 bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 82.9 KB
Line 
1/* $Id: DBGFR3Flow.cpp 101539 2023-10-22 02:43:09Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Control Flow Graph Interface (CFG).
4 */
5
6/*
7 * Copyright (C) 2016-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/** @page pg_dbgf_cfg DBGFR3Flow - Control Flow Graph Interface
30 *
31 * The control flow graph interface provides an API to disassemble
32 * guest code providing the result in a control flow graph.
33 */
34
35
36/*********************************************************************************************************************************
37* Header Files *
38*********************************************************************************************************************************/
39#define LOG_GROUP LOG_GROUP_DBGF
40#include <VBox/vmm/dbgf.h>
41#include "DBGFInternal.h"
42#include <VBox/vmm/mm.h>
43#include <VBox/vmm/uvm.h>
44#include <VBox/vmm/vm.h>
45#include <VBox/err.h>
46#include <VBox/log.h>
47
48#include <iprt/assert.h>
49#include <iprt/thread.h>
50#include <iprt/param.h>
51#include <iprt/list.h>
52#include <iprt/mem.h>
53#include <iprt/sort.h>
54#include <iprt/strcache.h>
55
56
57/*********************************************************************************************************************************
58* Structures and Typedefs *
59*********************************************************************************************************************************/
60
61/**
62 * Internal control flow graph state.
63 */
64typedef struct DBGFFLOWINT
65{
66 /** Reference counter. */
67 uint32_t volatile cRefs;
68 /** Internal reference counter for basic blocks. */
69 uint32_t volatile cRefsBb;
70 /** Flags during creation. */
71 uint32_t fFlags;
72 /** List of all basic blocks. */
73 RTLISTANCHOR LstFlowBb;
74 /** List of identified branch tables. */
75 RTLISTANCHOR LstBranchTbl;
76 /** Number of basic blocks in this control flow graph. */
77 uint32_t cBbs;
78 /** Number of branch tables in this control flow graph. */
79 uint32_t cBranchTbls;
80 /** Number of call instructions in this control flow graph. */
81 uint32_t cCallInsns;
82 /** The lowest addres of a basic block. */
83 DBGFADDRESS AddrLowest;
84 /** The highest address of a basic block. */
85 DBGFADDRESS AddrHighest;
86 /** String cache for disassembled instructions. */
87 RTSTRCACHE hStrCacheInstr;
88} DBGFFLOWINT;
89/** Pointer to an internal control flow graph state. */
90typedef DBGFFLOWINT *PDBGFFLOWINT;
91
92/**
93 * Instruction record
94 */
95typedef struct DBGFFLOWBBINSTR
96{
97 /** Instruction address. */
98 DBGFADDRESS AddrInstr;
99 /** Size of instruction. */
100 uint32_t cbInstr;
101 /** Disassembled instruction string. */
102 const char *pszInstr;
103} DBGFFLOWBBINSTR;
104/** Pointer to an instruction record. */
105typedef DBGFFLOWBBINSTR *PDBGFFLOWBBINSTR;
106
107
108/**
109 * A branch table identified by the graph processor.
110 */
111typedef struct DBGFFLOWBRANCHTBLINT
112{
113 /** Node for the list of branch tables. */
114 RTLISTNODE NdBranchTbl;
115 /** The owning control flow graph. */
116 PDBGFFLOWINT pFlow;
117 /** Reference counter. */
118 uint32_t volatile cRefs;
119 /** The general register index holding the bracnh table base. */
120 uint8_t idxGenRegBase;
121 /** Start address of the branch table. */
122 DBGFADDRESS AddrStart;
123 /** Number of valid entries in the branch table. */
124 uint32_t cSlots;
125 /** The addresses contained in the branch table - variable in size. */
126 DBGFADDRESS aAddresses[1];
127} DBGFFLOWBRANCHTBLINT;
128/** Pointer to a branch table structure. */
129typedef DBGFFLOWBRANCHTBLINT *PDBGFFLOWBRANCHTBLINT;
130
131
132/**
133 * Internal control flow graph basic block state.
134 */
135typedef struct DBGFFLOWBBINT
136{
137 /** Node for the list of all basic blocks. */
138 RTLISTNODE NdFlowBb;
139 /** The control flow graph the basic block belongs to. */
140 PDBGFFLOWINT pFlow;
141 /** Reference counter. */
142 uint32_t volatile cRefs;
143 /** Basic block end type. */
144 DBGFFLOWBBENDTYPE enmEndType;
145 /** Start address of this basic block. */
146 DBGFADDRESS AddrStart;
147 /** End address of this basic block. */
148 DBGFADDRESS AddrEnd;
149 /** Address of the block succeeding.
150 * This is valid for conditional jumps
151 * (the other target is referenced by AddrEnd+1) and
152 * unconditional jumps (not ret, iret, etc.) except
153 * if we can't infer the jump target (jmp *eax for example). */
154 DBGFADDRESS AddrTarget;
155 /** The indirect branch table identified for indirect branches. */
156 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl;
157 /** Last status error code if DBGF_FLOW_BB_F_INCOMPLETE_ERR is set. */
158 int rcError;
159 /** Error message if DBGF_FLOW_BB_F_INCOMPLETE_ERR is set. */
160 char *pszErr;
161 /** Flags for this basic block. */
162 uint32_t fFlags;
163 /** Number of instructions in this basic block. */
164 uint32_t cInstr;
165 /** Maximum number of instruction records for this basic block. */
166 uint32_t cInstrMax;
167 /** Instruction records, variable in size. */
168 DBGFFLOWBBINSTR aInstr[1];
169} DBGFFLOWBBINT;
170/** Pointer to an internal control flow graph basic block state. */
171typedef DBGFFLOWBBINT *PDBGFFLOWBBINT;
172
173
174/**
175 * Control flow graph iterator state.
176 */
177typedef struct DBGFFLOWITINT
178{
179 /** Pointer to the control flow graph (holding a reference). */
180 PDBGFFLOWINT pFlow;
181 /** Next basic block to return. */
182 uint32_t idxBbNext;
183 /** Array of basic blocks sorted by the specified order - variable in size. */
184 PDBGFFLOWBBINT apBb[1];
185} DBGFFLOWITINT;
186/** Pointer to the internal control flow graph iterator state. */
187typedef DBGFFLOWITINT *PDBGFFLOWITINT;
188
189
190/**
191 * Control flow graph branch table iterator state.
192 */
193typedef struct DBGFFLOWBRANCHTBLITINT
194{
195 /** Pointer to the control flow graph (holding a reference). */
196 PDBGFFLOWINT pFlow;
197 /** Next branch table to return. */
198 uint32_t idxTblNext;
199 /** Array of branch table pointers sorted by the specified order - variable in size. */
200 PDBGFFLOWBRANCHTBLINT apBranchTbl[1];
201} DBGFFLOWBRANCHTBLITINT;
202/** Pointer to the internal control flow graph branch table iterator state. */
203typedef DBGFFLOWBRANCHTBLITINT *PDBGFFLOWBRANCHTBLITINT;
204
205
206/*********************************************************************************************************************************
207* Internal Functions *
208*********************************************************************************************************************************/
209
210static uint32_t dbgfR3FlowBbReleaseInt(PDBGFFLOWBBINT pFlowBb, bool fMayDestroyFlow);
211static void dbgfR3FlowBranchTblDestroy(PDBGFFLOWBRANCHTBLINT pFlowBranchTbl);
212
213
214/**
215 * Checks whether both addresses are equal.
216 *
217 * @returns true if both addresses point to the same location, false otherwise.
218 * @param pAddr1 First address.
219 * @param pAddr2 Second address.
220 */
221static bool dbgfR3FlowAddrEqual(PDBGFADDRESS pAddr1, PDBGFADDRESS pAddr2)
222{
223 return pAddr1->Sel == pAddr2->Sel
224 && pAddr1->off == pAddr2->off;
225}
226
227
228/**
229 * Checks whether the first given address is lower than the second one.
230 *
231 * @returns true if both addresses point to the same location, false otherwise.
232 * @param pAddr1 First address.
233 * @param pAddr2 Second address.
234 */
235static bool dbgfR3FlowAddrLower(PDBGFADDRESS pAddr1, PDBGFADDRESS pAddr2)
236{
237 return pAddr1->Sel == pAddr2->Sel
238 && pAddr1->off < pAddr2->off;
239}
240
241
242/**
243 * Checks whether the given basic block and address intersect.
244 *
245 * @returns true if they intersect, false otherwise.
246 * @param pFlowBb The basic block to check.
247 * @param pAddr The address to check for.
248 */
249static bool dbgfR3FlowAddrIntersect(PDBGFFLOWBBINT pFlowBb, PDBGFADDRESS pAddr)
250{
251 return (pFlowBb->AddrStart.Sel == pAddr->Sel)
252 && (pFlowBb->AddrStart.off <= pAddr->off)
253 && (pFlowBb->AddrEnd.off >= pAddr->off);
254}
255
256
257/**
258 * Returns the distance of the two given addresses.
259 *
260 * @returns Distance of the addresses.
261 * @param pAddr1 The first address.
262 * @param pAddr2 The second address.
263 */
264static RTGCUINTPTR dbgfR3FlowAddrGetDistance(PDBGFADDRESS pAddr1, PDBGFADDRESS pAddr2)
265{
266 if (pAddr1->Sel == pAddr2->Sel)
267 {
268 if (pAddr1->off >= pAddr2->off)
269 return pAddr1->off - pAddr2->off;
270 else
271 return pAddr2->off - pAddr1->off;
272 }
273 else
274 AssertFailed();
275
276 return 0;
277}
278
279
280/**
281 * Creates a new basic block.
282 *
283 * @returns Pointer to the basic block on success or NULL if out of memory.
284 * @param pThis The control flow graph.
285 * @param pAddrStart The start of the basic block.
286 * @param fFlowBbFlags Additional flags for this bascic block.
287 * @param cInstrMax Maximum number of instructions this block can hold initially.
288 */
289static PDBGFFLOWBBINT dbgfR3FlowBbCreate(PDBGFFLOWINT pThis, PDBGFADDRESS pAddrStart, uint32_t fFlowBbFlags,
290 uint32_t cInstrMax)
291{
292 PDBGFFLOWBBINT pFlowBb = (PDBGFFLOWBBINT)RTMemAllocZ(RT_UOFFSETOF_DYN(DBGFFLOWBBINT, aInstr[cInstrMax]));
293 if (RT_LIKELY(pFlowBb))
294 {
295 RTListInit(&pFlowBb->NdFlowBb);
296 pFlowBb->cRefs = 1;
297 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_INVALID;
298 pFlowBb->pFlow = pThis;
299 pFlowBb->fFlags = DBGF_FLOW_BB_F_EMPTY | fFlowBbFlags;
300 pFlowBb->AddrStart = *pAddrStart;
301 pFlowBb->AddrEnd = *pAddrStart;
302 pFlowBb->rcError = VINF_SUCCESS;
303 pFlowBb->pszErr = NULL;
304 pFlowBb->cInstr = 0;
305 pFlowBb->cInstrMax = cInstrMax;
306 pFlowBb->pFlowBranchTbl = NULL;
307 ASMAtomicIncU32(&pThis->cRefsBb);
308 }
309
310 return pFlowBb;
311}
312
313
314/**
315 * Creates an empty branch table with the given size.
316 *
317 * @returns Pointer to the empty branch table on success or NULL if out of memory.
318 * @param pThis The control flow graph.
319 * @param pAddrStart The start of the branch table.
320 * @param idxGenRegBase The general register index holding the base address.
321 * @param cSlots Number of slots the table has.
322 */
323static PDBGFFLOWBRANCHTBLINT
324dbgfR3FlowBranchTblCreate(PDBGFFLOWINT pThis, PDBGFADDRESS pAddrStart, uint8_t idxGenRegBase, uint32_t cSlots)
325{
326 PDBGFFLOWBRANCHTBLINT pBranchTbl = (PDBGFFLOWBRANCHTBLINT)RTMemAllocZ(RT_UOFFSETOF_DYN(DBGFFLOWBRANCHTBLINT,
327 aAddresses[cSlots]));
328 if (RT_LIKELY(pBranchTbl))
329 {
330 RTListInit(&pBranchTbl->NdBranchTbl);
331 pBranchTbl->pFlow = pThis;
332 pBranchTbl->idxGenRegBase = idxGenRegBase;
333 pBranchTbl->AddrStart = *pAddrStart;
334 pBranchTbl->cSlots = cSlots;
335 pBranchTbl->cRefs = 1;
336 }
337
338 return pBranchTbl;
339}
340
341
342/**
343 * Destroys a control flow graph.
344 *
345 * @param pThis The control flow graph to destroy.
346 */
347static void dbgfR3FlowDestroy(PDBGFFLOWINT pThis)
348{
349 /* Defer destruction if there are still basic blocks referencing us. */
350 PDBGFFLOWBBINT pFlowBb;
351 PDBGFFLOWBBINT pFlowBbNext;
352 RTListForEachSafe(&pThis->LstFlowBb, pFlowBb, pFlowBbNext, DBGFFLOWBBINT, NdFlowBb)
353 {
354 dbgfR3FlowBbReleaseInt(pFlowBb, false /*fMayDestroyFlow*/);
355 }
356
357 Assert(!pThis->cRefs);
358 if (!pThis->cRefsBb)
359 {
360 /* Destroy the branch tables. */
361 PDBGFFLOWBRANCHTBLINT pTbl = NULL;
362 PDBGFFLOWBRANCHTBLINT pTblNext = NULL;
363 RTListForEachSafe(&pThis->LstBranchTbl, pTbl, pTblNext, DBGFFLOWBRANCHTBLINT, NdBranchTbl)
364 {
365 dbgfR3FlowBranchTblDestroy(pTbl);
366 }
367
368 RTStrCacheDestroy(pThis->hStrCacheInstr);
369 RTMemFree(pThis);
370 }
371}
372
373
374/**
375 * Destroys a basic block.
376 *
377 * @param pFlowBb The basic block to destroy.
378 * @param fMayDestroyFlow Flag whether the control flow graph container
379 * should be destroyed when there is nothing referencing it.
380 */
381static void dbgfR3FlowBbDestroy(PDBGFFLOWBBINT pFlowBb, bool fMayDestroyFlow)
382{
383 PDBGFFLOWINT pThis = pFlowBb->pFlow;
384
385 RTListNodeRemove(&pFlowBb->NdFlowBb);
386 pThis->cBbs--;
387 for (uint32_t idxInstr = 0; idxInstr < pFlowBb->cInstr; idxInstr++)
388 RTStrCacheRelease(pThis->hStrCacheInstr, pFlowBb->aInstr[idxInstr].pszInstr);
389 uint32_t cRefsBb = ASMAtomicDecU32(&pThis->cRefsBb);
390 RTMemFree(pFlowBb);
391
392 if (!cRefsBb && !pThis->cRefs && fMayDestroyFlow)
393 dbgfR3FlowDestroy(pThis);
394}
395
396
397/**
398 * Destroys a given branch table.
399 *
400 * @param pFlowBranchTbl The flow branch table to destroy.
401 */
402static void dbgfR3FlowBranchTblDestroy(PDBGFFLOWBRANCHTBLINT pFlowBranchTbl)
403{
404 RTListNodeRemove(&pFlowBranchTbl->NdBranchTbl);
405 RTMemFree(pFlowBranchTbl);
406}
407
408
409/**
410 * Internal basic block release worker.
411 *
412 * @returns New reference count of the released basic block, on 0
413 * it is destroyed.
414 * @param pFlowBb The basic block to release.
415 * @param fMayDestroyFlow Flag whether the control flow graph container
416 * should be destroyed when there is nothing referencing it.
417 */
418static uint32_t dbgfR3FlowBbReleaseInt(PDBGFFLOWBBINT pFlowBb, bool fMayDestroyFlow)
419{
420 uint32_t cRefs = ASMAtomicDecU32(&pFlowBb->cRefs);
421 AssertMsg(cRefs < _1M, ("%#x %p %d\n", cRefs, pFlowBb, pFlowBb->enmEndType));
422 if (cRefs == 0)
423 dbgfR3FlowBbDestroy(pFlowBb, fMayDestroyFlow);
424 return cRefs;
425}
426
427
428/**
429 * Links the given basic block into the control flow graph.
430 *
431 * @param pThis The control flow graph to link into.
432 * @param pFlowBb The basic block to link.
433 */
434DECLINLINE(void) dbgfR3FlowLink(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb)
435{
436 RTListAppend(&pThis->LstFlowBb, &pFlowBb->NdFlowBb);
437 pThis->cBbs++;
438}
439
440
441/**
442 * Links the given branch table into the control flow graph.
443 *
444 * @param pThis The control flow graph to link into.
445 * @param pBranchTbl The branch table to link.
446 */
447DECLINLINE(void) dbgfR3FlowBranchTblLink(PDBGFFLOWINT pThis, PDBGFFLOWBRANCHTBLINT pBranchTbl)
448{
449 RTListAppend(&pThis->LstBranchTbl, &pBranchTbl->NdBranchTbl);
450 pThis->cBranchTbls++;
451}
452
453
454/**
455 * Returns the first unpopulated basic block of the given control flow graph.
456 *
457 * @returns The first unpopulated control flow graph or NULL if not found.
458 * @param pThis The control flow graph.
459 */
460DECLINLINE(PDBGFFLOWBBINT) dbgfR3FlowGetUnpopulatedBb(PDBGFFLOWINT pThis)
461{
462 PDBGFFLOWBBINT pFlowBb;
463 RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
464 {
465 if (pFlowBb->fFlags & DBGF_FLOW_BB_F_EMPTY)
466 return pFlowBb;
467 }
468
469 return NULL;
470}
471
472
473/**
474 * Returns the branch table with the given address if it exists.
475 *
476 * @returns Pointer to the branch table record or NULL if not found.
477 * @param pThis The control flow graph.
478 * @param pAddrTbl The branch table address.
479 */
480DECLINLINE(PDBGFFLOWBRANCHTBLINT) dbgfR3FlowBranchTblFindByAddr(PDBGFFLOWINT pThis, PDBGFADDRESS pAddrTbl)
481{
482 PDBGFFLOWBRANCHTBLINT pTbl;
483 RTListForEach(&pThis->LstBranchTbl, pTbl, DBGFFLOWBRANCHTBLINT, NdBranchTbl)
484 {
485 if (dbgfR3FlowAddrEqual(&pTbl->AddrStart, pAddrTbl))
486 return pTbl;
487 }
488
489 return NULL;
490}
491
492
493/**
494 * Sets the given error status for the basic block.
495 *
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.x86.Base.idxGenReg == idxRegTgt
791 /*&& DisState.Param1.cb == cbPtr*/
792 && DisState.Param2.x86.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->x86.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->x86.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 rc = dbgfR3DisasInstrStateEx(pUVM, idCpu, &AddrDisasm, fFlags,
1157 &szOutput[0], sizeof(szOutput), &DisState);
1158 if (RT_SUCCESS(rc))
1159 {
1160 if ( pThis->fFlags & DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB
1161 && DisState.pCurInstr->uOpcode == OP_CALL
1162 && !(pFlowBb->fFlags & DBGF_FLOW_BB_F_EMPTY))
1163 {
1164 /*
1165 * If the basic block is not empty, the basic block is terminated and the successor is added
1166 * which will contain the call instruction.
1167 */
1168 pFlowBb->AddrTarget = AddrDisasm;
1169 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND;
1170 rc = dbgfR3FlowBbSuccessorAdd(pThis, &AddrDisasm,
1171 (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
1172 pFlowBb->pFlowBranchTbl);
1173 if (RT_FAILURE(rc))
1174 dbgfR3FlowBbSetError(pFlowBb, rc, "Adding successor blocks failed with %Rrc", rc);
1175 break;
1176 }
1177
1178 pFlowBb->fFlags &= ~DBGF_FLOW_BB_F_EMPTY;
1179 cbDisasmLeft -= DisState.cbInstr;
1180
1181 if (pFlowBb->cInstr == pFlowBb->cInstrMax)
1182 {
1183 /* Reallocate. */
1184 RTListNodeRemove(&pFlowBb->NdFlowBb);
1185 PDBGFFLOWBBINT pFlowBbNew = (PDBGFFLOWBBINT)RTMemRealloc(pFlowBb,
1186 RT_UOFFSETOF_DYN(DBGFFLOWBBINT, aInstr[pFlowBb->cInstrMax + 10]));
1187 if (pFlowBbNew)
1188 {
1189 pFlowBbNew->cInstrMax += 10;
1190 pFlowBb = pFlowBbNew;
1191 }
1192 else
1193 rc = VERR_NO_MEMORY;
1194 RTListAppend(&pThis->LstFlowBb, &pFlowBb->NdFlowBb);
1195 }
1196
1197 if (RT_SUCCESS(rc))
1198 {
1199 PDBGFFLOWBBINSTR pInstr = &pFlowBb->aInstr[pFlowBb->cInstr];
1200
1201 pInstr->AddrInstr = AddrDisasm;
1202 pInstr->cbInstr = DisState.cbInstr;
1203 pInstr->pszInstr = RTStrCacheEnter(pThis->hStrCacheInstr, &szOutput[0]);
1204 pFlowBb->cInstr++;
1205
1206 pFlowBb->AddrEnd = AddrDisasm;
1207 DBGFR3AddrAdd(&pFlowBb->AddrEnd, pInstr->cbInstr - 1);
1208 DBGFR3AddrAdd(&AddrDisasm, pInstr->cbInstr);
1209
1210 /*
1211 * Check control flow instructions and create new basic blocks
1212 * marking the current one as complete.
1213 */
1214 if (DisState.pCurInstr->fOpType & DISOPTYPE_CONTROLFLOW)
1215 {
1216 uint16_t uOpc = DisState.pCurInstr->uOpcode;
1217
1218 if (uOpc == OP_CALL)
1219 pThis->cCallInsns++;
1220
1221 if ( uOpc == OP_RETN || uOpc == OP_RETF || uOpc == OP_IRET
1222 || uOpc == OP_SYSEXIT || uOpc == OP_SYSRET)
1223 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_EXIT;
1224 else if (uOpc == OP_JMP)
1225 {
1226 Assert(DisState.pCurInstr->fOpType & DISOPTYPE_UNCOND_CONTROLFLOW);
1227
1228 if (dbgfR3FlowBranchTargetIsIndirect(&DisState.Param1))
1229 {
1230 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP;
1231
1232 if (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE)
1233 {
1234 Assert(pThis->fFlags & DBGF_FLOW_CREATE_F_TRY_RESOLVE_INDIRECT_BRANCHES);
1235
1236 /*
1237 * This basic block was already discovered by parsing a jump table and
1238 * there should be a candidate for the branch table. Check whether it uses the
1239 * same branch table.
1240 */
1241 rc = dbgfR3FlowBbCheckBranchTblCandidate(pThis, pFlowBb, pUVM, idCpu,
1242 &DisState.Param1, fFlags);
1243 }
1244 else
1245 {
1246 if (pThis->fFlags & DBGF_FLOW_CREATE_F_TRY_RESOLVE_INDIRECT_BRANCHES)
1247 rc = dbgfR3FlowTryResolveIndirectBranch(pThis, pFlowBb, pUVM, idCpu,
1248 &DisState.Param1, fFlags);
1249 else
1250 dbgfR3FlowBbSetError(pFlowBb, VERR_NOT_SUPPORTED,
1251 "Detected indirect branch and resolving it not being enabled");
1252 }
1253 }
1254 else
1255 {
1256 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND_JMP;
1257
1258 /* Create one new basic block with the jump target address. */
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 else if (uOpc != OP_CALL)
1269 {
1270 Assert(DisState.pCurInstr->fOpType & DISOPTYPE_COND_CONTROLFLOW);
1271 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_COND;
1272
1273 /*
1274 * Create two new basic blocks, one with the jump target address
1275 * and one starting after the current instruction.
1276 */
1277 rc = dbgfR3FlowBbSuccessorAdd(pThis, &AddrDisasm,
1278 (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
1279 pFlowBb->pFlowBranchTbl);
1280 if (RT_SUCCESS(rc))
1281 {
1282 rc = dbgfR3FlowQueryDirectBranchTarget(pUVM, idCpu, &DisState.Param1, &pInstr->AddrInstr, pInstr->cbInstr,
1283 RT_BOOL(DisState.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW),
1284 &pFlowBb->AddrTarget);
1285 if (RT_SUCCESS(rc))
1286 rc = dbgfR3FlowBbSuccessorAdd(pThis, &pFlowBb->AddrTarget,
1287 (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
1288 pFlowBb->pFlowBranchTbl);
1289 }
1290 }
1291 else if (pThis->fFlags & DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB)
1292 {
1293 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND;
1294 pFlowBb->fFlags |= DBGF_FLOW_BB_F_CALL_INSN;
1295
1296 /* Add new basic block coming after the call instruction. */
1297 rc = dbgfR3FlowBbSuccessorAdd(pThis, &AddrDisasm,
1298 (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
1299 pFlowBb->pFlowBranchTbl);
1300 if ( RT_SUCCESS(rc)
1301 && !dbgfR3FlowBranchTargetIsIndirect(&DisState.Param1))
1302 {
1303 /* Resolve the branch target. */
1304 rc = dbgfR3FlowQueryDirectBranchTarget(pUVM, idCpu, &DisState.Param1, &pInstr->AddrInstr, pInstr->cbInstr,
1305 RT_BOOL(DisState.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW),
1306 &pFlowBb->AddrTarget);
1307 if (RT_SUCCESS(rc))
1308 pFlowBb->fFlags |= DBGF_FLOW_BB_F_CALL_INSN_TARGET_KNOWN;
1309 }
1310 }
1311
1312 if (RT_FAILURE(rc))
1313 dbgfR3FlowBbSetError(pFlowBb, rc, "Adding successor blocks failed with %Rrc", rc);
1314
1315 /* Quit disassembling. */
1316 if ( ( uOpc != OP_CALL
1317 || (pThis->fFlags & DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB))
1318 || RT_FAILURE(rc))
1319 break;
1320 }
1321 }
1322 else
1323 dbgfR3FlowBbSetError(pFlowBb, rc, "Increasing basic block failed with %Rrc", rc);
1324 }
1325 else
1326 dbgfR3FlowBbSetError(pFlowBb, rc, "Disassembling the instruction failed with %Rrc", rc);
1327 }
1328
1329 return VINF_SUCCESS;
1330}
1331
1332/**
1333 * Populate all empty basic blocks.
1334 *
1335 * @returns VBox status code.
1336 * @param pUVM The user mode VM handle.
1337 * @param idCpu CPU id for disassembling.
1338 * @param pThis The control flow graph to populate.
1339 * @param cbDisasmMax The maximum amount to disassemble.
1340 * @param fFlags Combination of DBGF_DISAS_FLAGS_*.
1341 */
1342static int dbgfR3FlowPopulate(PUVM pUVM, VMCPUID idCpu, PDBGFFLOWINT pThis, uint32_t cbDisasmMax, uint32_t fFlags)
1343{
1344 int rc = VINF_SUCCESS;
1345 PDBGFFLOWBBINT pFlowBb = dbgfR3FlowGetUnpopulatedBb(pThis);
1346
1347 while (pFlowBb != NULL)
1348 {
1349 rc = dbgfR3FlowBbProcess(pUVM, idCpu, pThis, pFlowBb, cbDisasmMax, fFlags);
1350 if (RT_FAILURE(rc))
1351 break;
1352
1353 pFlowBb = dbgfR3FlowGetUnpopulatedBb(pThis);
1354 }
1355
1356 return rc;
1357}
1358
1359/**
1360 * Creates a new control flow graph from the given start address.
1361 *
1362 * @returns VBox status code.
1363 * @param pUVM The user mode VM handle.
1364 * @param idCpu CPU id for disassembling.
1365 * @param pAddressStart Where to start creating the control flow graph.
1366 * @param cbDisasmMax Limit the amount of bytes to disassemble, 0 for no limit.
1367 * @param fFlagsFlow Combination of DBGF_FLOW_CREATE_F_* to control the creation of the flow graph.
1368 * @param fFlagsDisasm Combination of DBGF_DISAS_FLAGS_* controlling the style of the disassembled
1369 * instructions.
1370 * @param phFlow Where to store the handle to the control flow graph on success.
1371 */
1372VMMR3DECL(int) DBGFR3FlowCreate(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddressStart, uint32_t cbDisasmMax,
1373 uint32_t fFlagsFlow, uint32_t fFlagsDisasm, PDBGFFLOW phFlow)
1374{
1375 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1376 PVM pVM = pUVM->pVM;
1377 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1378 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
1379 AssertPtrReturn(pAddressStart, VERR_INVALID_POINTER);
1380 AssertReturn(!(fFlagsDisasm & ~DBGF_DISAS_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
1381 AssertReturn((fFlagsDisasm & DBGF_DISAS_FLAGS_MODE_MASK) <= DBGF_DISAS_FLAGS_64BIT_MODE, VERR_INVALID_PARAMETER);
1382
1383 /* Create the control flow graph container. */
1384 int rc = VINF_SUCCESS;
1385 PDBGFFLOWINT pThis = (PDBGFFLOWINT)RTMemAllocZ(sizeof(DBGFFLOWINT));
1386 if (RT_LIKELY(pThis))
1387 {
1388 rc = RTStrCacheCreate(&pThis->hStrCacheInstr, "DBGFFLOW");
1389 if (RT_SUCCESS(rc))
1390 {
1391 pThis->cRefs = 1;
1392 pThis->cRefsBb = 0;
1393 pThis->cBbs = 0;
1394 pThis->cBranchTbls = 0;
1395 pThis->cCallInsns = 0;
1396 pThis->fFlags = fFlagsFlow;
1397 RTListInit(&pThis->LstFlowBb);
1398 RTListInit(&pThis->LstBranchTbl);
1399 /* Create the entry basic block and start the work. */
1400
1401 PDBGFFLOWBBINT pFlowBb = dbgfR3FlowBbCreate(pThis, pAddressStart, DBGF_FLOW_BB_F_ENTRY, 10);
1402 if (RT_LIKELY(pFlowBb))
1403 {
1404 dbgfR3FlowLink(pThis, pFlowBb);
1405 rc = dbgfR3FlowPopulate(pUVM, idCpu, pThis, cbDisasmMax, fFlagsDisasm);
1406 if (RT_SUCCESS(rc))
1407 {
1408 *phFlow = pThis;
1409 return VINF_SUCCESS;
1410 }
1411 }
1412 else
1413 rc = VERR_NO_MEMORY;
1414 }
1415
1416 ASMAtomicDecU32(&pThis->cRefs);
1417 dbgfR3FlowDestroy(pThis);
1418 }
1419 else
1420 rc = VERR_NO_MEMORY;
1421
1422 return rc;
1423}
1424
1425
1426/**
1427 * Retains the control flow graph handle.
1428 *
1429 * @returns Current reference count.
1430 * @param hFlow The control flow graph handle to retain.
1431 */
1432VMMR3DECL(uint32_t) DBGFR3FlowRetain(DBGFFLOW hFlow)
1433{
1434 PDBGFFLOWINT pThis = hFlow;
1435 AssertPtrReturn(pThis, UINT32_MAX);
1436
1437 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1438 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1439 return cRefs;
1440}
1441
1442
1443/**
1444 * Releases the control flow graph handle.
1445 *
1446 * @returns Current reference count, on 0 the control flow graph will be destroyed.
1447 * @param hFlow The control flow graph handle to release.
1448 */
1449VMMR3DECL(uint32_t) DBGFR3FlowRelease(DBGFFLOW hFlow)
1450{
1451 PDBGFFLOWINT pThis = hFlow;
1452 if (!pThis)
1453 return 0;
1454 AssertPtrReturn(pThis, UINT32_MAX);
1455
1456 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1457 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1458 if (cRefs == 0)
1459 dbgfR3FlowDestroy(pThis);
1460 return cRefs;
1461}
1462
1463
1464/**
1465 * Queries the basic block denoting the entry point into the control flow graph.
1466 *
1467 * @returns VBox status code.
1468 * @param hFlow The control flow graph handle.
1469 * @param phFlowBb Where to store the basic block handle on success.
1470 */
1471VMMR3DECL(int) DBGFR3FlowQueryStartBb(DBGFFLOW hFlow, PDBGFFLOWBB phFlowBb)
1472{
1473 PDBGFFLOWINT pThis = hFlow;
1474 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1475
1476 PDBGFFLOWBBINT pFlowBb;
1477 RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
1478 {
1479 if (pFlowBb->fFlags & DBGF_FLOW_BB_F_ENTRY)
1480 {
1481 *phFlowBb = pFlowBb;
1482 return VINF_SUCCESS;
1483 }
1484 }
1485
1486 AssertFailed(); /* Should never get here. */
1487 return VERR_INTERNAL_ERROR;
1488}
1489
1490
1491/**
1492 * Queries a basic block in the given control flow graph which covers the given
1493 * address.
1494 *
1495 * @returns VBox status code.
1496 * @retval VERR_NOT_FOUND if there is no basic block intersecting with the address.
1497 * @param hFlow The control flow graph handle.
1498 * @param pAddr The address to look for.
1499 * @param phFlowBb Where to store the basic block handle on success.
1500 */
1501VMMR3DECL(int) DBGFR3FlowQueryBbByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBB phFlowBb)
1502{
1503 PDBGFFLOWINT pThis = hFlow;
1504 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1505 AssertPtrReturn(pAddr, VERR_INVALID_POINTER);
1506 AssertPtrReturn(phFlowBb, VERR_INVALID_POINTER);
1507
1508 PDBGFFLOWBBINT pFlowBb;
1509 RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
1510 {
1511 if (dbgfR3FlowAddrIntersect(pFlowBb, pAddr))
1512 {
1513 DBGFR3FlowBbRetain(pFlowBb);
1514 *phFlowBb = pFlowBb;
1515 return VINF_SUCCESS;
1516 }
1517 }
1518
1519 return VERR_NOT_FOUND;
1520}
1521
1522
1523/**
1524 * Queries a branch table in the given control flow graph by the given address.
1525 *
1526 * @returns VBox status code.
1527 * @retval VERR_NOT_FOUND if there is no branch table with the given address.
1528 * @param hFlow The control flow graph handle.
1529 * @param pAddr The address of the branch table.
1530 * @param phFlowBranchTbl Where to store the handle to branch table on success.
1531 *
1532 * @note Call DBGFR3FlowBranchTblRelease() when the handle is not required anymore.
1533 */
1534VMMR3DECL(int) DBGFR3FlowQueryBranchTblByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBRANCHTBL phFlowBranchTbl)
1535{
1536 PDBGFFLOWINT pThis = hFlow;
1537 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1538 AssertPtrReturn(pAddr, VERR_INVALID_POINTER);
1539 AssertPtrReturn(phFlowBranchTbl, VERR_INVALID_POINTER);
1540
1541 PDBGFFLOWBRANCHTBLINT pBranchTbl = dbgfR3FlowBranchTblFindByAddr(pThis, pAddr);
1542 if (pBranchTbl)
1543 {
1544 DBGFR3FlowBranchTblRetain(pBranchTbl);
1545 *phFlowBranchTbl = pBranchTbl;
1546 return VINF_SUCCESS;
1547 }
1548
1549 return VERR_NOT_FOUND;
1550}
1551
1552
1553/**
1554 * Returns the number of basic blcoks inside the control flow graph.
1555 *
1556 * @returns Number of basic blocks.
1557 * @param hFlow The control flow graph handle.
1558 */
1559VMMR3DECL(uint32_t) DBGFR3FlowGetBbCount(DBGFFLOW hFlow)
1560{
1561 PDBGFFLOWINT pThis = hFlow;
1562 AssertPtrReturn(pThis, 0);
1563
1564 return pThis->cBbs;
1565}
1566
1567
1568/**
1569 * Returns the number of branch tables inside the control flow graph.
1570 *
1571 * @returns Number of basic blocks.
1572 * @param hFlow The control flow graph handle.
1573 */
1574VMMR3DECL(uint32_t) DBGFR3FlowGetBranchTblCount(DBGFFLOW hFlow)
1575{
1576 PDBGFFLOWINT pThis = hFlow;
1577 AssertPtrReturn(pThis, 0);
1578
1579 return pThis->cBranchTbls;
1580}
1581
1582
1583/**
1584 * Returns the number of call instructions encountered in the given
1585 * control flow graph.
1586 *
1587 * @returns Number of call instructions.
1588 * @param hFlow The control flow graph handle.
1589 */
1590VMMR3DECL(uint32_t) DBGFR3FlowGetCallInsnCount(DBGFFLOW hFlow)
1591{
1592 PDBGFFLOWINT pThis = hFlow;
1593 AssertPtrReturn(pThis, 0);
1594
1595 return pThis->cCallInsns;
1596}
1597
1598
1599/**
1600 * Retains the basic block handle.
1601 *
1602 * @returns Current reference count.
1603 * @param hFlowBb The basic block handle to retain.
1604 */
1605VMMR3DECL(uint32_t) DBGFR3FlowBbRetain(DBGFFLOWBB hFlowBb)
1606{
1607 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1608 AssertPtrReturn(pFlowBb, UINT32_MAX);
1609
1610 uint32_t cRefs = ASMAtomicIncU32(&pFlowBb->cRefs);
1611 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p %d\n", cRefs, pFlowBb, pFlowBb->enmEndType));
1612 return cRefs;
1613}
1614
1615
1616/**
1617 * Releases the basic block handle.
1618 *
1619 * @returns Current reference count, on 0 the basic block will be destroyed.
1620 * @param hFlowBb The basic block handle to release.
1621 */
1622VMMR3DECL(uint32_t) DBGFR3FlowBbRelease(DBGFFLOWBB hFlowBb)
1623{
1624 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1625 if (!pFlowBb)
1626 return 0;
1627
1628 return dbgfR3FlowBbReleaseInt(pFlowBb, true /* fMayDestroyFlow */);
1629}
1630
1631
1632/**
1633 * Returns the start address of the basic block.
1634 *
1635 * @returns Pointer to DBGF adress containing the start address of the basic block.
1636 * @param hFlowBb The basic block handle.
1637 * @param pAddrStart Where to store the start address of the basic block.
1638 */
1639VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetStartAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrStart)
1640{
1641 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1642 AssertPtrReturn(pFlowBb, NULL);
1643 AssertPtrReturn(pAddrStart, NULL);
1644
1645 *pAddrStart = pFlowBb->AddrStart;
1646 return pAddrStart;
1647}
1648
1649
1650/**
1651 * Returns the end address of the basic block (inclusive).
1652 *
1653 * @returns Pointer to DBGF adress containing the end address of the basic block.
1654 * @param hFlowBb The basic block handle.
1655 * @param pAddrEnd Where to store the end address of the basic block.
1656 */
1657VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetEndAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrEnd)
1658{
1659 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1660 AssertPtrReturn(pFlowBb, NULL);
1661 AssertPtrReturn(pAddrEnd, NULL);
1662
1663 *pAddrEnd = pFlowBb->AddrEnd;
1664 return pAddrEnd;
1665}
1666
1667
1668/**
1669 * Returns the address the last instruction in the basic block branches to.
1670 *
1671 * @returns Pointer to DBGF adress containing the branch address of the basic block.
1672 * @param hFlowBb The basic block handle.
1673 * @param pAddrTarget Where to store the branch address of the basic block.
1674 *
1675 * @note This is only valid for unconditional or conditional branches, or for a basic block
1676 * containing only a call instruction when DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB was given
1677 * during creation and the branch target could be deduced as indicated by the DBGF_FLOW_BB_F_CALL_INSN_TARGET_KNOWN
1678 * flag for the basic block. This method will assert for every other basic block type.
1679 * @note For indirect unconditional branches using a branch table this will return the start address
1680 * of the branch table.
1681 */
1682VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetBranchAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrTarget)
1683{
1684 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1685 AssertPtrReturn(pFlowBb, NULL);
1686 AssertPtrReturn(pAddrTarget, NULL);
1687 AssertReturn( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_JMP
1688 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_COND
1689 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP
1690 || ( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND
1691 && (pFlowBb->fFlags & DBGF_FLOW_BB_F_CALL_INSN_TARGET_KNOWN)),
1692 NULL);
1693
1694 if ( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP
1695 && pFlowBb->pFlowBranchTbl)
1696 *pAddrTarget = pFlowBb->pFlowBranchTbl->AddrStart;
1697 else
1698 *pAddrTarget = pFlowBb->AddrTarget;
1699 return pAddrTarget;
1700}
1701
1702
1703/**
1704 * Returns the address of the next block following this one in the instruction stream.
1705 * (usually end address + 1).
1706 *
1707 * @returns Pointer to DBGF adress containing the following address of the basic block.
1708 * @param hFlowBb The basic block handle.
1709 * @param pAddrFollow Where to store the following address of the basic block.
1710 *
1711 * @note This is only valid for conditional branches and if the last instruction in the
1712 * given basic block doesn't change the control flow but the blocks were split
1713 * because the successor is referenced by multiple other blocks as an entry point.
1714 */
1715VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetFollowingAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrFollow)
1716{
1717 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1718 AssertPtrReturn(pFlowBb, NULL);
1719 AssertPtrReturn(pAddrFollow, NULL);
1720 AssertReturn( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND
1721 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_COND,
1722 NULL);
1723
1724 *pAddrFollow = pFlowBb->AddrEnd;
1725 DBGFR3AddrAdd(pAddrFollow, 1);
1726 return pAddrFollow;
1727}
1728
1729
1730/**
1731 * Returns the type of the last instruction in the basic block.
1732 *
1733 * @returns Last instruction type.
1734 * @param hFlowBb The basic block handle.
1735 */
1736VMMR3DECL(DBGFFLOWBBENDTYPE) DBGFR3FlowBbGetType(DBGFFLOWBB hFlowBb)
1737{
1738 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1739 AssertPtrReturn(pFlowBb, DBGFFLOWBBENDTYPE_INVALID);
1740
1741 return pFlowBb->enmEndType;
1742}
1743
1744
1745/**
1746 * Get the number of instructions contained in the basic block.
1747 *
1748 * @returns Number of instructions in the basic block.
1749 * @param hFlowBb The basic block handle.
1750 */
1751VMMR3DECL(uint32_t) DBGFR3FlowBbGetInstrCount(DBGFFLOWBB hFlowBb)
1752{
1753 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1754 AssertPtrReturn(pFlowBb, 0);
1755
1756 return pFlowBb->cInstr;
1757}
1758
1759
1760/**
1761 * Get flags for the given basic block.
1762 *
1763 * @returns Combination of DBGF_FLOW_BB_F_*
1764 * @param hFlowBb The basic block handle.
1765 */
1766VMMR3DECL(uint32_t) DBGFR3FlowBbGetFlags(DBGFFLOWBB hFlowBb)
1767{
1768 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1769 AssertPtrReturn(pFlowBb, 0);
1770
1771 return pFlowBb->fFlags;
1772}
1773
1774
1775/**
1776 * Queries the branch table used if the given basic block ends with an indirect branch
1777 * and has a branch table referenced.
1778 *
1779 * @returns VBox status code.
1780 * @param hFlowBb The basic block handle.
1781 * @param phBranchTbl Where to store the branch table handle on success.
1782 *
1783 * @note Release the branch table reference with DBGFR3FlowBranchTblRelease() when not required
1784 * anymore.
1785 */
1786VMMR3DECL(int) DBGFR3FlowBbQueryBranchTbl(DBGFFLOWBB hFlowBb, PDBGFFLOWBRANCHTBL phBranchTbl)
1787{
1788 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1789 AssertPtrReturn(pFlowBb, VERR_INVALID_HANDLE);
1790 AssertReturn(pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP, VERR_INVALID_STATE);
1791 AssertPtrReturn(pFlowBb->pFlowBranchTbl, VERR_INVALID_STATE);
1792 AssertPtrReturn(phBranchTbl, VERR_INVALID_POINTER);
1793
1794 DBGFR3FlowBranchTblRetain(pFlowBb->pFlowBranchTbl);
1795 *phBranchTbl = pFlowBb->pFlowBranchTbl;
1796 return VINF_SUCCESS;
1797}
1798
1799
1800/**
1801 * Returns the error status and message if the given basic block has an error.
1802 *
1803 * @returns VBox status code of the error for the basic block.
1804 * @param hFlowBb The basic block handle.
1805 * @param ppszErr Where to store the pointer to the error message - optional.
1806 */
1807VMMR3DECL(int) DBGFR3FlowBbQueryError(DBGFFLOWBB hFlowBb, const char **ppszErr)
1808{
1809 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1810 AssertPtrReturn(pFlowBb, VERR_INVALID_HANDLE);
1811
1812 if (ppszErr)
1813 *ppszErr = pFlowBb->pszErr;
1814
1815 return pFlowBb->rcError;
1816}
1817
1818
1819/**
1820 * Store the disassembled instruction as a string in the given output buffer.
1821 *
1822 * @returns VBox status code.
1823 * @param hFlowBb The basic block handle.
1824 * @param idxInstr The instruction to query.
1825 * @param pAddrInstr Where to store the guest instruction address on success, optional.
1826 * @param pcbInstr Where to store the instruction size on success, optional.
1827 * @param ppszInstr Where to store the pointer to the disassembled instruction string, optional.
1828 */
1829VMMR3DECL(int) DBGFR3FlowBbQueryInstr(DBGFFLOWBB hFlowBb, uint32_t idxInstr, PDBGFADDRESS pAddrInstr,
1830 uint32_t *pcbInstr, const char **ppszInstr)
1831{
1832 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1833 AssertPtrReturn(pFlowBb, VERR_INVALID_POINTER);
1834 AssertReturn(idxInstr < pFlowBb->cInstr, VERR_INVALID_PARAMETER);
1835
1836 if (pAddrInstr)
1837 *pAddrInstr = pFlowBb->aInstr[idxInstr].AddrInstr;
1838 if (pcbInstr)
1839 *pcbInstr = pFlowBb->aInstr[idxInstr].cbInstr;
1840 if (ppszInstr)
1841 *ppszInstr = pFlowBb->aInstr[idxInstr].pszInstr;
1842
1843 return VINF_SUCCESS;
1844}
1845
1846
1847/**
1848 * Queries the successors of the basic block.
1849 *
1850 * @returns VBox status code.
1851 * @param hFlowBb The basic block handle.
1852 * @param phFlowBbFollow Where to store the handle to the basic block following
1853 * this one (optional).
1854 * @param phFlowBbTarget Where to store the handle to the basic block being the
1855 * branch target for this one (optional).
1856 */
1857VMMR3DECL(int) DBGFR3FlowBbQuerySuccessors(DBGFFLOWBB hFlowBb, PDBGFFLOWBB phFlowBbFollow, PDBGFFLOWBB phFlowBbTarget)
1858{
1859 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1860 AssertPtrReturn(pFlowBb, VERR_INVALID_POINTER);
1861
1862 if ( phFlowBbFollow
1863 && ( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND
1864 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_COND))
1865 {
1866 DBGFADDRESS AddrStart = pFlowBb->AddrEnd;
1867 DBGFR3AddrAdd(&AddrStart, 1);
1868 int rc = DBGFR3FlowQueryBbByAddress(pFlowBb->pFlow, &AddrStart, phFlowBbFollow);
1869 AssertRC(rc);
1870 }
1871
1872 if ( phFlowBbTarget
1873 && ( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_JMP
1874 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_COND))
1875 {
1876 int rc = DBGFR3FlowQueryBbByAddress(pFlowBb->pFlow, &pFlowBb->AddrTarget, phFlowBbTarget);
1877 AssertRC(rc);
1878 }
1879
1880 return VINF_SUCCESS;
1881}
1882
1883
1884/**
1885 * Returns the number of basic blocks referencing this basic block as a target.
1886 *
1887 * @returns Number of other basic blocks referencing this one.
1888 * @param hFlowBb The basic block handle.
1889 *
1890 * @note If the given basic block references itself (loop, etc.) this will be counted as well.
1891 */
1892VMMR3DECL(uint32_t) DBGFR3FlowBbGetRefBbCount(DBGFFLOWBB hFlowBb)
1893{
1894 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1895 AssertPtrReturn(pFlowBb, 0);
1896
1897 uint32_t cRefsBb = 0;
1898 PDBGFFLOWBBINT pFlowBbCur;
1899 RTListForEach(&pFlowBb->pFlow->LstFlowBb, pFlowBbCur, DBGFFLOWBBINT, NdFlowBb)
1900 {
1901 if (pFlowBbCur->fFlags & DBGF_FLOW_BB_F_INCOMPLETE_ERR)
1902 continue;
1903
1904 if ( pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_UNCOND
1905 || pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_COND)
1906 {
1907 DBGFADDRESS AddrStart = pFlowBb->AddrEnd;
1908 DBGFR3AddrAdd(&AddrStart, 1);
1909 if (dbgfR3FlowAddrEqual(&pFlowBbCur->AddrStart, &AddrStart))
1910 cRefsBb++;
1911 }
1912
1913 if ( ( pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_JMP
1914 || pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_COND)
1915 && dbgfR3FlowAddrEqual(&pFlowBbCur->AddrStart, &pFlowBb->AddrTarget))
1916 cRefsBb++;
1917 }
1918 return cRefsBb;
1919}
1920
1921
1922/**
1923 * Returns the basic block handles referencing the given basic block.
1924 *
1925 * @returns VBox status code.
1926 * @retval VERR_BUFFER_OVERFLOW if the array can't hold all the basic blocks.
1927 * @param hFlowBb The basic block handle.
1928 * @param paFlowBbRef Pointer to the array containing the referencing basic block handles on success.
1929 * @param cRef Number of entries in the given array.
1930 */
1931VMMR3DECL(int) DBGFR3FlowBbGetRefBb(DBGFFLOWBB hFlowBb, PDBGFFLOWBB paFlowBbRef, uint32_t cRef)
1932{
1933 RT_NOREF3(hFlowBb, paFlowBbRef, cRef);
1934 return VERR_NOT_IMPLEMENTED;
1935}
1936
1937
1938/**
1939 * Retains a reference for the given control flow graph branch table.
1940 *
1941 * @returns new reference count.
1942 * @param hFlowBranchTbl The branch table handle.
1943 */
1944VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRetain(DBGFFLOWBRANCHTBL hFlowBranchTbl)
1945{
1946 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
1947 AssertPtrReturn(pFlowBranchTbl, UINT32_MAX);
1948
1949 uint32_t cRefs = ASMAtomicIncU32(&pFlowBranchTbl->cRefs);
1950 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pFlowBranchTbl));
1951 return cRefs;
1952}
1953
1954
1955/**
1956 * Releases a given branch table handle.
1957 *
1958 * @returns the new reference count of the given branch table, on 0 it is destroyed.
1959 * @param hFlowBranchTbl The branch table handle.
1960 */
1961VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRelease(DBGFFLOWBRANCHTBL hFlowBranchTbl)
1962{
1963 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
1964 if (!pFlowBranchTbl)
1965 return 0;
1966 AssertPtrReturn(pFlowBranchTbl, UINT32_MAX);
1967
1968 uint32_t cRefs = ASMAtomicDecU32(&pFlowBranchTbl->cRefs);
1969 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pFlowBranchTbl));
1970 if (cRefs == 0)
1971 dbgfR3FlowBranchTblDestroy(pFlowBranchTbl);
1972 return cRefs;
1973}
1974
1975
1976/**
1977 * Return the number of slots the branch table has.
1978 *
1979 * @returns Number of slots in the branch table.
1980 * @param hFlowBranchTbl The branch table handle.
1981 */
1982VMMR3DECL(uint32_t) DBGFR3FlowBranchTblGetSlots(DBGFFLOWBRANCHTBL hFlowBranchTbl)
1983{
1984 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
1985 AssertPtrReturn(pFlowBranchTbl, 0);
1986
1987 return pFlowBranchTbl->cSlots;
1988}
1989
1990
1991/**
1992 * Returns the start address of the branch table in the guest.
1993 *
1994 * @returns Pointer to start address of the branch table (pAddrStart).
1995 * @param hFlowBranchTbl The branch table handle.
1996 * @param pAddrStart Where to store the branch table address.
1997 */
1998VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetStartAddress(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS pAddrStart)
1999{
2000 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
2001 AssertPtrReturn(pFlowBranchTbl, NULL);
2002 AssertPtrReturn(pAddrStart, NULL);
2003
2004 *pAddrStart = pFlowBranchTbl->AddrStart;
2005 return pAddrStart;
2006}
2007
2008
2009/**
2010 * Returns one address in the branch table at the given slot index.
2011 *
2012 * @return Pointer to the address at the given slot in the given branch table.
2013 * @param hFlowBranchTbl The branch table handle.
2014 * @param idxSlot The slot the address should be returned from.
2015 * @param pAddrSlot Where to store the address.
2016 */
2017VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetAddrAtSlot(DBGFFLOWBRANCHTBL hFlowBranchTbl, uint32_t idxSlot, PDBGFADDRESS pAddrSlot)
2018{
2019 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
2020 AssertPtrReturn(pFlowBranchTbl, NULL);
2021 AssertPtrReturn(pAddrSlot, NULL);
2022 AssertReturn(idxSlot < pFlowBranchTbl->cSlots, NULL);
2023
2024 *pAddrSlot = pFlowBranchTbl->aAddresses[idxSlot];
2025 return pAddrSlot;
2026}
2027
2028
2029/**
2030 * Query all addresses contained in the given branch table.
2031 *
2032 * @returns VBox status code.
2033 * @retval VERR_BUFFER_OVERFLOW if there is not enough space in the array to hold all addresses.
2034 * @param hFlowBranchTbl The branch table handle.
2035 * @param paAddrs Where to store the addresses on success.
2036 * @param cAddrs Number of entries the array can hold.
2037 */
2038VMMR3DECL(int) DBGFR3FlowBranchTblQueryAddresses(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS paAddrs, uint32_t cAddrs)
2039{
2040 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
2041 AssertPtrReturn(pFlowBranchTbl, VERR_INVALID_HANDLE);
2042 AssertPtrReturn(paAddrs, VERR_INVALID_POINTER);
2043 AssertReturn(cAddrs > 0, VERR_INVALID_PARAMETER);
2044
2045 if (cAddrs < pFlowBranchTbl->cSlots)
2046 return VERR_BUFFER_OVERFLOW;
2047
2048 memcpy(paAddrs, &pFlowBranchTbl->aAddresses[0], pFlowBranchTbl->cSlots * sizeof(DBGFADDRESS));
2049 return VINF_SUCCESS;
2050}
2051
2052
2053/**
2054 * @callback_method_impl{FNRTSORTCMP}
2055 */
2056static DECLCALLBACK(int) dbgfR3FlowItSortCmp(void const *pvElement1, void const *pvElement2, void *pvUser)
2057{
2058 PDBGFFLOWITORDER penmOrder = (PDBGFFLOWITORDER)pvUser;
2059 PDBGFFLOWBBINT pFlowBb1 = *(PDBGFFLOWBBINT *)pvElement1;
2060 PDBGFFLOWBBINT pFlowBb2 = *(PDBGFFLOWBBINT *)pvElement2;
2061
2062 if (dbgfR3FlowAddrEqual(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
2063 return 0;
2064
2065 if (*penmOrder == DBGFFLOWITORDER_BY_ADDR_LOWEST_FIRST)
2066 {
2067 if (dbgfR3FlowAddrLower(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
2068 return -1;
2069 else
2070 return 1;
2071 }
2072 else
2073 {
2074 if (dbgfR3FlowAddrLower(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
2075 return 1;
2076 else
2077 return -1;
2078 }
2079}
2080
2081
2082/**
2083 * Creates a new iterator for the given control flow graph.
2084 *
2085 * @returns VBox status code.
2086 * @param hFlow The control flow graph handle.
2087 * @param enmOrder The order in which the basic blocks are enumerated.
2088 * @param phFlowIt Where to store the handle to the iterator on success.
2089 */
2090VMMR3DECL(int) DBGFR3FlowItCreate(DBGFFLOW hFlow, DBGFFLOWITORDER enmOrder, PDBGFFLOWIT phFlowIt)
2091{
2092 int rc = VINF_SUCCESS;
2093 PDBGFFLOWINT pFlow = hFlow;
2094 AssertPtrReturn(pFlow, VERR_INVALID_POINTER);
2095 AssertPtrReturn(phFlowIt, VERR_INVALID_POINTER);
2096 AssertReturn(enmOrder > DBGFFLOWITORDER_INVALID && enmOrder < DBGFFLOWITORDER_BREADTH_FIRST,
2097 VERR_INVALID_PARAMETER);
2098 AssertReturn(enmOrder < DBGFFLOWITORDER_DEPTH_FRIST, VERR_NOT_IMPLEMENTED); /** @todo */
2099
2100 PDBGFFLOWITINT pIt = (PDBGFFLOWITINT)RTMemAllocZ(RT_UOFFSETOF_DYN(DBGFFLOWITINT, apBb[pFlow->cBbs]));
2101 if (RT_LIKELY(pIt))
2102 {
2103 DBGFR3FlowRetain(hFlow);
2104 pIt->pFlow = pFlow;
2105 pIt->idxBbNext = 0;
2106 /* Fill the list and then sort. */
2107 uint32_t idxBb = 0;
2108 PDBGFFLOWBBINT pFlowBb;
2109 RTListForEach(&pFlow->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
2110 {
2111 DBGFR3FlowBbRetain(pFlowBb);
2112 pIt->apBb[idxBb++] = pFlowBb;
2113 }
2114
2115 /* Sort the blocks by address. */
2116 RTSortShell(&pIt->apBb[0], pFlow->cBbs, sizeof(PDBGFFLOWBBINT), dbgfR3FlowItSortCmp, &enmOrder);
2117
2118 *phFlowIt = pIt;
2119 }
2120 else
2121 rc = VERR_NO_MEMORY;
2122
2123 return rc;
2124}
2125
2126
2127/**
2128 * Destroys a given control flow graph iterator.
2129 *
2130 * @param hFlowIt The control flow graph iterator handle.
2131 */
2132VMMR3DECL(void) DBGFR3FlowItDestroy(DBGFFLOWIT hFlowIt)
2133{
2134 PDBGFFLOWITINT pIt = hFlowIt;
2135 AssertPtrReturnVoid(pIt);
2136
2137 for (unsigned i = 0; i < pIt->pFlow->cBbs; i++)
2138 DBGFR3FlowBbRelease(pIt->apBb[i]);
2139
2140 DBGFR3FlowRelease(pIt->pFlow);
2141 RTMemFree(pIt);
2142}
2143
2144
2145/**
2146 * Returns the next basic block in the iterator or NULL if there is no
2147 * basic block left.
2148 *
2149 * @returns Handle to the next basic block in the iterator or NULL if the end
2150 * was reached.
2151 * @param hFlowIt The iterator handle.
2152 *
2153 * @note If a valid handle is returned it must be release with DBGFR3FlowBbRelease()
2154 * when not required anymore.
2155 */
2156VMMR3DECL(DBGFFLOWBB) DBGFR3FlowItNext(DBGFFLOWIT hFlowIt)
2157{
2158 PDBGFFLOWITINT pIt = hFlowIt;
2159 AssertPtrReturn(pIt, NULL);
2160
2161 PDBGFFLOWBBINT pFlowBb = NULL;
2162 if (pIt->idxBbNext < pIt->pFlow->cBbs)
2163 {
2164 pFlowBb = pIt->apBb[pIt->idxBbNext++];
2165 DBGFR3FlowBbRetain(pFlowBb);
2166 }
2167
2168 return pFlowBb;
2169}
2170
2171
2172/**
2173 * Resets the given iterator to the beginning.
2174 *
2175 * @returns VBox status code.
2176 * @param hFlowIt The iterator handle.
2177 */
2178VMMR3DECL(int) DBGFR3FlowItReset(DBGFFLOWIT hFlowIt)
2179{
2180 PDBGFFLOWITINT pIt = hFlowIt;
2181 AssertPtrReturn(pIt, VERR_INVALID_HANDLE);
2182
2183 pIt->idxBbNext = 0;
2184 return VINF_SUCCESS;
2185}
2186
2187
2188/**
2189 * @callback_method_impl{FNRTSORTCMP}
2190 */
2191static DECLCALLBACK(int) dbgfR3FlowBranchTblItSortCmp(void const *pvElement1, void const *pvElement2, void *pvUser)
2192{
2193 PDBGFFLOWITORDER penmOrder = (PDBGFFLOWITORDER)pvUser;
2194 PDBGFFLOWBRANCHTBLINT pTbl1 = *(PDBGFFLOWBRANCHTBLINT *)pvElement1;
2195 PDBGFFLOWBRANCHTBLINT pTbl2 = *(PDBGFFLOWBRANCHTBLINT *)pvElement2;
2196
2197 if (dbgfR3FlowAddrEqual(&pTbl1->AddrStart, &pTbl2->AddrStart))
2198 return 0;
2199
2200 if (*penmOrder == DBGFFLOWITORDER_BY_ADDR_LOWEST_FIRST)
2201 {
2202 if (dbgfR3FlowAddrLower(&pTbl1->AddrStart, &pTbl2->AddrStart))
2203 return -1;
2204 else
2205 return 1;
2206 }
2207 else
2208 {
2209 if (dbgfR3FlowAddrLower(&pTbl1->AddrStart, &pTbl2->AddrStart))
2210 return 1;
2211 else
2212 return -1;
2213 }
2214}
2215
2216
2217/**
2218 * Creates a new branch table iterator for the given control flow graph.
2219 *
2220 * @returns VBox status code.
2221 * @param hFlow The control flow graph handle.
2222 * @param enmOrder The order in which the basic blocks are enumerated.
2223 * @param phFlowBranchTblIt Where to store the handle to the iterator on success.
2224 */
2225VMMR3DECL(int) DBGFR3FlowBranchTblItCreate(DBGFFLOW hFlow, DBGFFLOWITORDER enmOrder,
2226 PDBGFFLOWBRANCHTBLIT phFlowBranchTblIt)
2227{
2228 int rc = VINF_SUCCESS;
2229 PDBGFFLOWINT pFlow = hFlow;
2230 AssertPtrReturn(pFlow, VERR_INVALID_POINTER);
2231 AssertPtrReturn(phFlowBranchTblIt, VERR_INVALID_POINTER);
2232 AssertReturn(enmOrder > DBGFFLOWITORDER_INVALID && enmOrder < DBGFFLOWITORDER_BREADTH_FIRST,
2233 VERR_INVALID_PARAMETER);
2234 AssertReturn(enmOrder < DBGFFLOWITORDER_DEPTH_FRIST, VERR_NOT_SUPPORTED);
2235
2236 PDBGFFLOWBRANCHTBLITINT pIt = (PDBGFFLOWBRANCHTBLITINT)RTMemAllocZ(RT_UOFFSETOF_DYN(DBGFFLOWBRANCHTBLITINT,
2237 apBranchTbl[pFlow->cBranchTbls]));
2238 if (RT_LIKELY(pIt))
2239 {
2240 DBGFR3FlowRetain(hFlow);
2241 pIt->pFlow = pFlow;
2242 pIt->idxTblNext = 0;
2243 /* Fill the list and then sort. */
2244 uint32_t idxTbl = 0;
2245 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl;
2246 RTListForEach(&pFlow->LstBranchTbl, pFlowBranchTbl, DBGFFLOWBRANCHTBLINT, NdBranchTbl)
2247 {
2248 DBGFR3FlowBranchTblRetain(pFlowBranchTbl);
2249 pIt->apBranchTbl[idxTbl++] = pFlowBranchTbl;
2250 }
2251
2252 /* Sort the blocks by address. */
2253 RTSortShell(&pIt->apBranchTbl[0], pFlow->cBranchTbls, sizeof(PDBGFFLOWBRANCHTBLINT), dbgfR3FlowBranchTblItSortCmp, &enmOrder);
2254
2255 *phFlowBranchTblIt = pIt;
2256 }
2257 else
2258 rc = VERR_NO_MEMORY;
2259
2260 return rc;
2261}
2262
2263
2264/**
2265 * Destroys a given control flow graph branch table iterator.
2266 *
2267 * @param hFlowBranchTblIt The control flow graph branch table iterator handle.
2268 */
2269VMMR3DECL(void) DBGFR3FlowBranchTblItDestroy(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt)
2270{
2271 PDBGFFLOWBRANCHTBLITINT pIt = hFlowBranchTblIt;
2272 AssertPtrReturnVoid(pIt);
2273
2274 for (unsigned i = 0; i < pIt->pFlow->cBranchTbls; i++)
2275 DBGFR3FlowBranchTblRelease(pIt->apBranchTbl[i]);
2276
2277 DBGFR3FlowRelease(pIt->pFlow);
2278 RTMemFree(pIt);
2279}
2280
2281
2282/**
2283 * Returns the next branch table in the iterator or NULL if there is no
2284 * branch table left.
2285 *
2286 * @returns Handle to the next basic block in the iterator or NULL if the end
2287 * was reached.
2288 * @param hFlowBranchTblIt The iterator handle.
2289 *
2290 * @note If a valid handle is returned it must be release with DBGFR3FlowBranchTblRelease()
2291 * when not required anymore.
2292 */
2293VMMR3DECL(DBGFFLOWBRANCHTBL) DBGFR3FlowBranchTblItNext(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt)
2294{
2295 PDBGFFLOWBRANCHTBLITINT pIt = hFlowBranchTblIt;
2296 AssertPtrReturn(pIt, NULL);
2297
2298 PDBGFFLOWBRANCHTBLINT pTbl = NULL;
2299 if (pIt->idxTblNext < pIt->pFlow->cBranchTbls)
2300 {
2301 pTbl = pIt->apBranchTbl[pIt->idxTblNext++];
2302 DBGFR3FlowBranchTblRetain(pTbl);
2303 }
2304
2305 return pTbl;
2306}
2307
2308
2309/**
2310 * Resets the given iterator to the beginning.
2311 *
2312 * @returns VBox status code.
2313 * @param hFlowBranchTblIt The iterator handle.
2314 */
2315VMMR3DECL(int) DBGFR3FlowBranchTblItReset(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt)
2316{
2317 PDBGFFLOWBRANCHTBLITINT pIt = hFlowBranchTblIt;
2318 AssertPtrReturn(pIt, VERR_INVALID_HANDLE);
2319
2320 pIt->idxTblNext = 0;
2321 return VINF_SUCCESS;
2322}
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