VirtualBox

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

Last change on this file since 106745 was 106745, checked in by vboxsync, 7 months ago

VMM/ARM: Treat DISOPTYPE_INTERRUPT insutrctions (like svc, hvc, ...) as call instructions, bugref:10393

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

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