VirtualBox

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

最後變更 在這個檔案從106743是 106743,由 vboxsync 提交於 5 月 前

VMM/ARM: Make the control flow graph generator work with ARMv8 A64 to some extent, bugref:10393

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette