VirtualBox

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

Last change on this file was 106784, checked in by vboxsync, 5 weeks ago

VMM/ARM: On ARM relative branch targets start always from the beginning of the current instruction while on x86 it always starts from the beginning of the following instruction, fixes control flow graph generation for ARMv8 guests, bugref:10393

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

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