VirtualBox

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

Last change on this file since 107623 was 107227, checked in by vboxsync, 2 months ago

VMM: Cleaning up ARMv8 / x86 split. jiraref:VBP-1470

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 87.0 KB
Line 
1/* $Id: DBGFR3Flow.cpp 107227 2024-12-04 15:20:14Z 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 return pDis->armv8.enmCond == kDisArmv8InstrCond_Al
235 || pDis->armv8.enmCond == kDisArmv8InstrCond_Al1;
236
237 return false;
238
239#elif defined(VBOX_VMM_TARGET_X86)
240 RT_NOREF_PV(pDis);
241 return uOpc == OP_JMP;
242
243#else
244# error "port me"
245#endif
246}
247
248
249/**
250 * Returns whether the given opcode denotes a call/branch and link instruction.
251 *
252 * @returns Flag whether the given instruction is a call.
253 * @param uOpc The opcode value from the disassembler.
254 * @param fOpType The opcode type flags for the given opcode.
255 */
256DECL_FORCE_INLINE(bool) dbgfR3FlowDisOpcIsCall(uint16_t uOpc, uint32_t fOpType)
257{
258#ifdef VBOX_VMM_TARGET_ARMV8
259 if ( uOpc == OP_ARMV8_A64_BL
260 || uOpc == OP_ARMV8_A64_BLR
261 || uOpc == OP_ARMV8_A64_BLRAA
262 || uOpc == OP_ARMV8_A64_BLRAB
263 || uOpc == OP_ARMV8_A64_BLRAAZ
264 || uOpc == OP_ARMV8_A64_BLRABZ)
265 return true;
266
267 /* Treat instructions like svc/hvc as calls. */
268 if (fOpType & DISOPTYPE_INTERRUPT)
269 return true;
270
271 return false;
272
273#elif defined(VBOX_VMM_TARGET_X86)
274 RT_NOREF_PV(fOpType);
275 return uOpc == OP_CALL;
276
277#else
278# error "port me"
279#endif
280}
281
282
283/**
284 * Returns whether the given opcode denotes a function/exception return.
285 *
286 * @returns Flag whether the given instruction is a return.
287 * @param uOpc The opcode value from the disassembler.
288 */
289DECL_FORCE_INLINE(bool) dbgfR3FlowDisOpcIsExit(uint16_t uOpc)
290{
291#ifdef VBOX_VMM_TARGET_ARMV8
292 return uOpc == OP_ARMV8_A64_RET
293 || uOpc == OP_ARMV8_A64_RETAA
294 || uOpc == OP_ARMV8_A64_RETAB
295 || uOpc == OP_ARMV8_A64_ERET
296 || uOpc == OP_ARMV8_A64_ERETAA
297 || uOpc == OP_ARMV8_A64_ERETAB;
298
299#elif defined(VBOX_VMM_TARGET_X86)
300 return uOpc == OP_RETN
301 || uOpc == OP_RETF
302 || uOpc == OP_IRET
303 || uOpc == OP_SYSEXIT
304 || uOpc == OP_SYSRET;
305
306#else
307# error "port me"
308#endif
309}
310
311
312/**
313 * Checks whether both addresses are equal.
314 *
315 * @returns true if both addresses point to the same location, false otherwise.
316 * @param pAddr1 First address.
317 * @param pAddr2 Second address.
318 */
319static bool dbgfR3FlowAddrEqual(PDBGFADDRESS pAddr1, PDBGFADDRESS pAddr2)
320{
321 return pAddr1->Sel == pAddr2->Sel
322 && pAddr1->off == pAddr2->off;
323}
324
325
326/**
327 * Checks whether the first given address is lower than the second one.
328 *
329 * @returns true if both addresses point to the same location, false otherwise.
330 * @param pAddr1 First address.
331 * @param pAddr2 Second address.
332 */
333static bool dbgfR3FlowAddrLower(PDBGFADDRESS pAddr1, PDBGFADDRESS pAddr2)
334{
335 return pAddr1->Sel == pAddr2->Sel
336 && pAddr1->off < pAddr2->off;
337}
338
339
340/**
341 * Checks whether the given basic block and address intersect.
342 *
343 * @returns true if they intersect, false otherwise.
344 * @param pFlowBb The basic block to check.
345 * @param pAddr The address to check for.
346 */
347static bool dbgfR3FlowAddrIntersect(PDBGFFLOWBBINT pFlowBb, PDBGFADDRESS pAddr)
348{
349 return pFlowBb->AddrStart.Sel == pAddr->Sel
350 && pFlowBb->AddrStart.off <= pAddr->off
351 && pFlowBb->AddrEnd.off >= pAddr->off;
352}
353
354
355/**
356 * Returns the distance of the two given addresses.
357 *
358 * @returns Distance of the addresses.
359 * @param pAddr1 The first address.
360 * @param pAddr2 The second address.
361 */
362static RTGCUINTPTR dbgfR3FlowAddrGetDistance(PDBGFADDRESS pAddr1, PDBGFADDRESS pAddr2)
363{
364 if (pAddr1->Sel == pAddr2->Sel)
365 {
366 if (pAddr1->off >= pAddr2->off)
367 return pAddr1->off - pAddr2->off;
368 return pAddr2->off - pAddr1->off;
369 }
370 AssertFailed();
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 Assert(!dbgfR3FlowBranchTargetIsIndirect(pDisParam));
777
778 *pAddrJmpTarget = *pAddrInstr;
779#ifdef VBOX_VMM_TARGET_X86
780 /* Relative to the next instruction. */
781 DBGFR3AddrAdd(pAddrJmpTarget, cbInstr);
782#elif defined(VBOX_VMM_TARGET_ARMV8)
783 /* Relative to the start of the instruction. */
784 RT_NOREF(cbInstr);
785#else
786# error "port me"
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 AssertFailedReturn(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 AssertFailedReturn(VERR_INVALID_STATE);
819 }
820
821 return VINF_SUCCESS;
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 PDBGFFLOWBBINT pFlowBb = dbgfR3FlowGetUnpopulatedBb(pThis);
1469 while (pFlowBb != NULL)
1470 {
1471 int rc = dbgfR3FlowBbProcess(pUVM, idCpu, pThis, pFlowBb, cbDisasmMax, fFlags);
1472 if (RT_SUCCESS(rc))
1473 pFlowBb = dbgfR3FlowGetUnpopulatedBb(pThis);
1474 else
1475 return rc;
1476 }
1477
1478 return VINF_SUCCESS;
1479}
1480
1481/**
1482 * Creates a new control flow graph from the given start address.
1483 *
1484 * @returns VBox status code.
1485 * @param pUVM The user mode VM handle.
1486 * @param idCpu CPU id for disassembling.
1487 * @param pAddressStart Where to start creating the control flow graph.
1488 * @param cbDisasmMax Limit the amount of bytes to disassemble, 0 for no limit.
1489 * @param fFlagsFlow Combination of DBGF_FLOW_CREATE_F_* to control the creation of the flow graph.
1490 * @param fFlagsDisasm Combination of DBGF_DISAS_FLAGS_* controlling the style of the disassembled
1491 * instructions.
1492 * @param phFlow Where to store the handle to the control flow graph on success.
1493 */
1494VMMR3DECL(int) DBGFR3FlowCreate(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddressStart, uint32_t cbDisasmMax,
1495 uint32_t fFlagsFlow, uint32_t fFlagsDisasm, PDBGFFLOW phFlow)
1496{
1497 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1498 PVM pVM = pUVM->pVM;
1499 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1500 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
1501 AssertPtrReturn(pAddressStart, VERR_INVALID_POINTER);
1502 AssertReturn(!(fFlagsDisasm & ~DBGF_DISAS_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
1503 AssertReturn((fFlagsDisasm & DBGF_DISAS_FLAGS_MODE_MASK) <= DBGF_DISAS_FLAGS_64BIT_MODE, VERR_INVALID_PARAMETER);
1504
1505 /* Create the control flow graph container. */
1506 int rc;
1507 PDBGFFLOWINT pThis = (PDBGFFLOWINT)RTMemAllocZ(sizeof(DBGFFLOWINT));
1508 if (RT_LIKELY(pThis))
1509 {
1510 rc = RTStrCacheCreate(&pThis->hStrCacheInstr, "DBGFFLOW");
1511 if (RT_SUCCESS(rc))
1512 {
1513 pThis->cRefs = 1;
1514 pThis->cRefsBb = 0;
1515 pThis->cBbs = 0;
1516 pThis->cBranchTbls = 0;
1517 pThis->cCallInsns = 0;
1518 pThis->fFlags = fFlagsFlow;
1519 RTListInit(&pThis->LstFlowBb);
1520 RTListInit(&pThis->LstBranchTbl);
1521 /* Create the entry basic block and start the work. */
1522
1523 PDBGFFLOWBBINT pFlowBb = dbgfR3FlowBbCreate(pThis, pAddressStart, DBGF_FLOW_BB_F_ENTRY, 10);
1524 if (RT_LIKELY(pFlowBb))
1525 {
1526 dbgfR3FlowLink(pThis, pFlowBb);
1527 rc = dbgfR3FlowPopulate(pUVM, idCpu, pThis, cbDisasmMax, fFlagsDisasm);
1528 if (RT_SUCCESS(rc))
1529 {
1530 *phFlow = pThis;
1531 return VINF_SUCCESS;
1532 }
1533 }
1534 else
1535 rc = VERR_NO_MEMORY;
1536 }
1537
1538 ASMAtomicDecU32(&pThis->cRefs);
1539 dbgfR3FlowDestroy(pThis);
1540 }
1541 else
1542 rc = VERR_NO_MEMORY;
1543
1544 return rc;
1545}
1546
1547
1548/**
1549 * Retains the control flow graph handle.
1550 *
1551 * @returns Current reference count.
1552 * @param hFlow The control flow graph handle to retain.
1553 */
1554VMMR3DECL(uint32_t) DBGFR3FlowRetain(DBGFFLOW hFlow)
1555{
1556 PDBGFFLOWINT pThis = hFlow;
1557 AssertPtrReturn(pThis, UINT32_MAX);
1558
1559 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1560 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1561 return cRefs;
1562}
1563
1564
1565/**
1566 * Releases the control flow graph handle.
1567 *
1568 * @returns Current reference count, on 0 the control flow graph will be destroyed.
1569 * @param hFlow The control flow graph handle to release.
1570 */
1571VMMR3DECL(uint32_t) DBGFR3FlowRelease(DBGFFLOW hFlow)
1572{
1573 PDBGFFLOWINT pThis = hFlow;
1574 if (!pThis)
1575 return 0;
1576 AssertPtrReturn(pThis, UINT32_MAX);
1577
1578 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1579 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1580 if (cRefs == 0)
1581 dbgfR3FlowDestroy(pThis);
1582 return cRefs;
1583}
1584
1585
1586/**
1587 * Queries the basic block denoting the entry point into the control flow graph.
1588 *
1589 * @returns VBox status code.
1590 * @param hFlow The control flow graph handle.
1591 * @param phFlowBb Where to store the basic block handle on success.
1592 */
1593VMMR3DECL(int) DBGFR3FlowQueryStartBb(DBGFFLOW hFlow, PDBGFFLOWBB phFlowBb)
1594{
1595 PDBGFFLOWINT pThis = hFlow;
1596 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1597
1598 PDBGFFLOWBBINT pFlowBb;
1599 RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
1600 {
1601 if (pFlowBb->fFlags & DBGF_FLOW_BB_F_ENTRY)
1602 {
1603 *phFlowBb = pFlowBb;
1604 return VINF_SUCCESS;
1605 }
1606 }
1607
1608 AssertFailed(); /* Should never get here. */
1609 return VERR_INTERNAL_ERROR;
1610}
1611
1612
1613/**
1614 * Queries a basic block in the given control flow graph which covers the given
1615 * address.
1616 *
1617 * @returns VBox status code.
1618 * @retval VERR_NOT_FOUND if there is no basic block intersecting with the address.
1619 * @param hFlow The control flow graph handle.
1620 * @param pAddr The address to look for.
1621 * @param phFlowBb Where to store the basic block handle on success.
1622 */
1623VMMR3DECL(int) DBGFR3FlowQueryBbByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBB phFlowBb)
1624{
1625 PDBGFFLOWINT pThis = hFlow;
1626 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1627 AssertPtrReturn(pAddr, VERR_INVALID_POINTER);
1628 AssertPtrReturn(phFlowBb, VERR_INVALID_POINTER);
1629
1630 PDBGFFLOWBBINT pFlowBb;
1631 RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
1632 {
1633 if (dbgfR3FlowAddrIntersect(pFlowBb, pAddr))
1634 {
1635 DBGFR3FlowBbRetain(pFlowBb);
1636 *phFlowBb = pFlowBb;
1637 return VINF_SUCCESS;
1638 }
1639 }
1640
1641 return VERR_NOT_FOUND;
1642}
1643
1644
1645/**
1646 * Queries a branch table in the given control flow graph by the given address.
1647 *
1648 * @returns VBox status code.
1649 * @retval VERR_NOT_FOUND if there is no branch table with the given address.
1650 * @param hFlow The control flow graph handle.
1651 * @param pAddr The address of the branch table.
1652 * @param phFlowBranchTbl Where to store the handle to branch table on success.
1653 *
1654 * @note Call DBGFR3FlowBranchTblRelease() when the handle is not required anymore.
1655 */
1656VMMR3DECL(int) DBGFR3FlowQueryBranchTblByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBRANCHTBL phFlowBranchTbl)
1657{
1658 PDBGFFLOWINT pThis = hFlow;
1659 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1660 AssertPtrReturn(pAddr, VERR_INVALID_POINTER);
1661 AssertPtrReturn(phFlowBranchTbl, VERR_INVALID_POINTER);
1662
1663 PDBGFFLOWBRANCHTBLINT pBranchTbl = dbgfR3FlowBranchTblFindByAddr(pThis, pAddr);
1664 if (pBranchTbl)
1665 {
1666 DBGFR3FlowBranchTblRetain(pBranchTbl);
1667 *phFlowBranchTbl = pBranchTbl;
1668 return VINF_SUCCESS;
1669 }
1670
1671 return VERR_NOT_FOUND;
1672}
1673
1674
1675/**
1676 * Returns the number of basic blcoks inside the control flow graph.
1677 *
1678 * @returns Number of basic blocks.
1679 * @param hFlow The control flow graph handle.
1680 */
1681VMMR3DECL(uint32_t) DBGFR3FlowGetBbCount(DBGFFLOW hFlow)
1682{
1683 PDBGFFLOWINT pThis = hFlow;
1684 AssertPtrReturn(pThis, 0);
1685
1686 return pThis->cBbs;
1687}
1688
1689
1690/**
1691 * Returns the number of branch tables inside the control flow graph.
1692 *
1693 * @returns Number of basic blocks.
1694 * @param hFlow The control flow graph handle.
1695 */
1696VMMR3DECL(uint32_t) DBGFR3FlowGetBranchTblCount(DBGFFLOW hFlow)
1697{
1698 PDBGFFLOWINT pThis = hFlow;
1699 AssertPtrReturn(pThis, 0);
1700
1701 return pThis->cBranchTbls;
1702}
1703
1704
1705/**
1706 * Returns the number of call instructions encountered in the given
1707 * control flow graph.
1708 *
1709 * @returns Number of call instructions.
1710 * @param hFlow The control flow graph handle.
1711 */
1712VMMR3DECL(uint32_t) DBGFR3FlowGetCallInsnCount(DBGFFLOW hFlow)
1713{
1714 PDBGFFLOWINT pThis = hFlow;
1715 AssertPtrReturn(pThis, 0);
1716
1717 return pThis->cCallInsns;
1718}
1719
1720
1721/**
1722 * Retains the basic block handle.
1723 *
1724 * @returns Current reference count.
1725 * @param hFlowBb The basic block handle to retain.
1726 */
1727VMMR3DECL(uint32_t) DBGFR3FlowBbRetain(DBGFFLOWBB hFlowBb)
1728{
1729 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1730 AssertPtrReturn(pFlowBb, UINT32_MAX);
1731
1732 uint32_t cRefs = ASMAtomicIncU32(&pFlowBb->cRefs);
1733 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p %d\n", cRefs, pFlowBb, pFlowBb->enmEndType));
1734 return cRefs;
1735}
1736
1737
1738/**
1739 * Releases the basic block handle.
1740 *
1741 * @returns Current reference count, on 0 the basic block will be destroyed.
1742 * @param hFlowBb The basic block handle to release.
1743 */
1744VMMR3DECL(uint32_t) DBGFR3FlowBbRelease(DBGFFLOWBB hFlowBb)
1745{
1746 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1747 if (!pFlowBb)
1748 return 0;
1749
1750 return dbgfR3FlowBbReleaseInt(pFlowBb, true /* fMayDestroyFlow */);
1751}
1752
1753
1754/**
1755 * Returns the start address of the basic block.
1756 *
1757 * @returns Pointer to DBGF adress containing the start address of the basic block.
1758 * @param hFlowBb The basic block handle.
1759 * @param pAddrStart Where to store the start address of the basic block.
1760 */
1761VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetStartAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrStart)
1762{
1763 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1764 AssertPtrReturn(pFlowBb, NULL);
1765 AssertPtrReturn(pAddrStart, NULL);
1766
1767 *pAddrStart = pFlowBb->AddrStart;
1768 return pAddrStart;
1769}
1770
1771
1772/**
1773 * Returns the end address of the basic block (inclusive).
1774 *
1775 * @returns Pointer to DBGF adress containing the end address of the basic block.
1776 * @param hFlowBb The basic block handle.
1777 * @param pAddrEnd Where to store the end address of the basic block.
1778 */
1779VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetEndAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrEnd)
1780{
1781 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1782 AssertPtrReturn(pFlowBb, NULL);
1783 AssertPtrReturn(pAddrEnd, NULL);
1784
1785 *pAddrEnd = pFlowBb->AddrEnd;
1786 return pAddrEnd;
1787}
1788
1789
1790/**
1791 * Returns the address the last instruction in the basic block branches to.
1792 *
1793 * @returns Pointer to DBGF adress containing the branch address of the basic block.
1794 * @param hFlowBb The basic block handle.
1795 * @param pAddrTarget Where to store the branch address of the basic block.
1796 *
1797 * @note This is only valid for unconditional or conditional branches, or for a basic block
1798 * containing only a call instruction when DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB was given
1799 * during creation and the branch target could be deduced as indicated by the DBGF_FLOW_BB_F_CALL_INSN_TARGET_KNOWN
1800 * flag for the basic block. This method will assert for every other basic block type.
1801 * @note For indirect unconditional branches using a branch table this will return the start address
1802 * of the branch table.
1803 */
1804VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetBranchAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrTarget)
1805{
1806 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1807 AssertPtrReturn(pFlowBb, NULL);
1808 AssertPtrReturn(pAddrTarget, NULL);
1809 AssertReturn( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_JMP
1810 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_COND
1811 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP
1812 || ( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND
1813 && (pFlowBb->fFlags & DBGF_FLOW_BB_F_CALL_INSN_TARGET_KNOWN)),
1814 NULL);
1815
1816 if ( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP
1817 && pFlowBb->pFlowBranchTbl)
1818 *pAddrTarget = pFlowBb->pFlowBranchTbl->AddrStart;
1819 else
1820 *pAddrTarget = pFlowBb->AddrTarget;
1821 return pAddrTarget;
1822}
1823
1824
1825/**
1826 * Returns the address of the next block following this one in the instruction stream.
1827 * (usually end address + 1).
1828 *
1829 * @returns Pointer to DBGF adress containing the following address of the basic block.
1830 * @param hFlowBb The basic block handle.
1831 * @param pAddrFollow Where to store the following address of the basic block.
1832 *
1833 * @note This is only valid for conditional branches and if the last instruction in the
1834 * given basic block doesn't change the control flow but the blocks were split
1835 * because the successor is referenced by multiple other blocks as an entry point.
1836 */
1837VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetFollowingAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrFollow)
1838{
1839 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1840 AssertPtrReturn(pFlowBb, NULL);
1841 AssertPtrReturn(pAddrFollow, NULL);
1842 AssertReturn( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND
1843 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_COND,
1844 NULL);
1845
1846 *pAddrFollow = pFlowBb->AddrEnd;
1847 DBGFR3AddrAdd(pAddrFollow, 1);
1848 return pAddrFollow;
1849}
1850
1851
1852/**
1853 * Returns the type of the last instruction in the basic block.
1854 *
1855 * @returns Last instruction type.
1856 * @param hFlowBb The basic block handle.
1857 */
1858VMMR3DECL(DBGFFLOWBBENDTYPE) DBGFR3FlowBbGetType(DBGFFLOWBB hFlowBb)
1859{
1860 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1861 AssertPtrReturn(pFlowBb, DBGFFLOWBBENDTYPE_INVALID);
1862
1863 return pFlowBb->enmEndType;
1864}
1865
1866
1867/**
1868 * Get the number of instructions contained in the basic block.
1869 *
1870 * @returns Number of instructions in the basic block.
1871 * @param hFlowBb The basic block handle.
1872 */
1873VMMR3DECL(uint32_t) DBGFR3FlowBbGetInstrCount(DBGFFLOWBB hFlowBb)
1874{
1875 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1876 AssertPtrReturn(pFlowBb, 0);
1877
1878 return pFlowBb->cInstr;
1879}
1880
1881
1882/**
1883 * Get flags for the given basic block.
1884 *
1885 * @returns Combination of DBGF_FLOW_BB_F_*
1886 * @param hFlowBb The basic block handle.
1887 */
1888VMMR3DECL(uint32_t) DBGFR3FlowBbGetFlags(DBGFFLOWBB hFlowBb)
1889{
1890 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1891 AssertPtrReturn(pFlowBb, 0);
1892
1893 return pFlowBb->fFlags;
1894}
1895
1896
1897/**
1898 * Queries the branch table used if the given basic block ends with an indirect branch
1899 * and has a branch table referenced.
1900 *
1901 * @returns VBox status code.
1902 * @param hFlowBb The basic block handle.
1903 * @param phBranchTbl Where to store the branch table handle on success.
1904 *
1905 * @note Release the branch table reference with DBGFR3FlowBranchTblRelease() when not required
1906 * anymore.
1907 */
1908VMMR3DECL(int) DBGFR3FlowBbQueryBranchTbl(DBGFFLOWBB hFlowBb, PDBGFFLOWBRANCHTBL phBranchTbl)
1909{
1910 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1911 AssertPtrReturn(pFlowBb, VERR_INVALID_HANDLE);
1912 AssertReturn(pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP, VERR_INVALID_STATE);
1913 AssertPtrReturn(pFlowBb->pFlowBranchTbl, VERR_INVALID_STATE);
1914 AssertPtrReturn(phBranchTbl, VERR_INVALID_POINTER);
1915
1916 DBGFR3FlowBranchTblRetain(pFlowBb->pFlowBranchTbl);
1917 *phBranchTbl = pFlowBb->pFlowBranchTbl;
1918 return VINF_SUCCESS;
1919}
1920
1921
1922/**
1923 * Returns the error status and message if the given basic block has an error.
1924 *
1925 * @returns VBox status code of the error for the basic block.
1926 * @param hFlowBb The basic block handle.
1927 * @param ppszErr Where to store the pointer to the error message - optional.
1928 */
1929VMMR3DECL(int) DBGFR3FlowBbQueryError(DBGFFLOWBB hFlowBb, const char **ppszErr)
1930{
1931 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1932 AssertPtrReturn(pFlowBb, VERR_INVALID_HANDLE);
1933
1934 if (ppszErr)
1935 *ppszErr = pFlowBb->pszErr;
1936
1937 return pFlowBb->rcError;
1938}
1939
1940
1941/**
1942 * Store the disassembled instruction as a string in the given output buffer.
1943 *
1944 * @returns VBox status code.
1945 * @param hFlowBb The basic block handle.
1946 * @param idxInstr The instruction to query.
1947 * @param pAddrInstr Where to store the guest instruction address on success, optional.
1948 * @param pcbInstr Where to store the instruction size on success, optional.
1949 * @param ppszInstr Where to store the pointer to the disassembled instruction string, optional.
1950 */
1951VMMR3DECL(int) DBGFR3FlowBbQueryInstr(DBGFFLOWBB hFlowBb, uint32_t idxInstr, PDBGFADDRESS pAddrInstr,
1952 uint32_t *pcbInstr, const char **ppszInstr)
1953{
1954 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1955 AssertPtrReturn(pFlowBb, VERR_INVALID_POINTER);
1956 AssertReturn(idxInstr < pFlowBb->cInstr, VERR_INVALID_PARAMETER);
1957
1958 if (pAddrInstr)
1959 *pAddrInstr = pFlowBb->aInstr[idxInstr].AddrInstr;
1960 if (pcbInstr)
1961 *pcbInstr = pFlowBb->aInstr[idxInstr].cbInstr;
1962 if (ppszInstr)
1963 *ppszInstr = pFlowBb->aInstr[idxInstr].pszInstr;
1964
1965 return VINF_SUCCESS;
1966}
1967
1968
1969/**
1970 * Queries the successors of the basic block.
1971 *
1972 * @returns VBox status code.
1973 * @param hFlowBb The basic block handle.
1974 * @param phFlowBbFollow Where to store the handle to the basic block following
1975 * this one (optional).
1976 * @param phFlowBbTarget Where to store the handle to the basic block being the
1977 * branch target for this one (optional).
1978 */
1979VMMR3DECL(int) DBGFR3FlowBbQuerySuccessors(DBGFFLOWBB hFlowBb, PDBGFFLOWBB phFlowBbFollow, PDBGFFLOWBB phFlowBbTarget)
1980{
1981 PDBGFFLOWBBINT pFlowBb = hFlowBb;
1982 AssertPtrReturn(pFlowBb, VERR_INVALID_POINTER);
1983
1984 if ( phFlowBbFollow
1985 && ( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND
1986 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_COND))
1987 {
1988 DBGFADDRESS AddrStart = pFlowBb->AddrEnd;
1989 DBGFR3AddrAdd(&AddrStart, 1);
1990 int rc = DBGFR3FlowQueryBbByAddress(pFlowBb->pFlow, &AddrStart, phFlowBbFollow);
1991 AssertRC(rc);
1992 }
1993
1994 if ( phFlowBbTarget
1995 && ( pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_JMP
1996 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_COND))
1997 {
1998 int rc = DBGFR3FlowQueryBbByAddress(pFlowBb->pFlow, &pFlowBb->AddrTarget, phFlowBbTarget);
1999 AssertRC(rc);
2000 }
2001
2002 return VINF_SUCCESS;
2003}
2004
2005
2006/**
2007 * Returns the number of basic blocks referencing this basic block as a target.
2008 *
2009 * @returns Number of other basic blocks referencing this one.
2010 * @param hFlowBb The basic block handle.
2011 *
2012 * @note If the given basic block references itself (loop, etc.) this will be counted as well.
2013 */
2014VMMR3DECL(uint32_t) DBGFR3FlowBbGetRefBbCount(DBGFFLOWBB hFlowBb)
2015{
2016 PDBGFFLOWBBINT pFlowBb = hFlowBb;
2017 AssertPtrReturn(pFlowBb, 0);
2018
2019 uint32_t cRefsBb = 0;
2020 PDBGFFLOWBBINT pFlowBbCur;
2021 RTListForEach(&pFlowBb->pFlow->LstFlowBb, pFlowBbCur, DBGFFLOWBBINT, NdFlowBb)
2022 {
2023 if (pFlowBbCur->fFlags & DBGF_FLOW_BB_F_INCOMPLETE_ERR)
2024 continue;
2025
2026 if ( pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_UNCOND
2027 || pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_COND)
2028 {
2029 DBGFADDRESS AddrStart = pFlowBb->AddrEnd;
2030 DBGFR3AddrAdd(&AddrStart, 1);
2031 if (dbgfR3FlowAddrEqual(&pFlowBbCur->AddrStart, &AddrStart))
2032 cRefsBb++;
2033 }
2034
2035 if ( ( pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_JMP
2036 || pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_COND)
2037 && dbgfR3FlowAddrEqual(&pFlowBbCur->AddrStart, &pFlowBb->AddrTarget))
2038 cRefsBb++;
2039 }
2040 return cRefsBb;
2041}
2042
2043
2044/**
2045 * Returns the basic block handles referencing the given basic block.
2046 *
2047 * @returns VBox status code.
2048 * @retval VERR_BUFFER_OVERFLOW if the array can't hold all the basic blocks.
2049 * @param hFlowBb The basic block handle.
2050 * @param paFlowBbRef Pointer to the array containing the referencing basic block handles on success.
2051 * @param cRef Number of entries in the given array.
2052 */
2053VMMR3DECL(int) DBGFR3FlowBbGetRefBb(DBGFFLOWBB hFlowBb, PDBGFFLOWBB paFlowBbRef, uint32_t cRef)
2054{
2055 RT_NOREF3(hFlowBb, paFlowBbRef, cRef);
2056 return VERR_NOT_IMPLEMENTED;
2057}
2058
2059
2060/**
2061 * Retains a reference for the given control flow graph branch table.
2062 *
2063 * @returns new reference count.
2064 * @param hFlowBranchTbl The branch table handle.
2065 */
2066VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRetain(DBGFFLOWBRANCHTBL hFlowBranchTbl)
2067{
2068 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
2069 AssertPtrReturn(pFlowBranchTbl, UINT32_MAX);
2070
2071 uint32_t cRefs = ASMAtomicIncU32(&pFlowBranchTbl->cRefs);
2072 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pFlowBranchTbl));
2073 return cRefs;
2074}
2075
2076
2077/**
2078 * Releases a given branch table handle.
2079 *
2080 * @returns the new reference count of the given branch table, on 0 it is destroyed.
2081 * @param hFlowBranchTbl The branch table handle.
2082 */
2083VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRelease(DBGFFLOWBRANCHTBL hFlowBranchTbl)
2084{
2085 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
2086 if (!pFlowBranchTbl)
2087 return 0;
2088 AssertPtrReturn(pFlowBranchTbl, UINT32_MAX);
2089
2090 uint32_t cRefs = ASMAtomicDecU32(&pFlowBranchTbl->cRefs);
2091 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pFlowBranchTbl));
2092 if (cRefs == 0)
2093 dbgfR3FlowBranchTblDestroy(pFlowBranchTbl);
2094 return cRefs;
2095}
2096
2097
2098/**
2099 * Return the number of slots the branch table has.
2100 *
2101 * @returns Number of slots in the branch table.
2102 * @param hFlowBranchTbl The branch table handle.
2103 */
2104VMMR3DECL(uint32_t) DBGFR3FlowBranchTblGetSlots(DBGFFLOWBRANCHTBL hFlowBranchTbl)
2105{
2106 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
2107 AssertPtrReturn(pFlowBranchTbl, 0);
2108
2109 return pFlowBranchTbl->cSlots;
2110}
2111
2112
2113/**
2114 * Returns the start address of the branch table in the guest.
2115 *
2116 * @returns Pointer to start address of the branch table (pAddrStart).
2117 * @param hFlowBranchTbl The branch table handle.
2118 * @param pAddrStart Where to store the branch table address.
2119 */
2120VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetStartAddress(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS pAddrStart)
2121{
2122 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
2123 AssertPtrReturn(pFlowBranchTbl, NULL);
2124 AssertPtrReturn(pAddrStart, NULL);
2125
2126 *pAddrStart = pFlowBranchTbl->AddrStart;
2127 return pAddrStart;
2128}
2129
2130
2131/**
2132 * Returns one address in the branch table at the given slot index.
2133 *
2134 * @return Pointer to the address at the given slot in the given branch table.
2135 * @param hFlowBranchTbl The branch table handle.
2136 * @param idxSlot The slot the address should be returned from.
2137 * @param pAddrSlot Where to store the address.
2138 */
2139VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetAddrAtSlot(DBGFFLOWBRANCHTBL hFlowBranchTbl, uint32_t idxSlot, PDBGFADDRESS pAddrSlot)
2140{
2141 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
2142 AssertPtrReturn(pFlowBranchTbl, NULL);
2143 AssertPtrReturn(pAddrSlot, NULL);
2144 AssertReturn(idxSlot < pFlowBranchTbl->cSlots, NULL);
2145
2146 *pAddrSlot = pFlowBranchTbl->aAddresses[idxSlot];
2147 return pAddrSlot;
2148}
2149
2150
2151/**
2152 * Query all addresses contained in the given branch table.
2153 *
2154 * @returns VBox status code.
2155 * @retval VERR_BUFFER_OVERFLOW if there is not enough space in the array to hold all addresses.
2156 * @param hFlowBranchTbl The branch table handle.
2157 * @param paAddrs Where to store the addresses on success.
2158 * @param cAddrs Number of entries the array can hold.
2159 */
2160VMMR3DECL(int) DBGFR3FlowBranchTblQueryAddresses(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS paAddrs, uint32_t cAddrs)
2161{
2162 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
2163 AssertPtrReturn(pFlowBranchTbl, VERR_INVALID_HANDLE);
2164 AssertPtrReturn(paAddrs, VERR_INVALID_POINTER);
2165 AssertReturn(cAddrs > 0, VERR_INVALID_PARAMETER);
2166
2167 if (cAddrs < pFlowBranchTbl->cSlots)
2168 return VERR_BUFFER_OVERFLOW;
2169
2170 memcpy(paAddrs, &pFlowBranchTbl->aAddresses[0], pFlowBranchTbl->cSlots * sizeof(DBGFADDRESS));
2171 return VINF_SUCCESS;
2172}
2173
2174
2175/**
2176 * @callback_method_impl{FNRTSORTCMP}
2177 */
2178static DECLCALLBACK(int) dbgfR3FlowItSortCmp(void const *pvElement1, void const *pvElement2, void *pvUser)
2179{
2180 PDBGFFLOWITORDER penmOrder = (PDBGFFLOWITORDER)pvUser;
2181 PDBGFFLOWBBINT pFlowBb1 = *(PDBGFFLOWBBINT *)pvElement1;
2182 PDBGFFLOWBBINT pFlowBb2 = *(PDBGFFLOWBBINT *)pvElement2;
2183
2184 if (dbgfR3FlowAddrEqual(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
2185 return 0;
2186
2187 if (*penmOrder == DBGFFLOWITORDER_BY_ADDR_LOWEST_FIRST)
2188 {
2189 if (dbgfR3FlowAddrLower(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
2190 return -1;
2191 else
2192 return 1;
2193 }
2194 else
2195 {
2196 if (dbgfR3FlowAddrLower(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
2197 return 1;
2198 else
2199 return -1;
2200 }
2201}
2202
2203
2204/**
2205 * Creates a new iterator for the given control flow graph.
2206 *
2207 * @returns VBox status code.
2208 * @param hFlow The control flow graph handle.
2209 * @param enmOrder The order in which the basic blocks are enumerated.
2210 * @param phFlowIt Where to store the handle to the iterator on success.
2211 */
2212VMMR3DECL(int) DBGFR3FlowItCreate(DBGFFLOW hFlow, DBGFFLOWITORDER enmOrder, PDBGFFLOWIT phFlowIt)
2213{
2214 int rc = VINF_SUCCESS;
2215 PDBGFFLOWINT pFlow = hFlow;
2216 AssertPtrReturn(pFlow, VERR_INVALID_POINTER);
2217 AssertPtrReturn(phFlowIt, VERR_INVALID_POINTER);
2218 AssertReturn(enmOrder > DBGFFLOWITORDER_INVALID && enmOrder < DBGFFLOWITORDER_BREADTH_FIRST,
2219 VERR_INVALID_PARAMETER);
2220 AssertReturn(enmOrder < DBGFFLOWITORDER_DEPTH_FRIST, VERR_NOT_IMPLEMENTED); /** @todo */
2221
2222 PDBGFFLOWITINT pIt = (PDBGFFLOWITINT)RTMemAllocZ(RT_UOFFSETOF_DYN(DBGFFLOWITINT, apBb[pFlow->cBbs]));
2223 if (RT_LIKELY(pIt))
2224 {
2225 DBGFR3FlowRetain(hFlow);
2226 pIt->pFlow = pFlow;
2227 pIt->idxBbNext = 0;
2228 /* Fill the list and then sort. */
2229 uint32_t idxBb = 0;
2230 PDBGFFLOWBBINT pFlowBb;
2231 RTListForEach(&pFlow->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
2232 {
2233 DBGFR3FlowBbRetain(pFlowBb);
2234 pIt->apBb[idxBb++] = pFlowBb;
2235 }
2236
2237 /* Sort the blocks by address. */
2238 RTSortShell(&pIt->apBb[0], pFlow->cBbs, sizeof(PDBGFFLOWBBINT), dbgfR3FlowItSortCmp, &enmOrder);
2239
2240 *phFlowIt = pIt;
2241 }
2242 else
2243 rc = VERR_NO_MEMORY;
2244
2245 return rc;
2246}
2247
2248
2249/**
2250 * Destroys a given control flow graph iterator.
2251 *
2252 * @param hFlowIt The control flow graph iterator handle.
2253 */
2254VMMR3DECL(void) DBGFR3FlowItDestroy(DBGFFLOWIT hFlowIt)
2255{
2256 PDBGFFLOWITINT pIt = hFlowIt;
2257 AssertPtrReturnVoid(pIt);
2258
2259 for (unsigned i = 0; i < pIt->pFlow->cBbs; i++)
2260 DBGFR3FlowBbRelease(pIt->apBb[i]);
2261
2262 DBGFR3FlowRelease(pIt->pFlow);
2263 RTMemFree(pIt);
2264}
2265
2266
2267/**
2268 * Returns the next basic block in the iterator or NULL if there is no
2269 * basic block left.
2270 *
2271 * @returns Handle to the next basic block in the iterator or NULL if the end
2272 * was reached.
2273 * @param hFlowIt The iterator handle.
2274 *
2275 * @note If a valid handle is returned it must be release with DBGFR3FlowBbRelease()
2276 * when not required anymore.
2277 */
2278VMMR3DECL(DBGFFLOWBB) DBGFR3FlowItNext(DBGFFLOWIT hFlowIt)
2279{
2280 PDBGFFLOWITINT pIt = hFlowIt;
2281 AssertPtrReturn(pIt, NULL);
2282
2283 PDBGFFLOWBBINT pFlowBb = NULL;
2284 if (pIt->idxBbNext < pIt->pFlow->cBbs)
2285 {
2286 pFlowBb = pIt->apBb[pIt->idxBbNext++];
2287 DBGFR3FlowBbRetain(pFlowBb);
2288 }
2289
2290 return pFlowBb;
2291}
2292
2293
2294/**
2295 * Resets the given iterator to the beginning.
2296 *
2297 * @returns VBox status code.
2298 * @param hFlowIt The iterator handle.
2299 */
2300VMMR3DECL(int) DBGFR3FlowItReset(DBGFFLOWIT hFlowIt)
2301{
2302 PDBGFFLOWITINT pIt = hFlowIt;
2303 AssertPtrReturn(pIt, VERR_INVALID_HANDLE);
2304
2305 pIt->idxBbNext = 0;
2306 return VINF_SUCCESS;
2307}
2308
2309
2310/**
2311 * @callback_method_impl{FNRTSORTCMP}
2312 */
2313static DECLCALLBACK(int) dbgfR3FlowBranchTblItSortCmp(void const *pvElement1, void const *pvElement2, void *pvUser)
2314{
2315 PDBGFFLOWITORDER penmOrder = (PDBGFFLOWITORDER)pvUser;
2316 PDBGFFLOWBRANCHTBLINT pTbl1 = *(PDBGFFLOWBRANCHTBLINT *)pvElement1;
2317 PDBGFFLOWBRANCHTBLINT pTbl2 = *(PDBGFFLOWBRANCHTBLINT *)pvElement2;
2318
2319 if (dbgfR3FlowAddrEqual(&pTbl1->AddrStart, &pTbl2->AddrStart))
2320 return 0;
2321
2322 if (*penmOrder == DBGFFLOWITORDER_BY_ADDR_LOWEST_FIRST)
2323 {
2324 if (dbgfR3FlowAddrLower(&pTbl1->AddrStart, &pTbl2->AddrStart))
2325 return -1;
2326 else
2327 return 1;
2328 }
2329 else
2330 {
2331 if (dbgfR3FlowAddrLower(&pTbl1->AddrStart, &pTbl2->AddrStart))
2332 return 1;
2333 else
2334 return -1;
2335 }
2336}
2337
2338
2339/**
2340 * Creates a new branch table iterator for the given control flow graph.
2341 *
2342 * @returns VBox status code.
2343 * @param hFlow The control flow graph handle.
2344 * @param enmOrder The order in which the basic blocks are enumerated.
2345 * @param phFlowBranchTblIt Where to store the handle to the iterator on success.
2346 */
2347VMMR3DECL(int) DBGFR3FlowBranchTblItCreate(DBGFFLOW hFlow, DBGFFLOWITORDER enmOrder,
2348 PDBGFFLOWBRANCHTBLIT phFlowBranchTblIt)
2349{
2350 int rc = VINF_SUCCESS;
2351 PDBGFFLOWINT pFlow = hFlow;
2352 AssertPtrReturn(pFlow, VERR_INVALID_POINTER);
2353 AssertPtrReturn(phFlowBranchTblIt, VERR_INVALID_POINTER);
2354 AssertReturn(enmOrder > DBGFFLOWITORDER_INVALID && enmOrder < DBGFFLOWITORDER_BREADTH_FIRST,
2355 VERR_INVALID_PARAMETER);
2356 AssertReturn(enmOrder < DBGFFLOWITORDER_DEPTH_FRIST, VERR_NOT_SUPPORTED);
2357
2358 PDBGFFLOWBRANCHTBLITINT pIt = (PDBGFFLOWBRANCHTBLITINT)RTMemAllocZ(RT_UOFFSETOF_DYN(DBGFFLOWBRANCHTBLITINT,
2359 apBranchTbl[pFlow->cBranchTbls]));
2360 if (RT_LIKELY(pIt))
2361 {
2362 DBGFR3FlowRetain(hFlow);
2363 pIt->pFlow = pFlow;
2364 pIt->idxTblNext = 0;
2365 /* Fill the list and then sort. */
2366 uint32_t idxTbl = 0;
2367 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl;
2368 RTListForEach(&pFlow->LstBranchTbl, pFlowBranchTbl, DBGFFLOWBRANCHTBLINT, NdBranchTbl)
2369 {
2370 DBGFR3FlowBranchTblRetain(pFlowBranchTbl);
2371 pIt->apBranchTbl[idxTbl++] = pFlowBranchTbl;
2372 }
2373
2374 /* Sort the blocks by address. */
2375 RTSortShell(&pIt->apBranchTbl[0], pFlow->cBranchTbls, sizeof(PDBGFFLOWBRANCHTBLINT), dbgfR3FlowBranchTblItSortCmp, &enmOrder);
2376
2377 *phFlowBranchTblIt = pIt;
2378 }
2379 else
2380 rc = VERR_NO_MEMORY;
2381
2382 return rc;
2383}
2384
2385
2386/**
2387 * Destroys a given control flow graph branch table iterator.
2388 *
2389 * @param hFlowBranchTblIt The control flow graph branch table iterator handle.
2390 */
2391VMMR3DECL(void) DBGFR3FlowBranchTblItDestroy(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt)
2392{
2393 PDBGFFLOWBRANCHTBLITINT pIt = hFlowBranchTblIt;
2394 AssertPtrReturnVoid(pIt);
2395
2396 for (unsigned i = 0; i < pIt->pFlow->cBranchTbls; i++)
2397 DBGFR3FlowBranchTblRelease(pIt->apBranchTbl[i]);
2398
2399 DBGFR3FlowRelease(pIt->pFlow);
2400 RTMemFree(pIt);
2401}
2402
2403
2404/**
2405 * Returns the next branch table in the iterator or NULL if there is no
2406 * branch table left.
2407 *
2408 * @returns Handle to the next basic block in the iterator or NULL if the end
2409 * was reached.
2410 * @param hFlowBranchTblIt The iterator handle.
2411 *
2412 * @note If a valid handle is returned it must be release with DBGFR3FlowBranchTblRelease()
2413 * when not required anymore.
2414 */
2415VMMR3DECL(DBGFFLOWBRANCHTBL) DBGFR3FlowBranchTblItNext(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt)
2416{
2417 PDBGFFLOWBRANCHTBLITINT pIt = hFlowBranchTblIt;
2418 AssertPtrReturn(pIt, NULL);
2419
2420 PDBGFFLOWBRANCHTBLINT pTbl = NULL;
2421 if (pIt->idxTblNext < pIt->pFlow->cBranchTbls)
2422 {
2423 pTbl = pIt->apBranchTbl[pIt->idxTblNext++];
2424 DBGFR3FlowBranchTblRetain(pTbl);
2425 }
2426
2427 return pTbl;
2428}
2429
2430
2431/**
2432 * Resets the given iterator to the beginning.
2433 *
2434 * @returns VBox status code.
2435 * @param hFlowBranchTblIt The iterator handle.
2436 */
2437VMMR3DECL(int) DBGFR3FlowBranchTblItReset(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt)
2438{
2439 PDBGFFLOWBRANCHTBLITINT pIt = hFlowBranchTblIt;
2440 AssertPtrReturn(pIt, VERR_INVALID_HANDLE);
2441
2442 pIt->idxTblNext = 0;
2443 return VINF_SUCCESS;
2444}
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