VirtualBox

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

Last change on this file was 103371, checked in by vboxsync, 3 months ago

VMM/DBGFR3Flow: Moved duplicate code for determining the pointer size to an inline function. Mark parfait false positive to avoid re-analysis. bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 83.7 KB
Line 
1/* $Id: DBGFR3Flow.cpp 103371 2024-02-14 20:15:01Z 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#if 0 /* unused */
726/**
727 * Returns the CPU mode based on the given assembler flags.
728 *
729 * @returns CPU mode.
730 * @param pUVM The user mode VM handle.
731 * @param idCpu CPU id for disassembling.
732 * @param fFlagsDisasm The flags used for disassembling.
733 */
734static CPUMMODE dbgfR3FlowGetDisasCpuMode(PUVM pUVM, VMCPUID idCpu, uint32_t fFlagsDisasm)
735{
736 CPUMMODE enmMode = CPUMMODE_INVALID;
737 uint32_t fDisasMode = fFlagsDisasm & DBGF_DISAS_FLAGS_MODE_MASK;
738 if (fDisasMode == DBGF_DISAS_FLAGS_DEFAULT_MODE)
739 enmMode = DBGFR3CpuGetMode(pUVM, idCpu);
740 else if ( fDisasMode == DBGF_DISAS_FLAGS_16BIT_MODE
741 || fDisasMode == DBGF_DISAS_FLAGS_16BIT_REAL_MODE)
742 enmMode = CPUMMODE_REAL;
743 else if (fDisasMode == DBGF_DISAS_FLAGS_32BIT_MODE)
744 enmMode = CPUMMODE_PROTECTED;
745 else if (fDisasMode == DBGF_DISAS_FLAGS_64BIT_MODE)
746 enmMode = CPUMMODE_LONG;
747 else
748 AssertFailed();
749
750 return enmMode;
751}
752#endif
753
754
755/**
756 * Returns the (PC) pointer size based on given assembler flags.
757 *
758 * @returns 2, 4, or 8.
759 * @param pUVM The user mode VM handle.
760 * @param idCpu CPU id for disassembling.
761 * @param fFlagsDisasm The flags used for disassembling.
762 */
763DECLINLINE(uint32_t) dbgfR3FlowGetDisasPtrSize(PUVM pUVM, VMCPUID idCpu, uint32_t fFlagsDisasm)
764{
765 switch (fFlagsDisasm & DBGF_DISAS_FLAGS_MODE_MASK)
766 {
767 case DBGF_DISAS_FLAGS_16BIT_MODE:
768 case DBGF_DISAS_FLAGS_16BIT_REAL_MODE:
769 return sizeof(uint16_t);
770 case DBGF_DISAS_FLAGS_32BIT_MODE:
771 return sizeof(uint32_t);
772 case DBGF_DISAS_FLAGS_64BIT_MODE:
773 return sizeof(uint64_t);
774 default:
775 AssertMsgFailed(("%#x\n", fFlagsDisasm));
776 RT_FALL_THRU();
777 case DBGF_DISAS_FLAGS_DEFAULT_MODE:
778 {
779 CPUMMODE const enmMode = DBGFR3CpuGetMode(pUVM, idCpu);
780 switch (enmMode)
781 {
782 case CPUMMODE_REAL:
783 return sizeof(uint16_t);
784 case CPUMMODE_PROTECTED:
785 case CPUMMODE_ARMV8_AARCH32:
786 return sizeof(uint32_t);
787 default:
788 AssertFailed();
789 RT_FALL_THRU();
790 case CPUMMODE_LONG:
791 case CPUMMODE_ARMV8_AARCH64:
792 return sizeof(uint64_t);
793 }
794 break;
795 }
796 }
797}
798
799
800/**
801 * Searches backwards in the given basic block starting the given instruction index for
802 * a mov instruction with the given register as the target where the constant looks like
803 * a pointer.
804 *
805 * @returns Flag whether a candidate was found.
806 * @param pFlowBb The basic block containing the indirect branch.
807 * @param idxRegTgt The general register the mov targets.
808 * @param cbPtr The pointer size to look for.
809 * @param pUVM The user mode VM handle.
810 * @param idCpu CPU id for disassembling.
811 * @param fFlagsDisasm The flags to use for disassembling.
812 * @param pidxInstrStart The instruction index to start searching for on input,
813 * The last instruction evaluated on output.
814 * @param pAddrDest Where to store the candidate address on success.
815 */
816static bool dbgfR3FlowSearchMovWithConstantPtrSizeBackwards(PDBGFFLOWBBINT pFlowBb, uint8_t idxRegTgt, uint32_t cbPtr,
817 PUVM pUVM, VMCPUID idCpu, uint32_t fFlagsDisasm,
818 uint32_t *pidxInstrStart, PDBGFADDRESS pAddrDest)
819{
820 bool fFound = false;
821 uint32_t idxInstrCur = *pidxInstrStart;
822 uint32_t cInstrCheck = idxInstrCur + 1;
823
824 for (;;)
825 {
826 /** @todo Avoid to disassemble again. */
827 PDBGFFLOWBBINSTR pInstr = &pFlowBb->aInstr[idxInstrCur];
828 DBGFDISSTATE DisState;
829 char szOutput[_4K];
830
831 int rc = dbgfR3DisasInstrStateEx(pUVM, idCpu, &pInstr->AddrInstr, fFlagsDisasm,
832 &szOutput[0], sizeof(szOutput), &DisState);
833 if (RT_SUCCESS(rc))
834 {
835 if ( DisState.pCurInstr->uOpcode == OP_MOV
836 && (DisState.Param1.fUse & (DISUSE_REG_GEN16 | DISUSE_REG_GEN32 | DISUSE_REG_GEN64))
837 && DisState.Param1.x86.Base.idxGenReg == idxRegTgt
838 /*&& DisState.Param1.cb == cbPtr*/
839 && DisState.Param2.x86.cb == cbPtr
840 && (DisState.Param2.fUse & (DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32 | DISUSE_IMMEDIATE64)))
841 {
842 /* Found possible candidate. */
843 fFound = true;
844 if (DBGFADDRESS_IS_FLAT(&pInstr->AddrInstr))
845 DBGFR3AddrFromFlat(pUVM, pAddrDest, DisState.Param2.uValue);
846 else
847 DBGFR3AddrFromSelOff(pUVM, idCpu, pAddrDest, pInstr->AddrInstr.Sel, DisState.Param2.uValue);
848 break;
849 }
850 }
851 else
852 break;
853
854 cInstrCheck--;
855 if (!cInstrCheck)
856 break;
857
858 idxInstrCur--;
859 }
860
861 *pidxInstrStart = idxInstrCur;
862 return fFound;
863}
864
865
866/**
867 * Verifies the given branch table candidate and adds it to the control flow graph on success.
868 *
869 * @returns VBox status code.
870 * @param pThis The flow control graph.
871 * @param pFlowBb The basic block causing the indirect branch.
872 * @param pAddrBranchTbl Address of the branch table location.
873 * @param idxGenRegBase The general register holding the base address.
874 * @param cbPtr Guest pointer size.
875 * @param pUVM The user mode VM handle.
876 * @param idCpu CPU id for disassembling.
877 *
878 * @todo Handle branch tables greater than 4KB (lazy coder).
879 */
880static int dbgfR3FlowBranchTblVerifyAdd(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb, PDBGFADDRESS pAddrBranchTbl,
881 uint8_t idxGenRegBase, uint32_t cbPtr, PUVM pUVM, VMCPUID idCpu)
882{
883 int rc = VINF_SUCCESS;
884 PDBGFFLOWBRANCHTBLINT pBranchTbl = dbgfR3FlowBranchTblFindByAddr(pThis, pAddrBranchTbl);
885
886 if (!pBranchTbl)
887 {
888 uint32_t cSlots = 0;
889 uint8_t abBuf[_4K];
890
891 rc = DBGFR3MemRead(pUVM, idCpu, pAddrBranchTbl, &abBuf[0], sizeof(abBuf));
892 if (RT_SUCCESS(rc))
893 {
894 uint8_t *pbBuf = &abBuf[0];
895 while (pbBuf < &abBuf[0] + sizeof(abBuf))
896 {
897 DBGFADDRESS AddrDest;
898 RTGCUINTPTR GCPtr = cbPtr == sizeof(uint64_t)
899 ? *(uint64_t *)pbBuf
900 : cbPtr == sizeof(uint32_t)
901 ? *(uint32_t *)pbBuf
902 : *(uint16_t *)pbBuf;
903 pbBuf += cbPtr;
904
905 if (DBGFADDRESS_IS_FLAT(pAddrBranchTbl))
906 DBGFR3AddrFromFlat(pUVM, &AddrDest, GCPtr);
907 else
908 DBGFR3AddrFromSelOff(pUVM, idCpu, &AddrDest, pAddrBranchTbl->Sel, GCPtr);
909
910 if (dbgfR3FlowAddrGetDistance(&AddrDest, &pFlowBb->AddrEnd) > _512K)
911 break;
912
913 cSlots++;
914 }
915
916 /* If there are any slots use it. */
917 if (cSlots)
918 {
919 pBranchTbl = dbgfR3FlowBranchTblCreate(pThis, pAddrBranchTbl, idxGenRegBase, cSlots);
920 if (pBranchTbl)
921 {
922 /* Get the addresses. */
923 for (unsigned i = 0; i < cSlots && RT_SUCCESS(rc); i++)
924 {
925 RTGCUINTPTR GCPtr = cbPtr == sizeof(uint64_t)
926 ? *(uint64_t *)&abBuf[i * cbPtr]
927 : cbPtr == sizeof(uint32_t)
928 ? *(uint32_t *)&abBuf[i * cbPtr]
929 : *(uint16_t *)&abBuf[i * cbPtr];
930
931 if (DBGFADDRESS_IS_FLAT(pAddrBranchTbl))
932 DBGFR3AddrFromFlat(pUVM, &pBranchTbl->aAddresses[i], GCPtr);
933 else
934 DBGFR3AddrFromSelOff(pUVM, idCpu, &pBranchTbl->aAddresses[i],
935 pAddrBranchTbl->Sel, GCPtr);
936 rc = dbgfR3FlowBbSuccessorAdd(pThis, &pBranchTbl->aAddresses[i], DBGF_FLOW_BB_F_BRANCH_TABLE,
937 pBranchTbl);
938 }
939 dbgfR3FlowBranchTblLink(pThis, pBranchTbl);
940 }
941 else
942 rc = VERR_NO_MEMORY;
943 }
944 }
945 }
946
947 if (pBranchTbl)
948 pFlowBb->pFlowBranchTbl = pBranchTbl;
949
950 return rc;
951}
952
953
954/**
955 * Checks whether the location for the branch target candidate contains a valid code address.
956 *
957 * @returns VBox status code.
958 * @param pThis The flow control graph.
959 * @param pFlowBb The basic block causing the indirect branch.
960 * @param pAddrBranchTgt Address of the branch target location.
961 * @param idxGenRegBase The general register holding the address of the location.
962 * @param cbPtr Guest pointer size.
963 * @param pUVM The user mode VM handle.
964 * @param idCpu CPU id for disassembling.
965 * @param fBranchTbl Flag whether this is a possible branch table containing multiple
966 * targets.
967 */
968static int dbgfR3FlowCheckBranchTargetLocation(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb, PDBGFADDRESS pAddrBranchTgt,
969 uint8_t idxGenRegBase, uint32_t cbPtr, PUVM pUVM, VMCPUID idCpu, bool fBranchTbl)
970{
971 int rc;
972 if (!fBranchTbl)
973 {
974 RTUINT64U uVal = { 0 };
975 Assert(cbPtr <= sizeof(uVal));
976 rc = DBGFR3MemRead(pUVM, idCpu, pAddrBranchTgt, &uVal, cbPtr); /* (parfait wrong about potential buffer overflow, cbPtr is known) */
977 if (RT_SUCCESS(rc))
978 {
979 DBGFADDRESS AddrTgt;
980 RTGCUINTPTR GCPtr = cbPtr == sizeof(uint64_t) /* (We could use uVal directly on little endian machines.) */
981 ? uVal.au64[0]
982 : cbPtr == sizeof(uint32_t)
983 ? uVal.au32[0]
984 : uVal.au16[0];
985 if (DBGFADDRESS_IS_FLAT(pAddrBranchTgt))
986 DBGFR3AddrFromFlat(pUVM, &AddrTgt, GCPtr);
987 else
988 DBGFR3AddrFromSelOff(pUVM, idCpu, &AddrTgt, pAddrBranchTgt->Sel, GCPtr);
989
990 if (dbgfR3FlowAddrGetDistance(&AddrTgt, &pFlowBb->AddrEnd) <= _128K)
991 {
992 /* Finish the basic block. */
993 pFlowBb->AddrTarget = AddrTgt;
994 rc = dbgfR3FlowBbSuccessorAdd(pThis, &AddrTgt,
995 pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE,
996 pFlowBb->pFlowBranchTbl);
997 }
998 else
999 rc = VERR_NOT_FOUND;
1000 }
1001 }
1002 else
1003 rc = dbgfR3FlowBranchTblVerifyAdd(pThis, pFlowBb, pAddrBranchTgt,
1004 idxGenRegBase, cbPtr, pUVM, idCpu);
1005
1006 return rc;
1007}
1008
1009
1010/**
1011 * Tries to resolve the indirect branch.
1012 *
1013 * @returns VBox status code.
1014 * @param pThis The flow control graph.
1015 * @param pFlowBb The basic block causing the indirect branch.
1016 * @param pUVM The user mode VM handle.
1017 * @param idCpu CPU id for disassembling.
1018 * @param pDisParam The parameter from the disassembler.
1019 * @param fFlagsDisasm Flags for the disassembler.
1020 */
1021static int dbgfR3FlowTryResolveIndirectBranch(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb, PUVM pUVM,
1022 VMCPUID idCpu, PDISOPPARAM pDisParam, uint32_t fFlagsDisasm)
1023{
1024 Assert(dbgfR3FlowBranchTargetIsIndirect(pDisParam));
1025
1026 if (pDisParam->fUse & DISUSE_BASE)
1027 {
1028 uint8_t const idxRegBase = pDisParam->x86.Base.idxGenReg;
1029 uint32_t const cbPtr = dbgfR3FlowGetDisasPtrSize(pUVM, idCpu, fFlagsDisasm);
1030
1031 /* Check that the used register size and the pointer size match. */
1032 if ( ((pDisParam->fUse & DISUSE_REG_GEN16) && cbPtr == sizeof(uint16_t))
1033 || ((pDisParam->fUse & DISUSE_REG_GEN32) && cbPtr == sizeof(uint32_t))
1034 || ((pDisParam->fUse & DISUSE_REG_GEN64) && cbPtr == sizeof(uint64_t)))
1035 {
1036 /*
1037 * Search all instructions backwards until a move to the used general register
1038 * is detected with a constant using the pointer size.
1039 */
1040 uint32_t idxInstrStart = pFlowBb->cInstr - 1 - 1; /* Don't look at the branch. */
1041 bool fCandidateFound = false;
1042 bool fBranchTbl = RT_BOOL(pDisParam->fUse & DISUSE_INDEX);
1043 DBGFADDRESS AddrBranchTgt;
1044 do
1045 {
1046 fCandidateFound = dbgfR3FlowSearchMovWithConstantPtrSizeBackwards(pFlowBb, idxRegBase, cbPtr,
1047 pUVM, idCpu, fFlagsDisasm,
1048 &idxInstrStart, &AddrBranchTgt);
1049 if (fCandidateFound)
1050 {
1051 /* Check that the address is not too far away from the instruction address. */
1052 RTGCUINTPTR offPtr = dbgfR3FlowAddrGetDistance(&AddrBranchTgt, &pFlowBb->AddrEnd);
1053 if (offPtr <= 20 * _1M)
1054 {
1055 /* Read the content at the address and check that it is near this basic block too. */
1056 int rc = dbgfR3FlowCheckBranchTargetLocation(pThis, pFlowBb, &AddrBranchTgt, idxRegBase,
1057 cbPtr, pUVM, idCpu, fBranchTbl);
1058 if (RT_SUCCESS(rc))
1059 break;
1060 fCandidateFound = false;
1061 }
1062
1063 if (idxInstrStart > 0)
1064 idxInstrStart--;
1065 }
1066 } while (idxInstrStart > 0 && !fCandidateFound);
1067 }
1068 else
1069 dbgfR3FlowBbSetError(pFlowBb, VERR_INVALID_STATE,
1070 "The base register size and selected pointer size do not match (fUse=%#x cbPtr=%u)",
1071 pDisParam->fUse, cbPtr);
1072 }
1073
1074 return VINF_SUCCESS;
1075}
1076
1077
1078/**
1079 * Tries to resolve the indirect branch.
1080 *
1081 * @returns VBox status code.
1082 * @param pThis The flow control graph.
1083 * @param pFlowBb The basic block causing the indirect branch.
1084 * @param pUVM The user mode VM handle.
1085 * @param idCpu CPU id for disassembling.
1086 * @param pDisParam The parameter from the disassembler.
1087 * @param fFlagsDisasm Flags for the disassembler.
1088 */
1089static int dbgfR3FlowBbCheckBranchTblCandidate(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb, PUVM pUVM,
1090 VMCPUID idCpu, PDISOPPARAM pDisParam, uint32_t fFlagsDisasm)
1091{
1092 int rc = VINF_SUCCESS;
1093
1094 Assert(pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE && pFlowBb->pFlowBranchTbl);
1095
1096 if (pDisParam->fUse & DISUSE_BASE)
1097 {
1098 uint8_t const idxRegBase = pDisParam->x86.Base.idxGenReg;
1099 uint32_t const cbPtr = dbgfR3FlowGetDisasPtrSize(pUVM, idCpu, fFlagsDisasm);
1100
1101 /* Check that the used register size and the pointer size match. */
1102 if ( ((pDisParam->fUse & DISUSE_REG_GEN16) && cbPtr == sizeof(uint16_t))
1103 || ((pDisParam->fUse & DISUSE_REG_GEN32) && cbPtr == sizeof(uint32_t))
1104 || ((pDisParam->fUse & DISUSE_REG_GEN64) && cbPtr == sizeof(uint64_t)))
1105 {
1106 if (idxRegBase != pFlowBb->pFlowBranchTbl->idxGenRegBase)
1107 {
1108 /* Try to find the new branch table. */
1109 pFlowBb->pFlowBranchTbl = NULL;
1110 rc = dbgfR3FlowTryResolveIndirectBranch(pThis, pFlowBb, pUVM, idCpu, pDisParam, fFlagsDisasm);
1111 }
1112 /** @todo else check that the base register is not modified in this basic block. */
1113 }
1114 else
1115 dbgfR3FlowBbSetError(pFlowBb, VERR_INVALID_STATE,
1116 "The base register size and selected pointer size do not match (fUse=%#x cbPtr=%u)",
1117 pDisParam->fUse, cbPtr);
1118 }
1119 else
1120 dbgfR3FlowBbSetError(pFlowBb, VERR_INVALID_STATE,
1121 "The instruction does not use a register");
1122
1123 return rc;
1124}
1125
1126
1127/**
1128 * Processes and fills one basic block.
1129 *
1130 * @returns VBox status code.
1131 * @param pUVM The user mode VM handle.
1132 * @param idCpu CPU id for disassembling.
1133 * @param pThis The control flow graph to populate.
1134 * @param pFlowBb The basic block to fill.
1135 * @param cbDisasmMax The maximum amount to disassemble.
1136 * @param fFlags Combination of DBGF_DISAS_FLAGS_*.
1137 */
1138static int dbgfR3FlowBbProcess(PUVM pUVM, VMCPUID idCpu, PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb,
1139 uint32_t cbDisasmMax, uint32_t fFlags)
1140{
1141 int rc = VINF_SUCCESS;
1142 uint32_t cbDisasmLeft = cbDisasmMax ? cbDisasmMax : UINT32_MAX;
1143 DBGFADDRESS AddrDisasm = pFlowBb->AddrEnd;
1144
1145 Assert(pFlowBb->fFlags & DBGF_FLOW_BB_F_EMPTY);
1146
1147 /*
1148 * Disassemble instruction by instruction until we get a conditional or
1149 * unconditional jump or some sort of return.
1150 */
1151 while ( cbDisasmLeft
1152 && RT_SUCCESS(rc))
1153 {
1154 DBGFDISSTATE DisState;
1155 char szOutput[_4K];
1156
1157 /*
1158 * Before disassembling we have to check whether the address belongs
1159 * to another basic block and stop here.
1160 */
1161 if ( !(pFlowBb->fFlags & DBGF_FLOW_BB_F_EMPTY)
1162 && dbgfR3FlowHasBbWithStartAddr(pThis, &AddrDisasm))
1163 {
1164 pFlowBb->AddrTarget = AddrDisasm;
1165 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND;
1166 break;
1167 }
1168
1169 rc = dbgfR3DisasInstrStateEx(pUVM, idCpu, &AddrDisasm, fFlags,
1170 &szOutput[0], sizeof(szOutput), &DisState);
1171 if (RT_SUCCESS(rc))
1172 {
1173 if ( pThis->fFlags & DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB
1174 && DisState.pCurInstr->uOpcode == OP_CALL
1175 && !(pFlowBb->fFlags & DBGF_FLOW_BB_F_EMPTY))
1176 {
1177 /*
1178 * If the basic block is not empty, the basic block is terminated and the successor is added
1179 * which will contain the call instruction.
1180 */
1181 pFlowBb->AddrTarget = AddrDisasm;
1182 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND;
1183 rc = dbgfR3FlowBbSuccessorAdd(pThis, &AddrDisasm,
1184 (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
1185 pFlowBb->pFlowBranchTbl);
1186 if (RT_FAILURE(rc))
1187 dbgfR3FlowBbSetError(pFlowBb, rc, "Adding successor blocks failed with %Rrc", rc);
1188 break;
1189 }
1190
1191 pFlowBb->fFlags &= ~DBGF_FLOW_BB_F_EMPTY;
1192 cbDisasmLeft -= DisState.cbInstr;
1193
1194 if (pFlowBb->cInstr == pFlowBb->cInstrMax)
1195 {
1196 /* Reallocate. */
1197 RTListNodeRemove(&pFlowBb->NdFlowBb);
1198 PDBGFFLOWBBINT pFlowBbNew = (PDBGFFLOWBBINT)RTMemRealloc(pFlowBb,
1199 RT_UOFFSETOF_DYN(DBGFFLOWBBINT, aInstr[pFlowBb->cInstrMax + 10]));
1200 if (pFlowBbNew)
1201 {
1202 pFlowBbNew->cInstrMax += 10;
1203 pFlowBb = pFlowBbNew;
1204 }
1205 else
1206 rc = VERR_NO_MEMORY;
1207 RTListAppend(&pThis->LstFlowBb, &pFlowBb->NdFlowBb);
1208 }
1209
1210 if (RT_SUCCESS(rc))
1211 {
1212 PDBGFFLOWBBINSTR pInstr = &pFlowBb->aInstr[pFlowBb->cInstr];
1213
1214 pInstr->AddrInstr = AddrDisasm;
1215 pInstr->cbInstr = DisState.cbInstr;
1216 pInstr->pszInstr = RTStrCacheEnter(pThis->hStrCacheInstr, &szOutput[0]);
1217 pFlowBb->cInstr++;
1218
1219 pFlowBb->AddrEnd = AddrDisasm;
1220 DBGFR3AddrAdd(&pFlowBb->AddrEnd, pInstr->cbInstr - 1);
1221 DBGFR3AddrAdd(&AddrDisasm, pInstr->cbInstr);
1222
1223 /*
1224 * Check control flow instructions and create new basic blocks
1225 * marking the current one as complete.
1226 */
1227 if (DisState.pCurInstr->fOpType & DISOPTYPE_CONTROLFLOW)
1228 {
1229 uint16_t uOpc = DisState.pCurInstr->uOpcode;
1230
1231 if (uOpc == OP_CALL)
1232 pThis->cCallInsns++;
1233
1234 if ( uOpc == OP_RETN || uOpc == OP_RETF || uOpc == OP_IRET
1235 || uOpc == OP_SYSEXIT || uOpc == OP_SYSRET)
1236 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_EXIT;
1237 else if (uOpc == OP_JMP)
1238 {
1239 Assert(DisState.pCurInstr->fOpType & DISOPTYPE_UNCOND_CONTROLFLOW);
1240
1241 if (dbgfR3FlowBranchTargetIsIndirect(&DisState.Param1))
1242 {
1243 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP;
1244
1245 if (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE)
1246 {
1247 Assert(pThis->fFlags & DBGF_FLOW_CREATE_F_TRY_RESOLVE_INDIRECT_BRANCHES);
1248
1249 /*
1250 * This basic block was already discovered by parsing a jump table and
1251 * there should be a candidate for the branch table. Check whether it uses the
1252 * same branch table.
1253 */
1254 rc = dbgfR3FlowBbCheckBranchTblCandidate(pThis, pFlowBb, pUVM, idCpu,
1255 &DisState.Param1, fFlags);
1256 }
1257 else
1258 {
1259 if (pThis->fFlags & DBGF_FLOW_CREATE_F_TRY_RESOLVE_INDIRECT_BRANCHES)
1260 rc = dbgfR3FlowTryResolveIndirectBranch(pThis, pFlowBb, pUVM, idCpu,
1261 &DisState.Param1, fFlags);
1262 else
1263 dbgfR3FlowBbSetError(pFlowBb, VERR_NOT_SUPPORTED,
1264 "Detected indirect branch and resolving it not being enabled");
1265 }
1266 }
1267 else
1268 {
1269 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND_JMP;
1270
1271 /* Create one new basic block with the jump target address. */
1272 rc = dbgfR3FlowQueryDirectBranchTarget(pUVM, idCpu, &DisState.Param1, &pInstr->AddrInstr, pInstr->cbInstr,
1273 RT_BOOL(DisState.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW),
1274 &pFlowBb->AddrTarget);
1275 if (RT_SUCCESS(rc))
1276 rc = dbgfR3FlowBbSuccessorAdd(pThis, &pFlowBb->AddrTarget,
1277 (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
1278 pFlowBb->pFlowBranchTbl);
1279 }
1280 }
1281 else if (uOpc != OP_CALL)
1282 {
1283 Assert(DisState.pCurInstr->fOpType & DISOPTYPE_COND_CONTROLFLOW);
1284 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_COND;
1285
1286 /*
1287 * Create two new basic blocks, one with the jump target address
1288 * and one starting after the current instruction.
1289 */
1290 rc = dbgfR3FlowBbSuccessorAdd(pThis, &AddrDisasm,
1291 (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
1292 pFlowBb->pFlowBranchTbl);
1293 if (RT_SUCCESS(rc))
1294 {
1295 rc = dbgfR3FlowQueryDirectBranchTarget(pUVM, idCpu, &DisState.Param1, &pInstr->AddrInstr, pInstr->cbInstr,
1296 RT_BOOL(DisState.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW),
1297 &pFlowBb->AddrTarget);
1298 if (RT_SUCCESS(rc))
1299 rc = dbgfR3FlowBbSuccessorAdd(pThis, &pFlowBb->AddrTarget,
1300 (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
1301 pFlowBb->pFlowBranchTbl);
1302 }
1303 }
1304 else if (pThis->fFlags & DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB)
1305 {
1306 pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND;
1307 pFlowBb->fFlags |= DBGF_FLOW_BB_F_CALL_INSN;
1308
1309 /* Add new basic block coming after the call instruction. */
1310 rc = dbgfR3FlowBbSuccessorAdd(pThis, &AddrDisasm,
1311 (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
1312 pFlowBb->pFlowBranchTbl);
1313 if ( RT_SUCCESS(rc)
1314 && !dbgfR3FlowBranchTargetIsIndirect(&DisState.Param1))
1315 {
1316 /* Resolve the branch target. */
1317 rc = dbgfR3FlowQueryDirectBranchTarget(pUVM, idCpu, &DisState.Param1, &pInstr->AddrInstr, pInstr->cbInstr,
1318 RT_BOOL(DisState.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW),
1319 &pFlowBb->AddrTarget);
1320 if (RT_SUCCESS(rc))
1321 pFlowBb->fFlags |= DBGF_FLOW_BB_F_CALL_INSN_TARGET_KNOWN;
1322 }
1323 }
1324
1325 if (RT_FAILURE(rc))
1326 dbgfR3FlowBbSetError(pFlowBb, rc, "Adding successor blocks failed with %Rrc", rc);
1327
1328 /* Quit disassembling. */
1329 if ( ( uOpc != OP_CALL
1330 || (pThis->fFlags & DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB))
1331 || RT_FAILURE(rc))
1332 break;
1333 }
1334 }
1335 else
1336 dbgfR3FlowBbSetError(pFlowBb, rc, "Increasing basic block failed with %Rrc", rc);
1337 }
1338 else
1339 dbgfR3FlowBbSetError(pFlowBb, rc, "Disassembling the instruction failed with %Rrc", rc);
1340 }
1341
1342 return VINF_SUCCESS;
1343}
1344
1345/**
1346 * Populate all empty basic blocks.
1347 *
1348 * @returns VBox status code.
1349 * @param pUVM The user mode VM handle.
1350 * @param idCpu CPU id for disassembling.
1351 * @param pThis The control flow graph to populate.
1352 * @param cbDisasmMax The maximum amount to disassemble.
1353 * @param fFlags Combination of DBGF_DISAS_FLAGS_*.
1354 */
1355static int dbgfR3FlowPopulate(PUVM pUVM, VMCPUID idCpu, PDBGFFLOWINT pThis, uint32_t cbDisasmMax, uint32_t fFlags)
1356{
1357 int rc = VINF_SUCCESS;
1358 PDBGFFLOWBBINT pFlowBb = dbgfR3FlowGetUnpopulatedBb(pThis);
1359
1360 while (pFlowBb != NULL)
1361 {
1362 rc = dbgfR3FlowBbProcess(pUVM, idCpu, pThis, pFlowBb, cbDisasmMax, fFlags);
1363 if (RT_FAILURE(rc))
1364 break;
1365
1366 pFlowBb = dbgfR3FlowGetUnpopulatedBb(pThis);
1367 }
1368
1369 return rc;
1370}
1371
1372/**
1373 * Creates a new control flow graph from the given start address.
1374 *
1375 * @returns VBox status code.
1376 * @param pUVM The user mode VM handle.
1377 * @param idCpu CPU id for disassembling.
1378 * @param pAddressStart Where to start creating the control flow graph.
1379 * @param cbDisasmMax Limit the amount of bytes to disassemble, 0 for no limit.
1380 * @param fFlagsFlow Combination of DBGF_FLOW_CREATE_F_* to control the creation of the flow graph.
1381 * @param fFlagsDisasm Combination of DBGF_DISAS_FLAGS_* controlling the style of the disassembled
1382 * instructions.
1383 * @param phFlow Where to store the handle to the control flow graph on success.
1384 */
1385VMMR3DECL(int) DBGFR3FlowCreate(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddressStart, uint32_t cbDisasmMax,
1386 uint32_t fFlagsFlow, uint32_t fFlagsDisasm, PDBGFFLOW phFlow)
1387{
1388 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1389 PVM pVM = pUVM->pVM;
1390 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1391 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
1392 AssertPtrReturn(pAddressStart, VERR_INVALID_POINTER);
1393 AssertReturn(!(fFlagsDisasm & ~DBGF_DISAS_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
1394 AssertReturn((fFlagsDisasm & DBGF_DISAS_FLAGS_MODE_MASK) <= DBGF_DISAS_FLAGS_64BIT_MODE, VERR_INVALID_PARAMETER);
1395
1396 /* Create the control flow graph container. */
1397 int rc = VINF_SUCCESS;
1398 PDBGFFLOWINT pThis = (PDBGFFLOWINT)RTMemAllocZ(sizeof(DBGFFLOWINT));
1399 if (RT_LIKELY(pThis))
1400 {
1401 rc = RTStrCacheCreate(&pThis->hStrCacheInstr, "DBGFFLOW");
1402 if (RT_SUCCESS(rc))
1403 {
1404 pThis->cRefs = 1;
1405 pThis->cRefsBb = 0;
1406 pThis->cBbs = 0;
1407 pThis->cBranchTbls = 0;
1408 pThis->cCallInsns = 0;
1409 pThis->fFlags = fFlagsFlow;
1410 RTListInit(&pThis->LstFlowBb);
1411 RTListInit(&pThis->LstBranchTbl);
1412 /* Create the entry basic block and start the work. */
1413
1414 PDBGFFLOWBBINT pFlowBb = dbgfR3FlowBbCreate(pThis, pAddressStart, DBGF_FLOW_BB_F_ENTRY, 10);
1415 if (RT_LIKELY(pFlowBb))
1416 {
1417 dbgfR3FlowLink(pThis, pFlowBb);
1418 rc = dbgfR3FlowPopulate(pUVM, idCpu, pThis, cbDisasmMax, fFlagsDisasm);
1419 if (RT_SUCCESS(rc))
1420 {
1421 *phFlow = pThis;
1422 return VINF_SUCCESS;
1423 }
1424 }
1425 else
1426 rc = VERR_NO_MEMORY;
1427 }
1428
1429 ASMAtomicDecU32(&pThis->cRefs);
1430 dbgfR3FlowDestroy(pThis);
1431 }
1432 else
1433 rc = VERR_NO_MEMORY;
1434
1435 return rc;
1436}
1437
1438
1439/**
1440 * Retains the control flow graph handle.
1441 *
1442 * @returns Current reference count.
1443 * @param hFlow The control flow graph handle to retain.
1444 */
1445VMMR3DECL(uint32_t) DBGFR3FlowRetain(DBGFFLOW hFlow)
1446{
1447 PDBGFFLOWINT pThis = hFlow;
1448 AssertPtrReturn(pThis, UINT32_MAX);
1449
1450 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1451 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1452 return cRefs;
1453}
1454
1455
1456/**
1457 * Releases the control flow graph handle.
1458 *
1459 * @returns Current reference count, on 0 the control flow graph will be destroyed.
1460 * @param hFlow The control flow graph handle to release.
1461 */
1462VMMR3DECL(uint32_t) DBGFR3FlowRelease(DBGFFLOW hFlow)
1463{
1464 PDBGFFLOWINT pThis = hFlow;
1465 if (!pThis)
1466 return 0;
1467 AssertPtrReturn(pThis, UINT32_MAX);
1468
1469 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1470 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1471 if (cRefs == 0)
1472 dbgfR3FlowDestroy(pThis);
1473 return cRefs;
1474}
1475
1476
1477/**
1478 * Queries the basic block denoting the entry point into the control flow graph.
1479 *
1480 * @returns VBox status code.
1481 * @param hFlow The control flow graph handle.
1482 * @param phFlowBb Where to store the basic block handle on success.
1483 */
1484VMMR3DECL(int) DBGFR3FlowQueryStartBb(DBGFFLOW hFlow, PDBGFFLOWBB phFlowBb)
1485{
1486 PDBGFFLOWINT pThis = hFlow;
1487 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1488
1489 PDBGFFLOWBBINT pFlowBb;
1490 RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
1491 {
1492 if (pFlowBb->fFlags & DBGF_FLOW_BB_F_ENTRY)
1493 {
1494 *phFlowBb = pFlowBb;
1495 return VINF_SUCCESS;
1496 }
1497 }
1498
1499 AssertFailed(); /* Should never get here. */
1500 return VERR_INTERNAL_ERROR;
1501}
1502
1503
1504/**
1505 * Queries a basic block in the given control flow graph which covers the given
1506 * address.
1507 *
1508 * @returns VBox status code.
1509 * @retval VERR_NOT_FOUND if there is no basic block intersecting with the address.
1510 * @param hFlow The control flow graph handle.
1511 * @param pAddr The address to look for.
1512 * @param phFlowBb Where to store the basic block handle on success.
1513 */
1514VMMR3DECL(int) DBGFR3FlowQueryBbByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBB phFlowBb)
1515{
1516 PDBGFFLOWINT pThis = hFlow;
1517 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1518 AssertPtrReturn(pAddr, VERR_INVALID_POINTER);
1519 AssertPtrReturn(phFlowBb, VERR_INVALID_POINTER);
1520
1521 PDBGFFLOWBBINT pFlowBb;
1522 RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
1523 {
1524 if (dbgfR3FlowAddrIntersect(pFlowBb, pAddr))
1525 {
1526 DBGFR3FlowBbRetain(pFlowBb);
1527 *phFlowBb = pFlowBb;
1528 return VINF_SUCCESS;
1529 }
1530 }
1531
1532 return VERR_NOT_FOUND;
1533}
1534
1535
1536/**
1537 * Queries a branch table in the given control flow graph by the given address.
1538 *
1539 * @returns VBox status code.
1540 * @retval VERR_NOT_FOUND if there is no branch table with the given address.
1541 * @param hFlow The control flow graph handle.
1542 * @param pAddr The address of the branch table.
1543 * @param phFlowBranchTbl Where to store the handle to branch table on success.
1544 *
1545 * @note Call DBGFR3FlowBranchTblRelease() when the handle is not required anymore.
1546 */
1547VMMR3DECL(int) DBGFR3FlowQueryBranchTblByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBRANCHTBL phFlowBranchTbl)
1548{
1549 PDBGFFLOWINT pThis = hFlow;
1550 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1551 AssertPtrReturn(pAddr, VERR_INVALID_POINTER);
1552 AssertPtrReturn(phFlowBranchTbl, VERR_INVALID_POINTER);
1553
1554 PDBGFFLOWBRANCHTBLINT pBranchTbl = dbgfR3FlowBranchTblFindByAddr(pThis, pAddr);
1555 if (pBranchTbl)
1556 {
1557 DBGFR3FlowBranchTblRetain(pBranchTbl);
1558 *phFlowBranchTbl = pBranchTbl;
1559 return VINF_SUCCESS;
1560 }
1561
1562 return VERR_NOT_FOUND;
1563}
1564
1565
1566/**
1567 * Returns the number of basic blcoks inside the control flow graph.
1568 *
1569 * @returns Number of basic blocks.
1570 * @param hFlow The control flow graph handle.
1571 */
1572VMMR3DECL(uint32_t) DBGFR3FlowGetBbCount(DBGFFLOW hFlow)
1573{
1574 PDBGFFLOWINT pThis = hFlow;
1575 AssertPtrReturn(pThis, 0);
1576
1577 return pThis->cBbs;
1578}
1579
1580
1581/**
1582 * Returns the number of branch tables inside the control flow graph.
1583 *
1584 * @returns Number of basic blocks.
1585 * @param hFlow The control flow graph handle.
1586 */
1587VMMR3DECL(uint32_t) DBGFR3FlowGetBranchTblCount(DBGFFLOW hFlow)
1588{
1589 PDBGFFLOWINT pThis = hFlow;
1590 AssertPtrReturn(pThis, 0);
1591
1592 return pThis->cBranchTbls;
1593}
1594
1595
1596/**
1597 * Returns the number of call instructions encountered in the given
1598 * control flow graph.
1599 *
1600 * @returns Number of call instructions.
1601 * @param hFlow The control flow graph handle.
1602 */
1603VMMR3DECL(uint32_t) DBGFR3FlowGetCallInsnCount(DBGFFLOW hFlow)
1604{
1605 PDBGFFLOWINT pThis = hFlow;
1606 AssertPtrReturn(pThis, 0);
1607
1608 return pThis->cCallInsns;
1609}
1610
1611
1612/**
1613 * Retains the basic block handle.
1614 *
1615 * @returns Current reference count.
1616 * @param hFlowBb The basic block handle to retain.
1617 */
1618VMMR3DECL(uint32_t) DBGFR3FlowBbRetain(DBGFFLOWBB hFlowBb)
1619{
1620 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1621 AssertPtrReturn(pFlowBb, UINT32_MAX);
1622
1623 uint32_t cRefs = ASMAtomicIncU32(&pFlowBb->cRefs);
1624 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p %d\n", cRefs, pFlowBb, pFlowBb->enmEndType));
1625 return cRefs;
1626}
1627
1628
1629/**
1630 * Releases the basic block handle.
1631 *
1632 * @returns Current reference count, on 0 the basic block will be destroyed.
1633 * @param hFlowBb The basic block handle to release.
1634 */
1635VMMR3DECL(uint32_t) DBGFR3FlowBbRelease(DBGFFLOWBB hFlowBb)
1636{
1637 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1638 if (!pFlowBb)
1639 return 0;
1640
1641 return dbgfR3FlowBbReleaseInt(pFlowBb, true /* fMayDestroyFlow */);
1642}
1643
1644
1645/**
1646 * Returns the start address of the basic block.
1647 *
1648 * @returns Pointer to DBGF adress containing the start address of the basic block.
1649 * @param hFlowBb The basic block handle.
1650 * @param pAddrStart Where to store the start address of the basic block.
1651 */
1652VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetStartAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrStart)
1653{
1654 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1655 AssertPtrReturn(pFlowBb, NULL);
1656 AssertPtrReturn(pAddrStart, NULL);
1657
1658 *pAddrStart = pFlowBb->AddrStart;
1659 return pAddrStart;
1660}
1661
1662
1663/**
1664 * Returns the end address of the basic block (inclusive).
1665 *
1666 * @returns Pointer to DBGF adress containing the end address of the basic block.
1667 * @param hFlowBb The basic block handle.
1668 * @param pAddrEnd Where to store the end address of the basic block.
1669 */
1670VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetEndAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrEnd)
1671{
1672 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1673 AssertPtrReturn(pFlowBb, NULL);
1674 AssertPtrReturn(pAddrEnd, NULL);
1675
1676 *pAddrEnd = pFlowBb->AddrEnd;
1677 return pAddrEnd;
1678}
1679
1680
1681/**
1682 * Returns the address the last instruction in the basic block branches to.
1683 *
1684 * @returns Pointer to DBGF adress containing the branch address of the basic block.
1685 * @param hFlowBb The basic block handle.
1686 * @param pAddrTarget Where to store the branch address of the basic block.
1687 *
1688 * @note This is only valid for unconditional or conditional branches, or for a basic block
1689 * containing only a call instruction when DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB was given
1690 * during creation and the branch target could be deduced as indicated by the DBGF_FLOW_BB_F_CALL_INSN_TARGET_KNOWN
1691 * flag for the basic block. This method will assert for every other basic block type.
1692 * @note For indirect unconditional branches using a branch table this will return the start address
1693 * of the branch table.
1694 */
1695VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetBranchAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrTarget)
1696{
1697 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1698 AssertPtrReturn(pFlowBb, NULL);
1699 AssertPtrReturn(pAddrTarget, NULL);
1700 AssertReturn( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_JMP
1701 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_COND
1702 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP
1703 || ( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND
1704 && (pFlowBb->fFlags & DBGF_FLOW_BB_F_CALL_INSN_TARGET_KNOWN)),
1705 NULL);
1706
1707 if ( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP
1708 && pFlowBb->pFlowBranchTbl)
1709 *pAddrTarget = pFlowBb->pFlowBranchTbl->AddrStart;
1710 else
1711 *pAddrTarget = pFlowBb->AddrTarget;
1712 return pAddrTarget;
1713}
1714
1715
1716/**
1717 * Returns the address of the next block following this one in the instruction stream.
1718 * (usually end address + 1).
1719 *
1720 * @returns Pointer to DBGF adress containing the following address of the basic block.
1721 * @param hFlowBb The basic block handle.
1722 * @param pAddrFollow Where to store the following address of the basic block.
1723 *
1724 * @note This is only valid for conditional branches and if the last instruction in the
1725 * given basic block doesn't change the control flow but the blocks were split
1726 * because the successor is referenced by multiple other blocks as an entry point.
1727 */
1728VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetFollowingAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrFollow)
1729{
1730 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1731 AssertPtrReturn(pFlowBb, NULL);
1732 AssertPtrReturn(pAddrFollow, NULL);
1733 AssertReturn( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND
1734 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_COND,
1735 NULL);
1736
1737 *pAddrFollow = pFlowBb->AddrEnd;
1738 DBGFR3AddrAdd(pAddrFollow, 1);
1739 return pAddrFollow;
1740}
1741
1742
1743/**
1744 * Returns the type of the last instruction in the basic block.
1745 *
1746 * @returns Last instruction type.
1747 * @param hFlowBb The basic block handle.
1748 */
1749VMMR3DECL(DBGFFLOWBBENDTYPE) DBGFR3FlowBbGetType(DBGFFLOWBB hFlowBb)
1750{
1751 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1752 AssertPtrReturn(pFlowBb, DBGFFLOWBBENDTYPE_INVALID);
1753
1754 return pFlowBb->enmEndType;
1755}
1756
1757
1758/**
1759 * Get the number of instructions contained in the basic block.
1760 *
1761 * @returns Number of instructions in the basic block.
1762 * @param hFlowBb The basic block handle.
1763 */
1764VMMR3DECL(uint32_t) DBGFR3FlowBbGetInstrCount(DBGFFLOWBB hFlowBb)
1765{
1766 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1767 AssertPtrReturn(pFlowBb, 0);
1768
1769 return pFlowBb->cInstr;
1770}
1771
1772
1773/**
1774 * Get flags for the given basic block.
1775 *
1776 * @returns Combination of DBGF_FLOW_BB_F_*
1777 * @param hFlowBb The basic block handle.
1778 */
1779VMMR3DECL(uint32_t) DBGFR3FlowBbGetFlags(DBGFFLOWBB hFlowBb)
1780{
1781 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1782 AssertPtrReturn(pFlowBb, 0);
1783
1784 return pFlowBb->fFlags;
1785}
1786
1787
1788/**
1789 * Queries the branch table used if the given basic block ends with an indirect branch
1790 * and has a branch table referenced.
1791 *
1792 * @returns VBox status code.
1793 * @param hFlowBb The basic block handle.
1794 * @param phBranchTbl Where to store the branch table handle on success.
1795 *
1796 * @note Release the branch table reference with DBGFR3FlowBranchTblRelease() when not required
1797 * anymore.
1798 */
1799VMMR3DECL(int) DBGFR3FlowBbQueryBranchTbl(DBGFFLOWBB hFlowBb, PDBGFFLOWBRANCHTBL phBranchTbl)
1800{
1801 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1802 AssertPtrReturn(pFlowBb, VERR_INVALID_HANDLE);
1803 AssertReturn(pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP, VERR_INVALID_STATE);
1804 AssertPtrReturn(pFlowBb->pFlowBranchTbl, VERR_INVALID_STATE);
1805 AssertPtrReturn(phBranchTbl, VERR_INVALID_POINTER);
1806
1807 DBGFR3FlowBranchTblRetain(pFlowBb->pFlowBranchTbl);
1808 *phBranchTbl = pFlowBb->pFlowBranchTbl;
1809 return VINF_SUCCESS;
1810}
1811
1812
1813/**
1814 * Returns the error status and message if the given basic block has an error.
1815 *
1816 * @returns VBox status code of the error for the basic block.
1817 * @param hFlowBb The basic block handle.
1818 * @param ppszErr Where to store the pointer to the error message - optional.
1819 */
1820VMMR3DECL(int) DBGFR3FlowBbQueryError(DBGFFLOWBB hFlowBb, const char **ppszErr)
1821{
1822 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1823 AssertPtrReturn(pFlowBb, VERR_INVALID_HANDLE);
1824
1825 if (ppszErr)
1826 *ppszErr = pFlowBb->pszErr;
1827
1828 return pFlowBb->rcError;
1829}
1830
1831
1832/**
1833 * Store the disassembled instruction as a string in the given output buffer.
1834 *
1835 * @returns VBox status code.
1836 * @param hFlowBb The basic block handle.
1837 * @param idxInstr The instruction to query.
1838 * @param pAddrInstr Where to store the guest instruction address on success, optional.
1839 * @param pcbInstr Where to store the instruction size on success, optional.
1840 * @param ppszInstr Where to store the pointer to the disassembled instruction string, optional.
1841 */
1842VMMR3DECL(int) DBGFR3FlowBbQueryInstr(DBGFFLOWBB hFlowBb, uint32_t idxInstr, PDBGFADDRESS pAddrInstr,
1843 uint32_t *pcbInstr, const char **ppszInstr)
1844{
1845 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1846 AssertPtrReturn(pFlowBb, VERR_INVALID_POINTER);
1847 AssertReturn(idxInstr < pFlowBb->cInstr, VERR_INVALID_PARAMETER);
1848
1849 if (pAddrInstr)
1850 *pAddrInstr = pFlowBb->aInstr[idxInstr].AddrInstr;
1851 if (pcbInstr)
1852 *pcbInstr = pFlowBb->aInstr[idxInstr].cbInstr;
1853 if (ppszInstr)
1854 *ppszInstr = pFlowBb->aInstr[idxInstr].pszInstr;
1855
1856 return VINF_SUCCESS;
1857}
1858
1859
1860/**
1861 * Queries the successors of the basic block.
1862 *
1863 * @returns VBox status code.
1864 * @param hFlowBb The basic block handle.
1865 * @param phFlowBbFollow Where to store the handle to the basic block following
1866 * this one (optional).
1867 * @param phFlowBbTarget Where to store the handle to the basic block being the
1868 * branch target for this one (optional).
1869 */
1870VMMR3DECL(int) DBGFR3FlowBbQuerySuccessors(DBGFFLOWBB hFlowBb, PDBGFFLOWBB phFlowBbFollow, PDBGFFLOWBB phFlowBbTarget)
1871{
1872 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1873 AssertPtrReturn(pFlowBb, VERR_INVALID_POINTER);
1874
1875 if ( phFlowBbFollow
1876 && ( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND
1877 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_COND))
1878 {
1879 DBGFADDRESS AddrStart = pFlowBb->AddrEnd;
1880 DBGFR3AddrAdd(&AddrStart, 1);
1881 int rc = DBGFR3FlowQueryBbByAddress(pFlowBb->pFlow, &AddrStart, phFlowBbFollow);
1882 AssertRC(rc);
1883 }
1884
1885 if ( phFlowBbTarget
1886 && ( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_JMP
1887 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_COND))
1888 {
1889 int rc = DBGFR3FlowQueryBbByAddress(pFlowBb->pFlow, &pFlowBb->AddrTarget, phFlowBbTarget);
1890 AssertRC(rc);
1891 }
1892
1893 return VINF_SUCCESS;
1894}
1895
1896
1897/**
1898 * Returns the number of basic blocks referencing this basic block as a target.
1899 *
1900 * @returns Number of other basic blocks referencing this one.
1901 * @param hFlowBb The basic block handle.
1902 *
1903 * @note If the given basic block references itself (loop, etc.) this will be counted as well.
1904 */
1905VMMR3DECL(uint32_t) DBGFR3FlowBbGetRefBbCount(DBGFFLOWBB hFlowBb)
1906{
1907 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1908 AssertPtrReturn(pFlowBb, 0);
1909
1910 uint32_t cRefsBb = 0;
1911 PDBGFFLOWBBINT pFlowBbCur;
1912 RTListForEach(&pFlowBb->pFlow->LstFlowBb, pFlowBbCur, DBGFFLOWBBINT, NdFlowBb)
1913 {
1914 if (pFlowBbCur->fFlags & DBGF_FLOW_BB_F_INCOMPLETE_ERR)
1915 continue;
1916
1917 if ( pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_UNCOND
1918 || pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_COND)
1919 {
1920 DBGFADDRESS AddrStart = pFlowBb->AddrEnd;
1921 DBGFR3AddrAdd(&AddrStart, 1);
1922 if (dbgfR3FlowAddrEqual(&pFlowBbCur->AddrStart, &AddrStart))
1923 cRefsBb++;
1924 }
1925
1926 if ( ( pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_JMP
1927 || pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_COND)
1928 && dbgfR3FlowAddrEqual(&pFlowBbCur->AddrStart, &pFlowBb->AddrTarget))
1929 cRefsBb++;
1930 }
1931 return cRefsBb;
1932}
1933
1934
1935/**
1936 * Returns the basic block handles referencing the given basic block.
1937 *
1938 * @returns VBox status code.
1939 * @retval VERR_BUFFER_OVERFLOW if the array can't hold all the basic blocks.
1940 * @param hFlowBb The basic block handle.
1941 * @param paFlowBbRef Pointer to the array containing the referencing basic block handles on success.
1942 * @param cRef Number of entries in the given array.
1943 */
1944VMMR3DECL(int) DBGFR3FlowBbGetRefBb(DBGFFLOWBB hFlowBb, PDBGFFLOWBB paFlowBbRef, uint32_t cRef)
1945{
1946 RT_NOREF3(hFlowBb, paFlowBbRef, cRef);
1947 return VERR_NOT_IMPLEMENTED;
1948}
1949
1950
1951/**
1952 * Retains a reference for the given control flow graph branch table.
1953 *
1954 * @returns new reference count.
1955 * @param hFlowBranchTbl The branch table handle.
1956 */
1957VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRetain(DBGFFLOWBRANCHTBL hFlowBranchTbl)
1958{
1959 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
1960 AssertPtrReturn(pFlowBranchTbl, UINT32_MAX);
1961
1962 uint32_t cRefs = ASMAtomicIncU32(&pFlowBranchTbl->cRefs);
1963 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pFlowBranchTbl));
1964 return cRefs;
1965}
1966
1967
1968/**
1969 * Releases a given branch table handle.
1970 *
1971 * @returns the new reference count of the given branch table, on 0 it is destroyed.
1972 * @param hFlowBranchTbl The branch table handle.
1973 */
1974VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRelease(DBGFFLOWBRANCHTBL hFlowBranchTbl)
1975{
1976 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
1977 if (!pFlowBranchTbl)
1978 return 0;
1979 AssertPtrReturn(pFlowBranchTbl, UINT32_MAX);
1980
1981 uint32_t cRefs = ASMAtomicDecU32(&pFlowBranchTbl->cRefs);
1982 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pFlowBranchTbl));
1983 if (cRefs == 0)
1984 dbgfR3FlowBranchTblDestroy(pFlowBranchTbl);
1985 return cRefs;
1986}
1987
1988
1989/**
1990 * Return the number of slots the branch table has.
1991 *
1992 * @returns Number of slots in the branch table.
1993 * @param hFlowBranchTbl The branch table handle.
1994 */
1995VMMR3DECL(uint32_t) DBGFR3FlowBranchTblGetSlots(DBGFFLOWBRANCHTBL hFlowBranchTbl)
1996{
1997 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
1998 AssertPtrReturn(pFlowBranchTbl, 0);
1999
2000 return pFlowBranchTbl->cSlots;
2001}
2002
2003
2004/**
2005 * Returns the start address of the branch table in the guest.
2006 *
2007 * @returns Pointer to start address of the branch table (pAddrStart).
2008 * @param hFlowBranchTbl The branch table handle.
2009 * @param pAddrStart Where to store the branch table address.
2010 */
2011VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetStartAddress(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS pAddrStart)
2012{
2013 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
2014 AssertPtrReturn(pFlowBranchTbl, NULL);
2015 AssertPtrReturn(pAddrStart, NULL);
2016
2017 *pAddrStart = pFlowBranchTbl->AddrStart;
2018 return pAddrStart;
2019}
2020
2021
2022/**
2023 * Returns one address in the branch table at the given slot index.
2024 *
2025 * @return Pointer to the address at the given slot in the given branch table.
2026 * @param hFlowBranchTbl The branch table handle.
2027 * @param idxSlot The slot the address should be returned from.
2028 * @param pAddrSlot Where to store the address.
2029 */
2030VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetAddrAtSlot(DBGFFLOWBRANCHTBL hFlowBranchTbl, uint32_t idxSlot, PDBGFADDRESS pAddrSlot)
2031{
2032 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
2033 AssertPtrReturn(pFlowBranchTbl, NULL);
2034 AssertPtrReturn(pAddrSlot, NULL);
2035 AssertReturn(idxSlot < pFlowBranchTbl->cSlots, NULL);
2036
2037 *pAddrSlot = pFlowBranchTbl->aAddresses[idxSlot];
2038 return pAddrSlot;
2039}
2040
2041
2042/**
2043 * Query all addresses contained in the given branch table.
2044 *
2045 * @returns VBox status code.
2046 * @retval VERR_BUFFER_OVERFLOW if there is not enough space in the array to hold all addresses.
2047 * @param hFlowBranchTbl The branch table handle.
2048 * @param paAddrs Where to store the addresses on success.
2049 * @param cAddrs Number of entries the array can hold.
2050 */
2051VMMR3DECL(int) DBGFR3FlowBranchTblQueryAddresses(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS paAddrs, uint32_t cAddrs)
2052{
2053 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
2054 AssertPtrReturn(pFlowBranchTbl, VERR_INVALID_HANDLE);
2055 AssertPtrReturn(paAddrs, VERR_INVALID_POINTER);
2056 AssertReturn(cAddrs > 0, VERR_INVALID_PARAMETER);
2057
2058 if (cAddrs < pFlowBranchTbl->cSlots)
2059 return VERR_BUFFER_OVERFLOW;
2060
2061 memcpy(paAddrs, &pFlowBranchTbl->aAddresses[0], pFlowBranchTbl->cSlots * sizeof(DBGFADDRESS));
2062 return VINF_SUCCESS;
2063}
2064
2065
2066/**
2067 * @callback_method_impl{FNRTSORTCMP}
2068 */
2069static DECLCALLBACK(int) dbgfR3FlowItSortCmp(void const *pvElement1, void const *pvElement2, void *pvUser)
2070{
2071 PDBGFFLOWITORDER penmOrder = (PDBGFFLOWITORDER)pvUser;
2072 PDBGFFLOWBBINT pFlowBb1 = *(PDBGFFLOWBBINT *)pvElement1;
2073 PDBGFFLOWBBINT pFlowBb2 = *(PDBGFFLOWBBINT *)pvElement2;
2074
2075 if (dbgfR3FlowAddrEqual(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
2076 return 0;
2077
2078 if (*penmOrder == DBGFFLOWITORDER_BY_ADDR_LOWEST_FIRST)
2079 {
2080 if (dbgfR3FlowAddrLower(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
2081 return -1;
2082 else
2083 return 1;
2084 }
2085 else
2086 {
2087 if (dbgfR3FlowAddrLower(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
2088 return 1;
2089 else
2090 return -1;
2091 }
2092}
2093
2094
2095/**
2096 * Creates a new iterator for the given control flow graph.
2097 *
2098 * @returns VBox status code.
2099 * @param hFlow The control flow graph handle.
2100 * @param enmOrder The order in which the basic blocks are enumerated.
2101 * @param phFlowIt Where to store the handle to the iterator on success.
2102 */
2103VMMR3DECL(int) DBGFR3FlowItCreate(DBGFFLOW hFlow, DBGFFLOWITORDER enmOrder, PDBGFFLOWIT phFlowIt)
2104{
2105 int rc = VINF_SUCCESS;
2106 PDBGFFLOWINT pFlow = hFlow;
2107 AssertPtrReturn(pFlow, VERR_INVALID_POINTER);
2108 AssertPtrReturn(phFlowIt, VERR_INVALID_POINTER);
2109 AssertReturn(enmOrder > DBGFFLOWITORDER_INVALID && enmOrder < DBGFFLOWITORDER_BREADTH_FIRST,
2110 VERR_INVALID_PARAMETER);
2111 AssertReturn(enmOrder < DBGFFLOWITORDER_DEPTH_FRIST, VERR_NOT_IMPLEMENTED); /** @todo */
2112
2113 PDBGFFLOWITINT pIt = (PDBGFFLOWITINT)RTMemAllocZ(RT_UOFFSETOF_DYN(DBGFFLOWITINT, apBb[pFlow->cBbs]));
2114 if (RT_LIKELY(pIt))
2115 {
2116 DBGFR3FlowRetain(hFlow);
2117 pIt->pFlow = pFlow;
2118 pIt->idxBbNext = 0;
2119 /* Fill the list and then sort. */
2120 uint32_t idxBb = 0;
2121 PDBGFFLOWBBINT pFlowBb;
2122 RTListForEach(&pFlow->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
2123 {
2124 DBGFR3FlowBbRetain(pFlowBb);
2125 pIt->apBb[idxBb++] = pFlowBb;
2126 }
2127
2128 /* Sort the blocks by address. */
2129 RTSortShell(&pIt->apBb[0], pFlow->cBbs, sizeof(PDBGFFLOWBBINT), dbgfR3FlowItSortCmp, &enmOrder);
2130
2131 *phFlowIt = pIt;
2132 }
2133 else
2134 rc = VERR_NO_MEMORY;
2135
2136 return rc;
2137}
2138
2139
2140/**
2141 * Destroys a given control flow graph iterator.
2142 *
2143 * @param hFlowIt The control flow graph iterator handle.
2144 */
2145VMMR3DECL(void) DBGFR3FlowItDestroy(DBGFFLOWIT hFlowIt)
2146{
2147 PDBGFFLOWITINT pIt = hFlowIt;
2148 AssertPtrReturnVoid(pIt);
2149
2150 for (unsigned i = 0; i < pIt->pFlow->cBbs; i++)
2151 DBGFR3FlowBbRelease(pIt->apBb[i]);
2152
2153 DBGFR3FlowRelease(pIt->pFlow);
2154 RTMemFree(pIt);
2155}
2156
2157
2158/**
2159 * Returns the next basic block in the iterator or NULL if there is no
2160 * basic block left.
2161 *
2162 * @returns Handle to the next basic block in the iterator or NULL if the end
2163 * was reached.
2164 * @param hFlowIt The iterator handle.
2165 *
2166 * @note If a valid handle is returned it must be release with DBGFR3FlowBbRelease()
2167 * when not required anymore.
2168 */
2169VMMR3DECL(DBGFFLOWBB) DBGFR3FlowItNext(DBGFFLOWIT hFlowIt)
2170{
2171 PDBGFFLOWITINT pIt = hFlowIt;
2172 AssertPtrReturn(pIt, NULL);
2173
2174 PDBGFFLOWBBINT pFlowBb = NULL;
2175 if (pIt->idxBbNext < pIt->pFlow->cBbs)
2176 {
2177 pFlowBb = pIt->apBb[pIt->idxBbNext++];
2178 DBGFR3FlowBbRetain(pFlowBb);
2179 }
2180
2181 return pFlowBb;
2182}
2183
2184
2185/**
2186 * Resets the given iterator to the beginning.
2187 *
2188 * @returns VBox status code.
2189 * @param hFlowIt The iterator handle.
2190 */
2191VMMR3DECL(int) DBGFR3FlowItReset(DBGFFLOWIT hFlowIt)
2192{
2193 PDBGFFLOWITINT pIt = hFlowIt;
2194 AssertPtrReturn(pIt, VERR_INVALID_HANDLE);
2195
2196 pIt->idxBbNext = 0;
2197 return VINF_SUCCESS;
2198}
2199
2200
2201/**
2202 * @callback_method_impl{FNRTSORTCMP}
2203 */
2204static DECLCALLBACK(int) dbgfR3FlowBranchTblItSortCmp(void const *pvElement1, void const *pvElement2, void *pvUser)
2205{
2206 PDBGFFLOWITORDER penmOrder = (PDBGFFLOWITORDER)pvUser;
2207 PDBGFFLOWBRANCHTBLINT pTbl1 = *(PDBGFFLOWBRANCHTBLINT *)pvElement1;
2208 PDBGFFLOWBRANCHTBLINT pTbl2 = *(PDBGFFLOWBRANCHTBLINT *)pvElement2;
2209
2210 if (dbgfR3FlowAddrEqual(&pTbl1->AddrStart, &pTbl2->AddrStart))
2211 return 0;
2212
2213 if (*penmOrder == DBGFFLOWITORDER_BY_ADDR_LOWEST_FIRST)
2214 {
2215 if (dbgfR3FlowAddrLower(&pTbl1->AddrStart, &pTbl2->AddrStart))
2216 return -1;
2217 else
2218 return 1;
2219 }
2220 else
2221 {
2222 if (dbgfR3FlowAddrLower(&pTbl1->AddrStart, &pTbl2->AddrStart))
2223 return 1;
2224 else
2225 return -1;
2226 }
2227}
2228
2229
2230/**
2231 * Creates a new branch table iterator for the given control flow graph.
2232 *
2233 * @returns VBox status code.
2234 * @param hFlow The control flow graph handle.
2235 * @param enmOrder The order in which the basic blocks are enumerated.
2236 * @param phFlowBranchTblIt Where to store the handle to the iterator on success.
2237 */
2238VMMR3DECL(int) DBGFR3FlowBranchTblItCreate(DBGFFLOW hFlow, DBGFFLOWITORDER enmOrder,
2239 PDBGFFLOWBRANCHTBLIT phFlowBranchTblIt)
2240{
2241 int rc = VINF_SUCCESS;
2242 PDBGFFLOWINT pFlow = hFlow;
2243 AssertPtrReturn(pFlow, VERR_INVALID_POINTER);
2244 AssertPtrReturn(phFlowBranchTblIt, VERR_INVALID_POINTER);
2245 AssertReturn(enmOrder > DBGFFLOWITORDER_INVALID && enmOrder < DBGFFLOWITORDER_BREADTH_FIRST,
2246 VERR_INVALID_PARAMETER);
2247 AssertReturn(enmOrder < DBGFFLOWITORDER_DEPTH_FRIST, VERR_NOT_SUPPORTED);
2248
2249 PDBGFFLOWBRANCHTBLITINT pIt = (PDBGFFLOWBRANCHTBLITINT)RTMemAllocZ(RT_UOFFSETOF_DYN(DBGFFLOWBRANCHTBLITINT,
2250 apBranchTbl[pFlow->cBranchTbls]));
2251 if (RT_LIKELY(pIt))
2252 {
2253 DBGFR3FlowRetain(hFlow);
2254 pIt->pFlow = pFlow;
2255 pIt->idxTblNext = 0;
2256 /* Fill the list and then sort. */
2257 uint32_t idxTbl = 0;
2258 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl;
2259 RTListForEach(&pFlow->LstBranchTbl, pFlowBranchTbl, DBGFFLOWBRANCHTBLINT, NdBranchTbl)
2260 {
2261 DBGFR3FlowBranchTblRetain(pFlowBranchTbl);
2262 pIt->apBranchTbl[idxTbl++] = pFlowBranchTbl;
2263 }
2264
2265 /* Sort the blocks by address. */
2266 RTSortShell(&pIt->apBranchTbl[0], pFlow->cBranchTbls, sizeof(PDBGFFLOWBRANCHTBLINT), dbgfR3FlowBranchTblItSortCmp, &enmOrder);
2267
2268 *phFlowBranchTblIt = pIt;
2269 }
2270 else
2271 rc = VERR_NO_MEMORY;
2272
2273 return rc;
2274}
2275
2276
2277/**
2278 * Destroys a given control flow graph branch table iterator.
2279 *
2280 * @param hFlowBranchTblIt The control flow graph branch table iterator handle.
2281 */
2282VMMR3DECL(void) DBGFR3FlowBranchTblItDestroy(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt)
2283{
2284 PDBGFFLOWBRANCHTBLITINT pIt = hFlowBranchTblIt;
2285 AssertPtrReturnVoid(pIt);
2286
2287 for (unsigned i = 0; i < pIt->pFlow->cBranchTbls; i++)
2288 DBGFR3FlowBranchTblRelease(pIt->apBranchTbl[i]);
2289
2290 DBGFR3FlowRelease(pIt->pFlow);
2291 RTMemFree(pIt);
2292}
2293
2294
2295/**
2296 * Returns the next branch table in the iterator or NULL if there is no
2297 * branch table left.
2298 *
2299 * @returns Handle to the next basic block in the iterator or NULL if the end
2300 * was reached.
2301 * @param hFlowBranchTblIt The iterator handle.
2302 *
2303 * @note If a valid handle is returned it must be release with DBGFR3FlowBranchTblRelease()
2304 * when not required anymore.
2305 */
2306VMMR3DECL(DBGFFLOWBRANCHTBL) DBGFR3FlowBranchTblItNext(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt)
2307{
2308 PDBGFFLOWBRANCHTBLITINT pIt = hFlowBranchTblIt;
2309 AssertPtrReturn(pIt, NULL);
2310
2311 PDBGFFLOWBRANCHTBLINT pTbl = NULL;
2312 if (pIt->idxTblNext < pIt->pFlow->cBranchTbls)
2313 {
2314 pTbl = pIt->apBranchTbl[pIt->idxTblNext++];
2315 DBGFR3FlowBranchTblRetain(pTbl);
2316 }
2317
2318 return pTbl;
2319}
2320
2321
2322/**
2323 * Resets the given iterator to the beginning.
2324 *
2325 * @returns VBox status code.
2326 * @param hFlowBranchTblIt The iterator handle.
2327 */
2328VMMR3DECL(int) DBGFR3FlowBranchTblItReset(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt)
2329{
2330 PDBGFFLOWBRANCHTBLITINT pIt = hFlowBranchTblIt;
2331 AssertPtrReturn(pIt, VERR_INVALID_HANDLE);
2332
2333 pIt->idxTblNext = 0;
2334 return VINF_SUCCESS;
2335}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use