VirtualBox

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

Last change on this file since 88366 was 88366, checked in by vboxsync, 3 years ago

VMM/DBGFR3Flow: Add ability to put call instructions into separate basic blocks which will aid the flow tracing code to instrument calls to other functions more easily

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

© 2023 Oracle
ContactPrivacy policyTerms of Use