VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 22 months ago

scm copyright and license note update

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

© 2023 Oracle
ContactPrivacy policyTerms of Use