VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFR3Cfg.cpp@ 64552

Last change on this file since 64552 was 64552, checked in by vboxsync, 8 years ago

DBGFR3Cfg: Additions to the API

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 64.3 KB
Line 
1/* $Id: DBGFR3Cfg.cpp 64552 2016-11-04 10:37:28Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Control Flow Graph Interface (CFG).
4 */
5
6/*
7 * Copyright (C) 2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/** @page pg_dbgf_cfg DBGFR3Cfg - Control Flow Graph Interface
20 *
21 * The control flow graph interface provides an API to disassemble
22 * guest code providing the result in a control flow graph.
23 */
24
25
26/*********************************************************************************************************************************
27* Header Files *
28*********************************************************************************************************************************/
29#define LOG_GROUP LOG_GROUP_DBGF
30#include <VBox/vmm/dbgf.h>
31#include "DBGFInternal.h"
32#include <VBox/vmm/mm.h>
33#include <VBox/vmm/uvm.h>
34#include <VBox/vmm/vm.h>
35#include <VBox/err.h>
36#include <VBox/log.h>
37
38#include <iprt/assert.h>
39#include <iprt/thread.h>
40#include <iprt/param.h>
41#include <iprt/list.h>
42#include <iprt/mem.h>
43#include <iprt/sort.h>
44#include <iprt/strcache.h>
45
46/*********************************************************************************************************************************
47* Defined Constants And Macros *
48*********************************************************************************************************************************/
49
50
51
52/*********************************************************************************************************************************
53* Structures and Typedefs *
54*********************************************************************************************************************************/
55
56/**
57 * Internal control flow graph state.
58 */
59typedef struct DBGFCFGINT
60{
61 /** Reference counter. */
62 uint32_t volatile cRefs;
63 /** Internal reference counter for basic blocks. */
64 uint32_t volatile cRefsBb;
65 /** List of all basic blocks. */
66 RTLISTANCHOR LstCfgBb;
67 /** Number of basic blocks in this control flow graph. */
68 uint32_t cBbs;
69 /** The lowest addres of a basic block. */
70 DBGFADDRESS AddrLowest;
71 /** The highest address of a basic block. */
72 DBGFADDRESS AddrHighest;
73 /** String cache for disassembled instructions. */
74 RTSTRCACHE hStrCacheInstr;
75} DBGFCFGINT;
76/** Pointer to an internal control flow graph state. */
77typedef DBGFCFGINT *PDBGFCFGINT;
78
79/**
80 * Instruction record
81 */
82typedef struct DBGFCFGBBINSTR
83{
84 /** Instruction address. */
85 DBGFADDRESS AddrInstr;
86 /** Size of instruction. */
87 uint32_t cbInstr;
88 /** Disassembled instruction string. */
89 const char *pszInstr;
90} DBGFCFGBBINSTR;
91/** Pointer to an instruction record. */
92typedef DBGFCFGBBINSTR *PDBGFCFGBBINSTR;
93
94/**
95 * Internal control flow graph basic block state.
96 */
97typedef struct DBGFCFGBBINT
98{
99 /** Node for the list of all basic blocks. */
100 RTLISTNODE NdCfgBb;
101 /** The control flow graph the basic block belongs to. */
102 PDBGFCFGINT pCfg;
103 /** Reference counter. */
104 uint32_t volatile cRefs;
105 /** Basic block end type. */
106 DBGFCFGBBENDTYPE enmEndType;
107 /** Start address of this basic block. */
108 DBGFADDRESS AddrStart;
109 /** End address of this basic block. */
110 DBGFADDRESS AddrEnd;
111 /** Address of the block succeeding.
112 * This is valid for conditional jumps
113 * (the other target is referenced by AddrEnd+1) and
114 * unconditional jumps (not ret, iret, etc.) except
115 * if we can't infer the jump target (jmp *eax for example). */
116 DBGFADDRESS AddrTarget;
117 /** Last status error code if DBGF_CFG_BB_F_INCOMPLETE_ERR is set. */
118 int rcError;
119 /** Error message if DBGF_CFG_BB_F_INCOMPLETE_ERR is set. */
120 char *pszErr;
121 /** Flags for this basic block. */
122 uint32_t fFlags;
123 /** Number of instructions in this basic block. */
124 uint32_t cInstr;
125 /** Maximum number of instruction records for this basic block. */
126 uint32_t cInstrMax;
127 /** Instruction records, variable in size. */
128 DBGFCFGBBINSTR aInstr[1];
129} DBGFCFGBBINT;
130/** Pointer to an internal control flow graph basic block state. */
131typedef DBGFCFGBBINT *PDBGFCFGBBINT;
132
133/**
134 * Control flow graph iterator state.
135 */
136typedef struct DBGFCFGITINT
137{
138 /** Pointer to the control flow graph (holding a reference). */
139 PDBGFCFGINT pCfg;
140 /** Next basic block to return. */
141 uint32_t idxBbNext;
142 /** Array of basic blocks sorted by the specified order - variable in size. */
143 PDBGFCFGBBINT apBb[1];
144} DBGFCFGITINT;
145/** Pointer to the internal control flow graph iterator state. */
146typedef DBGFCFGITINT *PDBGFCFGITINT;
147
148/**
149 * Dumper state for a basic block.
150 */
151typedef struct DBGFCFGDUMPBB
152{
153 /** The basic block referenced. */
154 PDBGFCFGBBINT pCfgBb;
155 /** Width of the basic block in chars. */
156 uint32_t cchWidth;
157 /** Height of the basic block in chars. */
158 uint32_t cchHeight;
159 /** X coordinate of the start. */
160 uint32_t uStartX;
161 /** Y coordinate of the start. */
162 uint32_t uStartY;
163} DBGFCFGDUMPBB;
164/** Pointer to a basic block dumper state. */
165typedef DBGFCFGDUMPBB *PDBGFCFGDUMPBB;
166
167/**
168 * Dumper ASCII screen.
169 */
170typedef struct DBGFCFGDUMPSCREEN
171{
172 /** Width of the screen. */
173 uint32_t cchWidth;
174 /** Height of the screen. */
175 uint32_t cchHeight;
176 /** Extra amount of characters at the end of each line (usually temrinator). */
177 uint32_t cchStride;
178 /** Pointer to the char buffer. */
179 char *pszScreen;
180} DBGFCFGDUMPSCREEN;
181/** Pointer to a dumper ASCII screen. */
182typedef DBGFCFGDUMPSCREEN *PDBGFCFGDUMPSCREEN;
183
184/*********************************************************************************************************************************
185* Internal Functions *
186*********************************************************************************************************************************/
187
188static uint32_t dbgfR3CfgBbReleaseInt(PDBGFCFGBBINT pCfgBb, bool fMayDestroyCfg);
189
190/**
191 * Creates a new basic block.
192 *
193 * @returns Pointer to the basic block on success or NULL if out of memory.
194 * @param pThis The control flow graph.
195 * @param pAddrStart The start of the basic block.
196 * @param cInstrMax Maximum number of instructions this block can hold initially.
197 */
198static PDBGFCFGBBINT dbgfR3CfgBbCreate(PDBGFCFGINT pThis, PDBGFADDRESS pAddrStart, uint32_t cInstrMax)
199{
200 PDBGFCFGBBINT pCfgBb = (PDBGFCFGBBINT)RTMemAllocZ(RT_OFFSETOF(DBGFCFGBBINT, aInstr[cInstrMax]));
201 if (RT_LIKELY(pCfgBb))
202 {
203 RTListInit(&pCfgBb->NdCfgBb);
204 pCfgBb->cRefs = 1;
205 pCfgBb->enmEndType = DBGFCFGBBENDTYPE_INVALID;
206 pCfgBb->pCfg = pThis;
207 pCfgBb->fFlags = DBGF_CFG_BB_F_EMPTY;
208 pCfgBb->AddrStart = *pAddrStart;
209 pCfgBb->AddrEnd = *pAddrStart;
210 pCfgBb->rcError = VINF_SUCCESS;
211 pCfgBb->pszErr = NULL;
212 pCfgBb->cInstr = 0;
213 pCfgBb->cInstrMax = cInstrMax;
214 ASMAtomicIncU32(&pThis->cRefsBb);
215 }
216
217 return pCfgBb;
218}
219
220
221/**
222 * Destroys a control flow graph.
223 *
224 * @returns nothing.
225 * @param pThis The control flow graph to destroy.
226 */
227static void dbgfR3CfgDestroy(PDBGFCFGINT pThis)
228{
229 /* Defer destruction if there are still basic blocks referencing us. */
230 PDBGFCFGBBINT pCfgBb = NULL;
231 PDBGFCFGBBINT pCfgBbNext = NULL;
232 RTListForEachSafe(&pThis->LstCfgBb, pCfgBb, pCfgBbNext, DBGFCFGBBINT, NdCfgBb)
233 {
234 dbgfR3CfgBbReleaseInt(pCfgBb, false /*fMayDestroyCfg*/);
235 }
236
237 Assert(!pThis->cRefs);
238 if (!pThis->cRefsBb)
239 {
240 RTStrCacheDestroy(pThis->hStrCacheInstr);
241 RTMemFree(pThis);
242 }
243}
244
245
246/**
247 * Destroys a basic block.
248 *
249 * @returns nothing.
250 * @param pCfgBb The basic block to destroy.
251 * @param fMayDestroyCfg Flag whether the control flow graph container
252 * should be destroyed when there is nothing referencing it.
253 */
254static void dbgfR3CfgBbDestroy(PDBGFCFGBBINT pCfgBb, bool fMayDestroyCfg)
255{
256 PDBGFCFGINT pThis = pCfgBb->pCfg;
257
258 RTListNodeRemove(&pCfgBb->NdCfgBb);
259 pThis->cBbs--;
260 for (uint32_t idxInstr = 0; idxInstr < pCfgBb->cInstr; idxInstr++)
261 RTStrCacheRelease(pThis->hStrCacheInstr, pCfgBb->aInstr[idxInstr].pszInstr);
262 uint32_t cRefsBb = ASMAtomicDecU32(&pThis->cRefsBb);
263 RTMemFree(pCfgBb);
264
265 if (!cRefsBb && !pThis->cRefs && fMayDestroyCfg)
266 dbgfR3CfgDestroy(pThis);
267}
268
269
270/**
271 * Internal basic block release worker.
272 *
273 * @returns New reference count of the released basic block, on 0
274 * it is destroyed.
275 * @param pCfgBb The basic block to release.
276 * @param fMayDestroyCfg Flag whether the control flow graph container
277 * should be destroyed when there is nothing referencing it.
278 */
279static uint32_t dbgfR3CfgBbReleaseInt(PDBGFCFGBBINT pCfgBb, bool fMayDestroyCfg)
280{
281 uint32_t cRefs = ASMAtomicDecU32(&pCfgBb->cRefs);
282 AssertMsg(cRefs < _1M, ("%#x %p %d\n", cRefs, pCfgBb, pCfgBb->enmEndType));
283 if (cRefs == 0)
284 dbgfR3CfgBbDestroy(pCfgBb, fMayDestroyCfg);
285 return cRefs;
286}
287
288
289/**
290 * Links the given basic block into the control flow graph.
291 *
292 * @returns nothing.
293 * @param pThis The control flow graph to link into.
294 * @param pCfgBb The basic block to link.
295 */
296DECLINLINE(void) dbgfR3CfgLink(PDBGFCFGINT pThis, PDBGFCFGBBINT pCfgBb)
297{
298 RTListAppend(&pThis->LstCfgBb, &pCfgBb->NdCfgBb);
299 pThis->cBbs++;
300}
301
302
303/**
304 * Returns the first unpopulated basic block of the given control flow graph.
305 *
306 * @returns The first unpopulated control flow graph or NULL if not found.
307 * @param pThis The control flow graph.
308 */
309DECLINLINE(PDBGFCFGBBINT) dbgfR3CfgGetUnpopulatedBb(PDBGFCFGINT pThis)
310{
311 PDBGFCFGBBINT pCfgBb = NULL;
312 RTListForEach(&pThis->LstCfgBb, pCfgBb, DBGFCFGBBINT, NdCfgBb)
313 {
314 if (pCfgBb->fFlags & DBGF_CFG_BB_F_EMPTY)
315 return pCfgBb;
316 }
317
318 return NULL;
319}
320
321
322/**
323 * Resolves the jump target address if possible from the given instruction address
324 * and instruction parameter.
325 *
326 * @returns VBox status code.
327 * @param pUVM The usermode VM handle.
328 * @param idCpu CPU id for resolving the address.
329 * @param pDisParam The parmeter from the disassembler.
330 * @param pAddrInstr The instruction address.
331 * @param cbInstr Size of instruction in bytes.
332 * @param fRelJmp Flag whether this is a reltive jump.
333 * @param pAddrJmpTarget Where to store the address to the jump target on success.
334 */
335static int dbgfR3CfgQueryJmpTarget(PUVM pUVM, VMCPUID idCpu, PDISOPPARAM pDisParam, PDBGFADDRESS pAddrInstr,
336 uint32_t cbInstr, bool fRelJmp, PDBGFADDRESS pAddrJmpTarget)
337{
338 int rc = VINF_SUCCESS;
339
340 /* Relative jumps are always from the beginning of the next instruction. */
341 *pAddrJmpTarget = *pAddrInstr;
342 DBGFR3AddrAdd(pAddrJmpTarget, cbInstr);
343
344 if (fRelJmp)
345 {
346 RTGCINTPTR iRel = 0;
347 if (pDisParam->fUse & DISUSE_IMMEDIATE8_REL)
348 iRel = (int8_t)pDisParam->uValue;
349 else if (pDisParam->fUse & DISUSE_IMMEDIATE16_REL)
350 iRel = (int16_t)pDisParam->uValue;
351 else if (pDisParam->fUse & DISUSE_IMMEDIATE32_REL)
352 iRel = (int32_t)pDisParam->uValue;
353 else if (pDisParam->fUse & DISUSE_IMMEDIATE64_REL)
354 iRel = (int64_t)pDisParam->uValue;
355 else
356 AssertFailedStmt(rc = VERR_NOT_SUPPORTED);
357
358 if (iRel < 0)
359 DBGFR3AddrSub(pAddrJmpTarget, -iRel);
360 else
361 DBGFR3AddrAdd(pAddrJmpTarget, iRel);
362 }
363 else
364 {
365 if (pDisParam->fUse & (DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32 | DISUSE_IMMEDIATE64))
366 {
367 if (DBGFADDRESS_IS_FLAT(pAddrInstr))
368 DBGFR3AddrFromFlat(pUVM, pAddrJmpTarget, pDisParam->uValue);
369 else
370 DBGFR3AddrFromSelOff(pUVM, idCpu, pAddrJmpTarget, pAddrInstr->Sel, pDisParam->uValue);
371 }
372 else
373 AssertFailedStmt(rc = VERR_NOT_SUPPORTED);
374 }
375
376 return rc;
377}
378
379
380/**
381 * Checks whether both addresses are equal.
382 *
383 * @returns true if both addresses point to the same location, false otherwise.
384 * @param pAddr1 First address.
385 * @param pAddr2 Second address.
386 */
387static bool dbgfR3CfgBbAddrEqual(PDBGFADDRESS pAddr1, PDBGFADDRESS pAddr2)
388{
389 return pAddr1->Sel == pAddr2->Sel
390 && pAddr1->off == pAddr2->off;
391}
392
393
394/**
395 * Checks whether the first given address is lower than the second one.
396 *
397 * @returns true if both addresses point to the same location, false otherwise.
398 * @param pAddr1 First address.
399 * @param pAddr2 Second address.
400 */
401static bool dbgfR3CfgBbAddrLower(PDBGFADDRESS pAddr1, PDBGFADDRESS pAddr2)
402{
403 return pAddr1->Sel == pAddr2->Sel
404 && pAddr1->off < pAddr2->off;
405}
406
407
408/**
409 * Checks whether the given basic block and address intersect.
410 *
411 * @returns true if they intersect, false otherwise.
412 * @param pCfgBb The basic block to check.
413 * @param pAddr The address to check for.
414 */
415static bool dbgfR3CfgBbAddrIntersect(PDBGFCFGBBINT pCfgBb, PDBGFADDRESS pAddr)
416{
417 return (pCfgBb->AddrStart.Sel == pAddr->Sel)
418 && (pCfgBb->AddrStart.off <= pAddr->off)
419 && (pCfgBb->AddrEnd.off >= pAddr->off);
420}
421
422
423/**
424 * Checks whether the given control flow graph contains a basic block
425 * with the given start address.
426 *
427 * @returns true if there is a basic block with the start address, false otherwise.
428 * @param pThis The control flow graph.
429 * @param pAddr The address to check for.
430 */
431static bool dbgfR3CfgHasBbWithStartAddr(PDBGFCFGINT pThis, PDBGFADDRESS pAddr)
432{
433 PDBGFCFGBBINT pCfgBb = NULL;
434 RTListForEach(&pThis->LstCfgBb, pCfgBb, DBGFCFGBBINT, NdCfgBb)
435 {
436 if (dbgfR3CfgBbAddrEqual(&pCfgBb->AddrStart, pAddr))
437 return true;
438 }
439 return false;
440}
441
442/**
443 * Splits a given basic block into two at the given address.
444 *
445 * @returns VBox status code.
446 * @param pThis The control flow graph.
447 * @param pCfgBb The basic block to split.
448 * @param pAddr The address to split at.
449 */
450static int dbgfR3CfgBbSplit(PDBGFCFGINT pThis, PDBGFCFGBBINT pCfgBb, PDBGFADDRESS pAddr)
451{
452 int rc = VINF_SUCCESS;
453 uint32_t idxInstrSplit;
454
455 /* If the block is empty it will get populated later so there is nothing to split,
456 * same if the start address equals. */
457 if ( pCfgBb->fFlags & DBGF_CFG_BB_F_EMPTY
458 || dbgfR3CfgBbAddrEqual(&pCfgBb->AddrStart, pAddr))
459 return VINF_SUCCESS;
460
461 /* Find the instruction to split at. */
462 for (idxInstrSplit = 1; idxInstrSplit < pCfgBb->cInstr; idxInstrSplit++)
463 if (dbgfR3CfgBbAddrEqual(&pCfgBb->aInstr[idxInstrSplit].AddrInstr, pAddr))
464 break;
465
466 Assert(idxInstrSplit > 0);
467
468 /*
469 * Given address might not be on instruction boundary, this is not supported
470 * so far and results in an error.
471 */
472 if (idxInstrSplit < pCfgBb->cInstr)
473 {
474 /* Create new basic block. */
475 uint32_t cInstrNew = pCfgBb->cInstr - idxInstrSplit;
476 PDBGFCFGBBINT pCfgBbNew = dbgfR3CfgBbCreate(pThis, &pCfgBb->aInstr[idxInstrSplit].AddrInstr,
477 cInstrNew);
478 if (pCfgBbNew)
479 {
480 /* Move instructions over. */
481 pCfgBbNew->cInstr = cInstrNew;
482 pCfgBbNew->AddrEnd = pCfgBb->AddrEnd;
483 pCfgBbNew->enmEndType = pCfgBb->enmEndType;
484 pCfgBbNew->fFlags = pCfgBb->fFlags & ~DBGF_CFG_BB_F_ENTRY;
485
486 /* Move any error to the new basic block and clear them in the old basic block. */
487 pCfgBbNew->rcError = pCfgBb->rcError;
488 pCfgBbNew->pszErr = pCfgBb->pszErr;
489 pCfgBb->rcError = VINF_SUCCESS;
490 pCfgBb->pszErr = NULL;
491 pCfgBb->fFlags &= ~DBGF_CFG_BB_F_INCOMPLETE_ERR;
492
493 memcpy(&pCfgBbNew->aInstr[0], &pCfgBb->aInstr[idxInstrSplit], cInstrNew * sizeof(DBGFCFGBBINSTR));
494 pCfgBb->cInstr = idxInstrSplit;
495 pCfgBb->enmEndType = DBGFCFGBBENDTYPE_UNCOND;
496 pCfgBb->AddrEnd = pCfgBb->aInstr[idxInstrSplit-1].AddrInstr;
497 pCfgBb->AddrTarget = pCfgBbNew->AddrStart;
498 DBGFR3AddrAdd(&pCfgBb->AddrEnd, pCfgBb->aInstr[idxInstrSplit-1].cbInstr - 1);
499 RT_BZERO(&pCfgBb->aInstr[idxInstrSplit], cInstrNew * sizeof(DBGFCFGBBINSTR));
500
501 dbgfR3CfgLink(pThis, pCfgBbNew);
502 }
503 else
504 rc = VERR_NO_MEMORY;
505 }
506 else
507 AssertFailedStmt(rc = VERR_INVALID_STATE); /** @todo: Proper status code. */
508
509 return rc;
510}
511
512
513/**
514 * Makes sure there is an successor at the given address splitting already existing
515 * basic blocks if they intersect.
516 *
517 * @returns VBox status code.
518 * @param pThis The control flow graph.
519 * @param pAddrSucc The guest address the new successor should start at.
520 */
521static int dbgfR3CfgBbSuccessorAdd(PDBGFCFGINT pThis, PDBGFADDRESS pAddrSucc)
522{
523 PDBGFCFGBBINT pCfgBb = NULL;
524 RTListForEach(&pThis->LstCfgBb, pCfgBb, DBGFCFGBBINT, NdCfgBb)
525 {
526 /*
527 * The basic block must be split if it intersects with the given address
528 * and the start address does not equal the given one.
529 */
530 if (dbgfR3CfgBbAddrIntersect(pCfgBb, pAddrSucc))
531 return dbgfR3CfgBbSplit(pThis, pCfgBb, pAddrSucc);
532 }
533
534 int rc = VINF_SUCCESS;
535 pCfgBb = dbgfR3CfgBbCreate(pThis, pAddrSucc, 10);
536 if (pCfgBb)
537 dbgfR3CfgLink(pThis, pCfgBb);
538 else
539 rc = VERR_NO_MEMORY;
540
541 return rc;
542}
543
544
545/**
546 * Sets the given error status for the basic block.
547 *
548 * @returns nothing.
549 * @param pCfgBb The basic block causing the error.
550 * @param rcError The error to set.
551 * @param pszFmt Format string of the error description.
552 * @param ... Arguments for the format string.
553 */
554static void dbgfR3CfgBbSetError(PDBGFCFGBBINT pCfgBb, int rcError, const char *pszFmt, ...)
555{
556 va_list va;
557 va_start(va, pszFmt);
558
559 Assert(!(pCfgBb->fFlags & DBGF_CFG_BB_F_INCOMPLETE_ERR));
560 pCfgBb->fFlags |= DBGF_CFG_BB_F_INCOMPLETE_ERR;
561 pCfgBb->fFlags &= ~DBGF_CFG_BB_F_EMPTY;
562 pCfgBb->rcError = rcError;
563 pCfgBb->pszErr = RTStrAPrintf2V(pszFmt, va);
564 va_end(va);
565}
566
567
568/**
569 * Processes and fills one basic block.
570 *
571 * @returns VBox status code.
572 * @param pUVM The user mode VM handle.
573 * @param idCpu CPU id for disassembling.
574 * @param pThis The control flow graph to populate.
575 * @param pCfgBb The basic block to fill.
576 * @param cbDisasmMax The maximum amount to disassemble.
577 * @param fFlags Combination of DBGF_DISAS_FLAGS_*.
578 */
579static int dbgfR3CfgBbProcess(PUVM pUVM, VMCPUID idCpu, PDBGFCFGINT pThis, PDBGFCFGBBINT pCfgBb,
580 uint32_t cbDisasmMax, uint32_t fFlags)
581{
582 int rc = VINF_SUCCESS;
583 uint32_t cbDisasmLeft = cbDisasmMax ? cbDisasmMax : UINT32_MAX;
584 DBGFADDRESS AddrDisasm = pCfgBb->AddrEnd;
585
586 Assert(pCfgBb->fFlags & DBGF_CFG_BB_F_EMPTY);
587
588 /*
589 * Disassemble instruction by instruction until we get a conditional or
590 * unconditional jump or some sort of return.
591 */
592 while ( cbDisasmLeft
593 && RT_SUCCESS(rc))
594 {
595 DBGFDISSTATE DisState;
596 char szOutput[_4K];
597
598 /*
599 * Before disassembling we have to check whether the address belongs
600 * to another basic block and stop here.
601 */
602 if ( !(pCfgBb->fFlags & DBGF_CFG_BB_F_EMPTY)
603 && dbgfR3CfgHasBbWithStartAddr(pThis, &AddrDisasm))
604 {
605 pCfgBb->AddrTarget = AddrDisasm;
606 pCfgBb->enmEndType = DBGFCFGBBENDTYPE_UNCOND;
607 break;
608 }
609
610 pCfgBb->fFlags &= ~DBGF_CFG_BB_F_EMPTY;
611
612 rc = dbgfR3DisasInstrStateEx(pUVM, idCpu, &AddrDisasm, fFlags,
613 &szOutput[0], sizeof(szOutput), &DisState);
614 if (RT_SUCCESS(rc))
615 {
616 cbDisasmLeft -= DisState.cbInstr;
617
618 if (pCfgBb->cInstr == pCfgBb->cInstrMax)
619 {
620 /* Reallocate. */
621 RTListNodeRemove(&pCfgBb->NdCfgBb);
622 PDBGFCFGBBINT pCfgBbNew = (PDBGFCFGBBINT)RTMemRealloc(pCfgBb, RT_OFFSETOF(DBGFCFGBBINT, aInstr[pCfgBb->cInstrMax + 10]));
623 if (pCfgBbNew)
624 {
625 pCfgBbNew->cInstrMax += 10;
626 pCfgBb = pCfgBbNew;
627 }
628 else
629 rc = VERR_NO_MEMORY;
630 RTListAppend(&pThis->LstCfgBb, &pCfgBb->NdCfgBb);
631 }
632
633 if (RT_SUCCESS(rc))
634 {
635 PDBGFCFGBBINSTR pInstr = &pCfgBb->aInstr[pCfgBb->cInstr];
636
637 pInstr->AddrInstr = AddrDisasm;
638 pInstr->cbInstr = DisState.cbInstr;
639 pInstr->pszInstr = RTStrCacheEnter(pThis->hStrCacheInstr, &szOutput[0]);
640 pCfgBb->cInstr++;
641
642 pCfgBb->AddrEnd = AddrDisasm;
643 DBGFR3AddrAdd(&pCfgBb->AddrEnd, pInstr->cbInstr - 1);
644 DBGFR3AddrAdd(&AddrDisasm, pInstr->cbInstr);
645
646 /*
647 * Check control flow instructions and create new basic blocks
648 * marking the current one as complete.
649 */
650 if (DisState.pCurInstr->fOpType & DISOPTYPE_CONTROLFLOW)
651 {
652 uint16_t uOpc = DisState.pCurInstr->uOpcode;
653
654 if ( uOpc == OP_RETN || uOpc == OP_RETF || uOpc == OP_IRET
655 || uOpc == OP_SYSEXIT || uOpc == OP_SYSRET)
656 pCfgBb->enmEndType = DBGFCFGBBENDTYPE_EXIT;
657 else if (uOpc == OP_JMP)
658 {
659 Assert(DisState.pCurInstr->fOpType & DISOPTYPE_UNCOND_CONTROLFLOW);
660 pCfgBb->enmEndType = DBGFCFGBBENDTYPE_UNCOND_JMP;
661
662 /* Create one new basic block with the jump target address. */
663 rc = dbgfR3CfgQueryJmpTarget(pUVM, idCpu, &DisState.Param1, &pInstr->AddrInstr, pInstr->cbInstr,
664 RT_BOOL(DisState.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW),
665 &pCfgBb->AddrTarget);
666 if (RT_SUCCESS(rc))
667 rc = dbgfR3CfgBbSuccessorAdd(pThis, &pCfgBb->AddrTarget);
668 }
669 else if (uOpc != OP_CALL)
670 {
671 Assert(DisState.pCurInstr->fOpType & DISOPTYPE_COND_CONTROLFLOW);
672 pCfgBb->enmEndType = DBGFCFGBBENDTYPE_COND;
673
674 /*
675 * Create two new basic blocks, one with the jump target address
676 * and one starting after the current instruction.
677 */
678 rc = dbgfR3CfgBbSuccessorAdd(pThis, &AddrDisasm);
679 if (RT_SUCCESS(rc))
680 {
681 rc = dbgfR3CfgQueryJmpTarget(pUVM, idCpu, &DisState.Param1, &pInstr->AddrInstr, pInstr->cbInstr,
682 RT_BOOL(DisState.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW),
683 &pCfgBb->AddrTarget);
684 if (RT_SUCCESS(rc))
685 rc = dbgfR3CfgBbSuccessorAdd(pThis, &pCfgBb->AddrTarget);
686 }
687 }
688
689 if (RT_FAILURE(rc))
690 dbgfR3CfgBbSetError(pCfgBb, rc, "Adding successor blocks failed with %Rrc", rc);
691
692 /* Quit disassembling. */
693 if ( uOpc != OP_CALL
694 || RT_FAILURE(rc))
695 break;
696 }
697 }
698 else
699 dbgfR3CfgBbSetError(pCfgBb, rc, "Increasing basic block failed with %Rrc", rc);
700 }
701 else
702 dbgfR3CfgBbSetError(pCfgBb, rc, "Disassembling the instruction failed with %Rrc", rc);
703 }
704
705 return VINF_SUCCESS;
706}
707
708/**
709 * Populate all empty basic blocks.
710 *
711 * @returns VBox status code.
712 * @param pUVM The user mode VM handle.
713 * @param idCpu CPU id for disassembling.
714 * @param pThis The control flow graph to populate.
715 * @param pAddrStart The start address to disassemble at.
716 * @param cbDisasmMax The maximum amount to disassemble.
717 * @param fFlags Combination of DBGF_DISAS_FLAGS_*.
718 */
719static int dbgfR3CfgPopulate(PUVM pUVM, VMCPUID idCpu, PDBGFCFGINT pThis, PDBGFADDRESS pAddrStart,
720 uint32_t cbDisasmMax, uint32_t fFlags)
721{
722 int rc = VINF_SUCCESS;
723 PDBGFCFGBBINT pCfgBb = dbgfR3CfgGetUnpopulatedBb(pThis);
724 DBGFADDRESS AddrEnd = *pAddrStart;
725 DBGFR3AddrAdd(&AddrEnd, cbDisasmMax);
726
727 while (VALID_PTR(pCfgBb))
728 {
729 rc = dbgfR3CfgBbProcess(pUVM, idCpu, pThis, pCfgBb, cbDisasmMax, fFlags);
730 if (RT_FAILURE(rc))
731 break;
732
733 pCfgBb = dbgfR3CfgGetUnpopulatedBb(pThis);
734 }
735
736 return rc;
737}
738
739/**
740 * Creates a new control flow graph from the given start address.
741 *
742 * @returns VBox status code.
743 * @param pUVM The user mode VM handle.
744 * @param idCpu CPU id for disassembling.
745 * @param pAddressStart Where to start creating the control flow graph.
746 * @param cbDisasmMax Limit the amount of bytes to disassemble, 0 for no limit.
747 * @param fFlags Combination of DBGF_DISAS_FLAGS_*.
748 * @param phCfg Where to store the handle to the control flow graph on success.
749 */
750VMMR3DECL(int) DBGFR3CfgCreate(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddressStart, uint32_t cbDisasmMax,
751 uint32_t fFlags, PDBGFCFG phCfg)
752{
753 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
754 PVM pVM = pUVM->pVM;
755 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
756 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
757 AssertPtrReturn(pAddressStart, VERR_INVALID_POINTER);
758 AssertReturn(!(fFlags & ~DBGF_DISAS_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
759 AssertReturn((fFlags & DBGF_DISAS_FLAGS_MODE_MASK) <= DBGF_DISAS_FLAGS_64BIT_MODE, VERR_INVALID_PARAMETER);
760
761 /* Create the control flow graph container. */
762 int rc = VINF_SUCCESS;
763 PDBGFCFGINT pThis = (PDBGFCFGINT)RTMemAllocZ(sizeof(DBGFCFGINT));
764 if (RT_LIKELY(pThis))
765 {
766 rc = RTStrCacheCreate(&pThis->hStrCacheInstr, "DBGFCFG");
767 if (RT_SUCCESS(rc))
768 {
769 pThis->cRefs = 1;
770 pThis->cRefsBb = 0;
771 pThis->cBbs = 0;
772 RTListInit(&pThis->LstCfgBb);
773 /* Create the entry basic block and start the work. */
774
775 PDBGFCFGBBINT pCfgBb = dbgfR3CfgBbCreate(pThis, pAddressStart, 10);
776 if (RT_LIKELY(pCfgBb))
777 {
778 pCfgBb->fFlags |= DBGF_CFG_BB_F_ENTRY;
779 dbgfR3CfgLink(pThis, pCfgBb);
780 rc = dbgfR3CfgPopulate(pUVM, idCpu, pThis, pAddressStart, cbDisasmMax, fFlags);
781 if (RT_SUCCESS(rc))
782 {
783 *phCfg = pThis;
784 return VINF_SUCCESS;
785 }
786 }
787 else
788 rc = VERR_NO_MEMORY;
789 }
790
791 ASMAtomicDecU32(&pThis->cRefs);
792 dbgfR3CfgDestroy(pThis);
793 }
794 else
795 rc = VERR_NO_MEMORY;
796
797 return rc;
798}
799
800
801/**
802 * Retains the control flow graph handle.
803 *
804 * @returns Current reference count.
805 * @param hCfg The control flow graph handle to retain.
806 */
807VMMR3DECL(uint32_t) DBGFR3CfgRetain(DBGFCFG hCfg)
808{
809 PDBGFCFGINT pThis = hCfg;
810 AssertPtrReturn(pThis, UINT32_MAX);
811
812 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
813 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
814 return cRefs;
815}
816
817
818/**
819 * Releases the control flow graph handle.
820 *
821 * @returns Current reference count, on 0 the control flow graph will be destroyed.
822 * @param hCfg The control flow graph handle to release.
823 */
824VMMR3DECL(uint32_t) DBGFR3CfgRelease(DBGFCFG hCfg)
825{
826 PDBGFCFGINT pThis = hCfg;
827 if (!pThis)
828 return 0;
829 AssertPtrReturn(pThis, UINT32_MAX);
830
831 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
832 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
833 if (cRefs == 0)
834 dbgfR3CfgDestroy(pThis);
835 return cRefs;
836}
837
838
839/**
840 * Queries the basic block denoting the entry point into the control flow graph.
841 *
842 * @returns VBox status code.
843 * @param hCfg The control flow graph handle.
844 * @param phCfgBb Where to store the basic block handle on success.
845 */
846VMMR3DECL(int) DBGFR3CfgQueryStartBb(DBGFCFG hCfg, PDBGFCFGBB phCfgBb)
847{
848 PDBGFCFGINT pThis = hCfg;
849 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
850
851 PDBGFCFGBBINT pCfgBb = NULL;
852 RTListForEach(&pThis->LstCfgBb, pCfgBb, DBGFCFGBBINT, NdCfgBb)
853 {
854 if (pCfgBb->fFlags & DBGF_CFG_BB_F_ENTRY)
855 {
856 *phCfgBb = pCfgBb;
857 return VINF_SUCCESS;
858 }
859 }
860
861 AssertFailed(); /* Should never get here. */
862 return VERR_INTERNAL_ERROR;
863}
864
865
866/**
867 * Queries a basic block in the given control flow graph which covers the given
868 * address.
869 *
870 * @returns VBox status code.
871 * @retval VERR_NOT_FOUND if there is no basic block intersecting with the address.
872 * @param hCfg The control flow graph handle.
873 * @param pAddr The address to look for.
874 * @param phCfgBb Where to store the basic block handle on success.
875 */
876VMMR3DECL(int) DBGFR3CfgQueryBbByAddress(DBGFCFG hCfg, PDBGFADDRESS pAddr, PDBGFCFGBB phCfgBb)
877{
878 PDBGFCFGINT pThis = hCfg;
879 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
880 AssertPtrReturn(phCfgBb, VERR_INVALID_POINTER);
881
882 PDBGFCFGBBINT pCfgBb = NULL;
883 RTListForEach(&pThis->LstCfgBb, pCfgBb, DBGFCFGBBINT, NdCfgBb)
884 {
885 if (dbgfR3CfgBbAddrIntersect(pCfgBb, pAddr))
886 {
887 DBGFR3CfgBbRetain(pCfgBb);
888 *phCfgBb = pCfgBb;
889 return VINF_SUCCESS;
890 }
891 }
892
893 return VERR_NOT_FOUND;
894}
895
896
897/**
898 * Returns the number of basic blcoks inside the control flow graph.
899 *
900 * @returns Number of basic blocks.
901 * @param hCfg The control flow graph handle.
902 */
903VMMR3DECL(uint32_t) DBGFR3CfgGetBbCount(DBGFCFG hCfg)
904{
905 PDBGFCFGINT pThis = hCfg;
906 AssertPtrReturn(pThis, 0);
907
908 return pThis->cBbs;
909}
910
911
912/**
913 * Returns the buffer starting at the given position.
914 *
915 * @returns Pointer to the ASCII buffer.
916 * @param pScreen The screen.
917 * @param uX Horizontal position.
918 * @param uY Vertical position.
919 */
920static char *dbgfR3CfgDumpScreenGetBufferAtPos(PDBGFCFGDUMPSCREEN pScreen, uint32_t uX, uint32_t uY)
921{
922 AssertReturn(uX < pScreen->cchWidth && uY < pScreen->cchHeight, NULL);
923 return pScreen->pszScreen + (pScreen->cchWidth + pScreen->cchStride) * uY + uX;
924}
925
926
927/**
928 * Draws a single pixel to the screen at the given coordinates.
929 *
930 * @returns nothing.
931 * @param pScreen The screen.
932 * @param uX X coordinate.
933 * @param uY Y coordinate.
934 * @param ch Character to draw.
935 */
936DECLINLINE(void) dbgfR3CfgDumpScreenDrawPixel(PDBGFCFGDUMPSCREEN pScreen, uint32_t uX, uint32_t uY, char ch)
937{
938 char *psz = dbgfR3CfgDumpScreenGetBufferAtPos(pScreen, uX, uY);
939 AssertPtrReturnVoid(psz);
940 AssertReturnVoid(*psz != '\0');
941 *psz = ch;
942}
943
944
945/**
946 * Draws a horizontal line at the given coordinates.
947 *
948 * @returns nothing.
949 * @param pScreen The screen.
950 * @param uStartX X position to start drawing.
951 * @param uEndX X position to draw the line to (inclusive).
952 * @param uY Y position.
953 * @param ch The character to use for drawing.
954 */
955static void dbgfR3CfgDumpScreenDrawLineHorizontal(PDBGFCFGDUMPSCREEN pScreen, uint32_t uStartX, uint32_t uEndX,
956 uint32_t uY, char ch)
957{
958 char *psz = dbgfR3CfgDumpScreenGetBufferAtPos(pScreen, uStartX, uY);
959 AssertPtrReturnVoid(psz);
960 //AssertReturnVoid(psz[uEndX - uStartX + 1] != '\0'); /* Triggers during initialization. */
961
962 memset(psz, ch, uEndX - uStartX + 1);
963}
964
965
966/**
967 * Draws a vertical line at the given coordinates.
968 *
969 * @returns nothing.
970 * @param pScreen The screen.
971 * @param uX X position to draw.
972 * @param uStartY Y position to start drawing.
973 * @param uEndY Y position to draw to (inclusive).
974 * @param ch The character to use for drawing.
975 */
976static void dbgfR3CfgDumpScreenDrawLineVertical(PDBGFCFGDUMPSCREEN pScreen, uint32_t uX, uint32_t uStartY,
977 uint32_t uEndY, char ch)
978{
979 while (uStartY <= uEndY)
980 {
981 char *psz = dbgfR3CfgDumpScreenGetBufferAtPos(pScreen, uX, uStartY);
982 AssertPtrReturnVoid(psz);
983 *psz = ch;
984 uStartY++;
985 }
986}
987
988
989/**
990 * Creates a new ASCII screen for layouting.
991 *
992 * @returns VBox status code.
993 * @param ppScreen Where to store the screen instance on success.
994 * @param cchWidth Width of the screen in characters.
995 * @param cchHeight Height of the screen in characters.
996 */
997static int dbgfR3CfgDumpScreenCreate(PDBGFCFGDUMPSCREEN *ppScreen, uint32_t cchWidth, uint32_t cchHeight)
998{
999 int rc = VINF_SUCCESS;
1000
1001 PDBGFCFGDUMPSCREEN pScreen = (PDBGFCFGDUMPSCREEN)RTMemAllocZ(sizeof(DBGFCFGDUMPSCREEN));
1002 if (pScreen)
1003 {
1004 pScreen->cchWidth = cchWidth;
1005 pScreen->cchHeight = cchHeight;
1006 pScreen->cchStride = 1; /* Zero terminators after every line. */
1007 pScreen->pszScreen = RTStrAlloc((cchWidth + 1) * cchHeight * sizeof(char));
1008 if (pScreen->pszScreen)
1009 {
1010 memset(pScreen->pszScreen, 0, (cchWidth + 1) * cchHeight * sizeof(char));
1011 /* Initialize the screen with spaces. */
1012 for (uint32_t i = 0; i < cchHeight; i++)
1013 dbgfR3CfgDumpScreenDrawLineHorizontal(pScreen, 0, cchWidth, i, ' ');
1014 *ppScreen = pScreen;
1015 }
1016 else
1017 rc = VERR_NO_STR_MEMORY;
1018
1019 if (RT_FAILURE(rc))
1020 RTMemFree(pScreen);
1021 }
1022 else
1023 rc = VERR_NO_MEMORY;
1024
1025 return rc;
1026}
1027
1028
1029/**
1030 * Destroys a given ASCII screen.
1031 *
1032 * @returns nothing.
1033 * @param pScreen The screen to destroy.
1034 */
1035static void dbgfR3CfgDumpScreenDestroy(PDBGFCFGDUMPSCREEN pScreen)
1036{
1037 RTStrFree(pScreen->pszScreen);
1038 RTMemFree(pScreen);
1039}
1040
1041
1042/**
1043 * Blits the entire screen using the dumper callback.
1044 *
1045 * @returns VBox status code.
1046 * @param pScreen The screen to blit.
1047 * @param pfnDump Dumper callback.
1048 * @param pvUser Opaque user data to pass to the dumper callback.
1049 */
1050static int dbgfR3CfgDumpScreenBlit(PDBGFCFGDUMPSCREEN pScreen, PFNDBGFR3CFGDUMP pfnDump, void *pvUser)
1051{
1052 int rc = VINF_SUCCESS;
1053
1054 for (uint32_t iY = 0; iY < pScreen->cchHeight && RT_SUCCESS(rc); iY++)
1055 {
1056 /* Play safe and restore line endings. */
1057 char *psz = dbgfR3CfgDumpScreenGetBufferAtPos(pScreen, 0, iY);
1058 psz[pScreen->cchWidth] = '\0';
1059 rc = pfnDump(psz, pvUser);
1060 }
1061
1062 return rc;
1063}
1064
1065
1066/**
1067 * Calculates the size required for the given basic block including the
1068 * border and spacing on the edges.
1069 *
1070 * @returns nothing.
1071 * @param pCfgBb The basic block.
1072 * @param pDumpBb The dumper state to fill in for the basic block.
1073 */
1074static void dbgfR3CfgDumpBbCalcSizes(PDBGFCFGBBINT pCfgBb, PDBGFCFGDUMPBB pDumpBb)
1075{
1076 pDumpBb->pCfgBb = pCfgBb;
1077 pDumpBb->cchHeight = pCfgBb->cInstr + 4; /* Include spacing and border top and bottom. */
1078 pDumpBb->cchWidth = 0;
1079 if ( RT_FAILURE(pCfgBb->rcError)
1080 && pCfgBb->pszErr)
1081 {
1082 pDumpBb->cchHeight++;
1083 pDumpBb->cchWidth = RT_MAX(pDumpBb->cchWidth, (uint32_t)strlen(pCfgBb->pszErr));
1084 }
1085 for (unsigned i = 0; i < pCfgBb->cInstr; i++)
1086 pDumpBb->cchWidth = RT_MAX(pDumpBb->cchWidth, (uint32_t)strlen(pCfgBb->aInstr[i].pszInstr));
1087 pDumpBb->cchWidth += 4; /* Include spacing and border left and right. */
1088}
1089
1090
1091/**
1092 * Dumps a top or bottom boundary line.
1093 *
1094 * @returns nothing.
1095 * @param pScreen The screen to draw to.
1096 * @param uStartX Where to start drawing the boundary.
1097 * @param uStartY Y coordinate.
1098 * @param cchWidth Width of the boundary.
1099 */
1100static void dbgfR3CfgDumpBbBoundary(PDBGFCFGDUMPSCREEN pScreen, uint32_t uStartX, uint32_t uStartY, uint32_t cchWidth)
1101{
1102 dbgfR3CfgDumpScreenDrawPixel(pScreen, uStartX, uStartY, '+');
1103 dbgfR3CfgDumpScreenDrawLineHorizontal(pScreen, uStartX + 1, uStartX + 1 + cchWidth - 2, uStartY, '-');
1104 dbgfR3CfgDumpScreenDrawPixel(pScreen, uStartX + cchWidth - 1, uStartY, '+');
1105}
1106
1107
1108/**
1109 * Dumps a spacing line between the top or bottom boundary and the actual disassembly.
1110 *
1111 * @returns nothing.
1112 * @param pScreen The screen to draw to.
1113 * @param uStartX Where to start drawing the spacing.
1114 * @param uStartY Y coordinate.
1115 * @param cchWidth Width of the spacing.
1116 */
1117static void dbgfR3CfgDumpBbSpacing(PDBGFCFGDUMPSCREEN pScreen, uint32_t uStartX, uint32_t uStartY, uint32_t cchWidth)
1118{
1119 dbgfR3CfgDumpScreenDrawPixel(pScreen, uStartX, uStartY, '|');
1120 dbgfR3CfgDumpScreenDrawLineHorizontal(pScreen, uStartX + 1, uStartX + 1 + cchWidth - 2, uStartY, ' ');
1121 dbgfR3CfgDumpScreenDrawPixel(pScreen, uStartX + cchWidth - 1, uStartY, '|');
1122}
1123
1124
1125/**
1126 * Writes a given text to the screen.
1127 *
1128 * @returns nothing.
1129 * @returns nothing.
1130 * @param pScreen The screen to draw to.
1131 * @param uStartX Where to start drawing the line.
1132 * @param uStartY Y coordinate.
1133 * @param cchWidth Maximum width of the text.
1134 * @param pszText The text to write.
1135 */
1136static void dbgfR3CfgDumpBbText(PDBGFCFGDUMPSCREEN pScreen, uint32_t uStartX, uint32_t uStartY,
1137 uint32_t cchWidth, const char *pszText)
1138{
1139 char *psz = dbgfR3CfgDumpScreenGetBufferAtPos(pScreen, uStartX, uStartY);
1140 AssertPtrReturnVoid(psz);
1141 size_t cch = 0;
1142 size_t cchText = strlen(pszText);
1143 psz[cch++] = '|';
1144 psz[cch++] = ' ';
1145 int rc = RTStrCopyEx(&psz[cch], cchWidth, pszText, cchText);
1146 AssertRC(rc);
1147
1148 /* Fill the rest with spaces. */
1149 cch += cchText;
1150 while (cch < cchWidth - 1)
1151 psz[cch++] = ' ';
1152 psz[cch] = '|';
1153}
1154
1155
1156/**
1157 * Dumps one basic block using the dumper callback.
1158 *
1159 * @returns nothing.
1160 * @param pDumpBb The basic block dump state to dump.
1161 * @param pScreen The screen to dump to.
1162 */
1163static void dbgfR3CfgDumpBb(PDBGFCFGDUMPBB pDumpBb, PDBGFCFGDUMPSCREEN pScreen)
1164{
1165 uint32_t uStartY = pDumpBb->uStartY;
1166
1167 dbgfR3CfgDumpBbBoundary(pScreen, pDumpBb->uStartX, uStartY, pDumpBb->cchWidth);
1168 uStartY++;
1169 dbgfR3CfgDumpBbSpacing(pScreen, pDumpBb->uStartX, uStartY, pDumpBb->cchWidth);
1170 uStartY++;
1171
1172 for (unsigned i = 0; i < pDumpBb->pCfgBb->cInstr; i++)
1173 dbgfR3CfgDumpBbText(pScreen, pDumpBb->uStartX, uStartY + i,
1174 pDumpBb->cchWidth, pDumpBb->pCfgBb->aInstr[i].pszInstr);
1175 uStartY += pDumpBb->pCfgBb->cInstr;
1176
1177 if (pDumpBb->pCfgBb->pszErr)
1178 {
1179 dbgfR3CfgDumpBbText(pScreen, pDumpBb->uStartX, uStartY, pDumpBb->cchWidth,
1180 pDumpBb->pCfgBb->pszErr);
1181 uStartY++;
1182 }
1183
1184 dbgfR3CfgDumpBbSpacing(pScreen, pDumpBb->uStartX, uStartY, pDumpBb->cchWidth);
1185 uStartY++;
1186 dbgfR3CfgDumpBbBoundary(pScreen, pDumpBb->uStartX, uStartY, pDumpBb->cchWidth);
1187 uStartY++;
1188}
1189
1190
1191/**
1192 * @callback_method_impl{FNRTSORTCMP}
1193 */
1194static DECLCALLBACK(int) dbgfR3CfgDumpSortCmp(void const *pvElement1, void const *pvElement2, void *pvUser)
1195{
1196 RT_NOREF(pvUser);
1197 PDBGFCFGDUMPBB pCfgDumpBb1 = (PDBGFCFGDUMPBB)pvElement1;
1198 PDBGFCFGDUMPBB pCfgDumpBb2 = (PDBGFCFGDUMPBB)pvElement2;
1199
1200 if (dbgfR3CfgBbAddrEqual(&pCfgDumpBb1->pCfgBb->AddrStart, &pCfgDumpBb2->pCfgBb->AddrStart))
1201 return 0;
1202 else if (dbgfR3CfgBbAddrLower(&pCfgDumpBb1->pCfgBb->AddrStart, &pCfgDumpBb2->pCfgBb->AddrStart))
1203 return -1;
1204
1205 return 1;
1206}
1207
1208
1209/**
1210 * Dumps a given control flow graph as ASCII using the given dumper callback.
1211 *
1212 * @returns VBox status code.
1213 * @param hCfg The control flow graph handle.
1214 * @param pfnDump The dumper callback.
1215 * @param pvUser Opaque user data to pass to the dumper callback.
1216 */
1217VMMR3DECL(int) DBGFR3CfgDump(DBGFCFG hCfg, PFNDBGFR3CFGDUMP pfnDump, void *pvUser)
1218{
1219 int rc = VINF_SUCCESS;
1220 PDBGFCFGINT pThis = hCfg;
1221 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1222 AssertPtrReturn(pfnDump, VERR_INVALID_POINTER);
1223
1224 PDBGFCFGDUMPBB paDumpBb = (PDBGFCFGDUMPBB)RTMemTmpAllocZ(pThis->cBbs * sizeof(DBGFCFGDUMPBB));
1225 if (paDumpBb)
1226 {
1227 /* Calculate the sizes of each basic block first. */
1228 PDBGFCFGBBINT pCfgBb = NULL;
1229 uint32_t idxDumpBb = 0;
1230 RTListForEach(&pThis->LstCfgBb, pCfgBb, DBGFCFGBBINT, NdCfgBb)
1231 {
1232 dbgfR3CfgDumpBbCalcSizes(pCfgBb, &paDumpBb[idxDumpBb]);
1233 idxDumpBb++;
1234 }
1235
1236 /* Sort the blocks by address. */
1237 RTSortShell(paDumpBb, pThis->cBbs, sizeof(DBGFCFGDUMPBB), dbgfR3CfgDumpSortCmp, NULL);
1238
1239 /* Calculate the ASCII screen dimensions and create one. */
1240 uint32_t cchWidth = 0;
1241 uint32_t cchLeftExtra = 5;
1242 uint32_t cchRightExtra = 5;
1243 uint32_t cchHeight = 0;
1244 for (unsigned i = 0; i < pThis->cBbs; i++)
1245 {
1246 PDBGFCFGDUMPBB pDumpBb = &paDumpBb[i];
1247 cchWidth = RT_MAX(cchWidth, pDumpBb->cchWidth);
1248 cchHeight += pDumpBb->cchHeight;
1249
1250 /* Incomplete blocks don't have a successor. */
1251 if (pDumpBb->pCfgBb->fFlags & DBGF_CFG_BB_F_INCOMPLETE_ERR)
1252 continue;
1253
1254 switch (pDumpBb->pCfgBb->enmEndType)
1255 {
1256 case DBGFCFGBBENDTYPE_EXIT:
1257 case DBGFCFGBBENDTYPE_LAST_DISASSEMBLED:
1258 break;
1259 case DBGFCFGBBENDTYPE_UNCOND_JMP:
1260 if ( dbgfR3CfgBbAddrLower(&pDumpBb->pCfgBb->AddrTarget, &pDumpBb->pCfgBb->AddrStart)
1261 || dbgfR3CfgBbAddrEqual(&pDumpBb->pCfgBb->AddrTarget, &pDumpBb->pCfgBb->AddrStart))
1262 cchLeftExtra++;
1263 else
1264 cchRightExtra++;
1265 break;
1266 case DBGFCFGBBENDTYPE_UNCOND:
1267 cchHeight += 2; /* For the arrow down to the next basic block. */
1268 break;
1269 case DBGFCFGBBENDTYPE_COND:
1270 cchHeight += 2; /* For the arrow down to the next basic block. */
1271 if ( dbgfR3CfgBbAddrLower(&pDumpBb->pCfgBb->AddrTarget, &pDumpBb->pCfgBb->AddrStart)
1272 || dbgfR3CfgBbAddrEqual(&pDumpBb->pCfgBb->AddrTarget, &pDumpBb->pCfgBb->AddrStart))
1273 cchLeftExtra++;
1274 else
1275 cchRightExtra++;
1276 break;
1277 default:
1278 AssertFailed();
1279 }
1280 }
1281
1282 cchWidth += 2;
1283
1284 PDBGFCFGDUMPSCREEN pScreen = NULL;
1285 rc = dbgfR3CfgDumpScreenCreate(&pScreen, cchWidth + cchLeftExtra + cchRightExtra, cchHeight);
1286 if (RT_SUCCESS(rc))
1287 {
1288 uint32_t uY = 0;
1289
1290 /* Dump the basic blocks and connections to the immediate successor. */
1291 for (unsigned i = 0; i < pThis->cBbs; i++)
1292 {
1293 paDumpBb[i].uStartX = cchLeftExtra + (cchWidth - paDumpBb[i].cchWidth) / 2;
1294 paDumpBb[i].uStartY = uY;
1295 dbgfR3CfgDumpBb(&paDumpBb[i], pScreen);
1296 uY += paDumpBb[i].cchHeight;
1297
1298 /* Incomplete blocks don't have a successor. */
1299 if (paDumpBb[i].pCfgBb->fFlags & DBGF_CFG_BB_F_INCOMPLETE_ERR)
1300 continue;
1301
1302 switch (paDumpBb[i].pCfgBb->enmEndType)
1303 {
1304 case DBGFCFGBBENDTYPE_EXIT:
1305 case DBGFCFGBBENDTYPE_LAST_DISASSEMBLED:
1306 case DBGFCFGBBENDTYPE_UNCOND_JMP:
1307 break;
1308 case DBGFCFGBBENDTYPE_UNCOND:
1309 case DBGFCFGBBENDTYPE_COND:
1310 /* Draw the arrow down to the next block. */
1311 dbgfR3CfgDumpScreenDrawPixel(pScreen, cchLeftExtra + cchWidth / 2, uY, '|');
1312 uY++;
1313 dbgfR3CfgDumpScreenDrawPixel(pScreen, cchLeftExtra + cchWidth / 2, uY, 'V');
1314 uY++;
1315 break;
1316 default:
1317 AssertFailed();
1318 }
1319 }
1320
1321 /* Last pass, connect all remaining branches. */
1322 uint32_t uBackConns = 0;
1323 uint32_t uFwdConns = 0;
1324 for (unsigned i = 0; i < pThis->cBbs; i++)
1325 {
1326 PDBGFCFGDUMPBB pDumpBb = &paDumpBb[i];
1327
1328 /* Incomplete blocks don't have a successor. */
1329 if (pDumpBb->pCfgBb->fFlags & DBGF_CFG_BB_F_INCOMPLETE_ERR)
1330 continue;
1331
1332 switch (pDumpBb->pCfgBb->enmEndType)
1333 {
1334 case DBGFCFGBBENDTYPE_EXIT:
1335 case DBGFCFGBBENDTYPE_LAST_DISASSEMBLED:
1336 case DBGFCFGBBENDTYPE_UNCOND:
1337 break;
1338 case DBGFCFGBBENDTYPE_COND:
1339 case DBGFCFGBBENDTYPE_UNCOND_JMP:
1340 {
1341 /* Find the target first to get the coordinates. */
1342 PDBGFCFGDUMPBB pDumpBbTgt = NULL;
1343 for (idxDumpBb = 0; idxDumpBb < pThis->cBbs; idxDumpBb++)
1344 {
1345 pDumpBbTgt = &paDumpBb[idxDumpBb];
1346 if (dbgfR3CfgBbAddrEqual(&pDumpBb->pCfgBb->AddrTarget, &pDumpBbTgt->pCfgBb->AddrStart))
1347 break;
1348 }
1349
1350 /*
1351 * Use the right side for targets with higher addresses,
1352 * left when jumping backwards.
1353 */
1354 if ( dbgfR3CfgBbAddrLower(&pDumpBb->pCfgBb->AddrTarget, &pDumpBb->pCfgBb->AddrStart)
1355 || dbgfR3CfgBbAddrEqual(&pDumpBb->pCfgBb->AddrTarget, &pDumpBb->pCfgBb->AddrStart))
1356 {
1357 /* Going backwards. */
1358 uint32_t uXVerLine = /*cchLeftExtra - 1 -*/ uBackConns + 1;
1359 uint32_t uYHorLine = pDumpBb->uStartY + pDumpBb->cchHeight - 1 - 2;
1360 uBackConns++;
1361
1362 /* Draw the arrow pointing to the target block. */
1363 dbgfR3CfgDumpScreenDrawPixel(pScreen, pDumpBbTgt->uStartX - 1, pDumpBbTgt->uStartY, '>');
1364 /* Draw the horizontal line. */
1365 dbgfR3CfgDumpScreenDrawLineHorizontal(pScreen, uXVerLine + 1, pDumpBbTgt->uStartX - 2,
1366 pDumpBbTgt->uStartY, '-');
1367 dbgfR3CfgDumpScreenDrawPixel(pScreen, uXVerLine, pDumpBbTgt->uStartY, '+');
1368 /* Draw the vertical line down to the source block. */
1369 dbgfR3CfgDumpScreenDrawLineVertical(pScreen, uXVerLine, pDumpBbTgt->uStartY + 1, uYHorLine - 1, '|');
1370 dbgfR3CfgDumpScreenDrawPixel(pScreen, uXVerLine, uYHorLine, '+');
1371 /* Draw the horizontal connection between the source block and vertical part. */
1372 dbgfR3CfgDumpScreenDrawLineHorizontal(pScreen, uXVerLine + 1, pDumpBb->uStartX - 1,
1373 uYHorLine, '-');
1374
1375 }
1376 else
1377 {
1378 /* Going forward. */
1379 uint32_t uXVerLine = cchWidth + cchLeftExtra + (cchRightExtra - uFwdConns) - 1;
1380 uint32_t uYHorLine = pDumpBb->uStartY + pDumpBb->cchHeight - 1 - 2;
1381 uFwdConns++;
1382
1383 /* Draw the horizontal line. */
1384 dbgfR3CfgDumpScreenDrawLineHorizontal(pScreen, pDumpBb->uStartX + pDumpBb->cchWidth,
1385 uXVerLine - 1, uYHorLine, '-');
1386 dbgfR3CfgDumpScreenDrawPixel(pScreen, uXVerLine, uYHorLine, '+');
1387 /* Draw the vertical line down to the target block. */
1388 dbgfR3CfgDumpScreenDrawLineVertical(pScreen, uXVerLine, uYHorLine + 1, pDumpBbTgt->uStartY - 1, '|');
1389 /* Draw the horizontal connection between the target block and vertical part. */
1390 dbgfR3CfgDumpScreenDrawLineHorizontal(pScreen, pDumpBbTgt->uStartX + pDumpBbTgt->cchWidth,
1391 uXVerLine, pDumpBbTgt->uStartY, '-');
1392 dbgfR3CfgDumpScreenDrawPixel(pScreen, uXVerLine, pDumpBbTgt->uStartY, '+');
1393 /* Draw the arrow pointing to the target block. */
1394 dbgfR3CfgDumpScreenDrawPixel(pScreen, pDumpBbTgt->uStartX + pDumpBbTgt->cchWidth,
1395 pDumpBbTgt->uStartY, '<');
1396 }
1397 break;
1398 }
1399 default:
1400 AssertFailed();
1401 }
1402 }
1403
1404 rc = dbgfR3CfgDumpScreenBlit(pScreen, pfnDump, pvUser);
1405 dbgfR3CfgDumpScreenDestroy(pScreen);
1406 }
1407
1408 RTMemTmpFree(paDumpBb);
1409 }
1410 else
1411 rc = VERR_NO_MEMORY;
1412 return rc;
1413}
1414
1415
1416/**
1417 * Retains the basic block handle.
1418 *
1419 * @returns Current reference count.
1420 * @param hCfgBb The basic block handle to retain.
1421 */
1422VMMR3DECL(uint32_t) DBGFR3CfgBbRetain(DBGFCFGBB hCfgBb)
1423{
1424 PDBGFCFGBBINT pCfgBb = hCfgBb;
1425 AssertPtrReturn(pCfgBb, UINT32_MAX);
1426
1427 uint32_t cRefs = ASMAtomicIncU32(&pCfgBb->cRefs);
1428 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p %d\n", cRefs, pCfgBb, pCfgBb->enmEndType));
1429 return cRefs;
1430}
1431
1432
1433/**
1434 * Releases the basic block handle.
1435 *
1436 * @returns Current reference count, on 0 the basic block will be destroyed.
1437 * @param hCfgBb The basic block handle to release.
1438 */
1439VMMR3DECL(uint32_t) DBGFR3CfgBbRelease(DBGFCFGBB hCfgBb)
1440{
1441 PDBGFCFGBBINT pCfgBb = hCfgBb;
1442 if (!pCfgBb)
1443 return 0;
1444
1445 return dbgfR3CfgBbReleaseInt(pCfgBb, true /* fMayDestroyCfg */);
1446}
1447
1448
1449/**
1450 * Returns the start address of the basic block.
1451 *
1452 * @returns Pointer to DBGF adress containing the start address of the basic block.
1453 * @param hCfgBb The basic block handle.
1454 * @param pAddrStart Where to store the start address of the basic block.
1455 */
1456VMMR3DECL(PDBGFADDRESS) DBGFR3CfgBbGetStartAddress(DBGFCFGBB hCfgBb, PDBGFADDRESS pAddrStart)
1457{
1458 PDBGFCFGBBINT pCfgBb = hCfgBb;
1459 AssertPtrReturn(pCfgBb, NULL);
1460 AssertPtrReturn(pAddrStart, NULL);
1461
1462 *pAddrStart = pCfgBb->AddrStart;
1463 return pAddrStart;
1464}
1465
1466
1467/**
1468 * Returns the end address of the basic block (inclusive).
1469 *
1470 * @returns Pointer to DBGF adress containing the end address of the basic block.
1471 * @param hCfgBb The basic block handle.
1472 * @param pAddrEnd Where to store the end address of the basic block.
1473 */
1474VMMR3DECL(PDBGFADDRESS) DBGFR3CfgBbGetEndAddress(DBGFCFGBB hCfgBb, PDBGFADDRESS pAddrEnd)
1475{
1476 PDBGFCFGBBINT pCfgBb = hCfgBb;
1477 AssertPtrReturn(pCfgBb, NULL);
1478 AssertPtrReturn(pAddrEnd, NULL);
1479
1480 *pAddrEnd = pCfgBb->AddrEnd;
1481 return pAddrEnd;
1482}
1483
1484
1485/**
1486 * Returns the address the last instruction in the basic block branches to.
1487 *
1488 * @returns Pointer to DBGF adress containing the branch address of the basic block.
1489 * @param hCfgBb The basic block handle.
1490 * @param pAddrTarget Where to store the branch address of the basic block.
1491 *
1492 * @note This is only valid for unconditional or conditional branches and will assert
1493 * for every other basic block type.
1494 */
1495VMMR3DECL(PDBGFADDRESS) DBGFR3CfgBbGetBranchAddress(DBGFCFGBB hCfgBb, PDBGFADDRESS pAddrTarget)
1496{
1497 PDBGFCFGBBINT pCfgBb = hCfgBb;
1498 AssertPtrReturn(pCfgBb, NULL);
1499 AssertPtrReturn(pAddrTarget, NULL);
1500 AssertReturn( pCfgBb->enmEndType == DBGFCFGBBENDTYPE_UNCOND_JMP
1501 || pCfgBb->enmEndType == DBGFCFGBBENDTYPE_COND,
1502 NULL);
1503
1504 *pAddrTarget = pCfgBb->AddrTarget;
1505 return pAddrTarget;
1506}
1507
1508
1509/**
1510 * Returns the address of the next block following this one in the instruction stream.
1511 * (usually end address + 1).
1512 *
1513 * @returns Pointer to DBGF adress containing the following address of the basic block.
1514 * @param hCfgBb The basic block handle.
1515 * @param pAddrFollow Where to store the following address of the basic block.
1516 *
1517 * @note This is only valid for conditional branches and if the last instruction in the
1518 * given basic block doesn't change the control flow but the blocks were split
1519 * because the successor is referenced by multiple other blocks as an entry point.
1520 */
1521VMMR3DECL(PDBGFADDRESS) DBGFR3CfgBbGetFollowingAddress(DBGFCFGBB hCfgBb, PDBGFADDRESS pAddrFollow)
1522{
1523 PDBGFCFGBBINT pCfgBb = hCfgBb;
1524 AssertPtrReturn(pCfgBb, NULL);
1525 AssertPtrReturn(pAddrFollow, NULL);
1526 AssertReturn( pCfgBb->enmEndType == DBGFCFGBBENDTYPE_UNCOND
1527 || pCfgBb->enmEndType == DBGFCFGBBENDTYPE_COND,
1528 NULL);
1529
1530 *pAddrFollow = pCfgBb->AddrEnd;
1531 DBGFR3AddrAdd(pAddrFollow, 1);
1532 return pAddrFollow;
1533}
1534
1535
1536/**
1537 * Returns the type of the last instruction in the basic block.
1538 *
1539 * @returns Last instruction type.
1540 * @param hCfgBb The basic block handle.
1541 */
1542VMMR3DECL(DBGFCFGBBENDTYPE) DBGFR3CfgBbGetType(DBGFCFGBB hCfgBb)
1543{
1544 PDBGFCFGBBINT pCfgBb = hCfgBb;
1545 AssertPtrReturn(pCfgBb, DBGFCFGBBENDTYPE_INVALID);
1546
1547 return pCfgBb->enmEndType;
1548}
1549
1550
1551/**
1552 * Get the number of instructions contained in the basic block.
1553 *
1554 * @returns Number of instructions in the basic block.
1555 * @param hCfgBb The basic block handle.
1556 */
1557VMMR3DECL(uint32_t) DBGFR3CfgBbGetInstrCount(DBGFCFGBB hCfgBb)
1558{
1559 PDBGFCFGBBINT pCfgBb = hCfgBb;
1560 AssertPtrReturn(pCfgBb, 0);
1561
1562 return pCfgBb->cInstr;
1563}
1564
1565
1566/**
1567 * Get flags for the given basic block.
1568 *
1569 * @returns Combination of DBGF_CFG_BB_F_*
1570 * @param hCfgBb The basic block handle.
1571 */
1572VMMR3DECL(uint32_t) DBGFR3CfgBbGetFlags(DBGFCFGBB hCfgBb)
1573{
1574 PDBGFCFGBBINT pCfgBb = hCfgBb;
1575 AssertPtrReturn(pCfgBb, 0);
1576
1577 return pCfgBb->fFlags;
1578}
1579
1580
1581/**
1582 * Returns the error status and message if the given basic block has an error.
1583 *
1584 * @returns VBox status code of the error for the basic block.
1585 * @param hCfgBb The basic block handle.
1586 * @param ppszErr Where to store the pointer to the error message - optional.
1587 */
1588VMMR3DECL(int) DBGFR3CfgBbQueryError(DBGFCFGBB hCfgBb, const char **ppszErr)
1589{
1590 PDBGFCFGBBINT pCfgBb = hCfgBb;
1591 AssertPtrReturn(pCfgBb, VERR_INVALID_HANDLE);
1592
1593 if (ppszErr)
1594 *ppszErr = pCfgBb->pszErr;
1595
1596 return pCfgBb->rcError;
1597}
1598
1599
1600/**
1601 * Store the disassembled instruction as a string in the given output buffer.
1602 *
1603 * @returns VBox status code.
1604 * @param hCfgBb The basic block handle.
1605 * @param idxInstr The instruction to query.
1606 * @param pAddrInstr Where to store the guest instruction address on success, optional.
1607 * @param pcbInstr Where to store the instruction size on success, optional.
1608 * @param ppszInstr Where to store the pointer to the disassembled instruction string, optional.
1609 */
1610VMMR3DECL(int) DBGFR3CfgBbQueryInstr(DBGFCFGBB hCfgBb, uint32_t idxInstr, PDBGFADDRESS pAddrInstr,
1611 uint32_t *pcbInstr, const char **ppszInstr)
1612{
1613 PDBGFCFGBBINT pCfgBb = hCfgBb;
1614 AssertPtrReturn(pCfgBb, VERR_INVALID_POINTER);
1615 AssertReturn(idxInstr < pCfgBb->cInstr, VERR_INVALID_PARAMETER);
1616
1617 if (pAddrInstr)
1618 *pAddrInstr = pCfgBb->aInstr[idxInstr].AddrInstr;
1619 if (pcbInstr)
1620 *pcbInstr = pCfgBb->aInstr[idxInstr].cbInstr;
1621 if (ppszInstr)
1622 *ppszInstr = pCfgBb->aInstr[idxInstr].pszInstr;
1623
1624 return VINF_SUCCESS;
1625}
1626
1627
1628/**
1629 * Queries the successors of the basic block.
1630 *
1631 * @returns VBox status code.
1632 * @param hCfgBb The basic block handle.
1633 * @param phCfgBbFollow Where to store the handle to the basic block following
1634 * this one (optional).
1635 * @param phCfgBbTarget Where to store the handle to the basic block being the
1636 * branch target for this one (optional).
1637 */
1638VMMR3DECL(int) DBGFR3CfgBbQuerySuccessors(DBGFCFGBB hCfgBb, PDBGFCFGBB phCfgBbFollow, PDBGFCFGBB phCfgBbTarget)
1639{
1640 PDBGFCFGBBINT pCfgBb = hCfgBb;
1641 AssertPtrReturn(pCfgBb, VERR_INVALID_POINTER);
1642
1643 if ( phCfgBbFollow
1644 && ( pCfgBb->enmEndType == DBGFCFGBBENDTYPE_UNCOND
1645 || pCfgBb->enmEndType == DBGFCFGBBENDTYPE_COND))
1646 {
1647 DBGFADDRESS AddrStart = pCfgBb->AddrEnd;
1648 DBGFR3AddrAdd(&AddrStart, 1);
1649 int rc = DBGFR3CfgQueryBbByAddress(pCfgBb->pCfg, &AddrStart, phCfgBbFollow);
1650 AssertRC(rc);
1651 }
1652
1653 if ( phCfgBbTarget
1654 && ( pCfgBb->enmEndType == DBGFCFGBBENDTYPE_UNCOND_JMP
1655 || pCfgBb->enmEndType == DBGFCFGBBENDTYPE_COND))
1656 {
1657 int rc = DBGFR3CfgQueryBbByAddress(pCfgBb->pCfg, &pCfgBb->AddrTarget, phCfgBbTarget);
1658 AssertRC(rc);
1659 }
1660
1661 return VINF_SUCCESS;
1662}
1663
1664
1665/**
1666 * Returns the number of basic blocks referencing this basic block as a target.
1667 *
1668 * @returns Number of other basic blocks referencing this one.
1669 * @param hCfgBb The basic block handle.
1670 *
1671 * @note If the given basic block references itself (loop, etc.) this will be counted as well.
1672 */
1673VMMR3DECL(uint32_t) DBGFR3CfgBbGetRefBbCount(DBGFCFGBB hCfgBb)
1674{
1675 PDBGFCFGBBINT pCfgBb = hCfgBb;
1676 AssertPtrReturn(pCfgBb, 0);
1677
1678 uint32_t cRefsBb = 0;
1679 PDBGFCFGBBINT pCfgBbCur = NULL;
1680 RTListForEach(&pCfgBb->pCfg->LstCfgBb, pCfgBbCur, DBGFCFGBBINT, NdCfgBb)
1681 {
1682 if (pCfgBbCur->fFlags & DBGF_CFG_BB_F_INCOMPLETE_ERR)
1683 continue;
1684
1685 if ( pCfgBbCur->enmEndType == DBGFCFGBBENDTYPE_UNCOND
1686 || pCfgBbCur->enmEndType == DBGFCFGBBENDTYPE_COND)
1687 {
1688 DBGFADDRESS AddrStart = pCfgBb->AddrEnd;
1689 DBGFR3AddrAdd(&AddrStart, 1);
1690 if (dbgfR3CfgBbAddrEqual(&pCfgBbCur->AddrStart, &AddrStart))
1691 cRefsBb++;
1692 }
1693
1694 if ( ( pCfgBbCur->enmEndType == DBGFCFGBBENDTYPE_UNCOND_JMP
1695 || pCfgBbCur->enmEndType == DBGFCFGBBENDTYPE_COND)
1696 && dbgfR3CfgBbAddrEqual(&pCfgBbCur->AddrStart, &pCfgBb->AddrTarget))
1697 cRefsBb++;
1698 }
1699 return cRefsBb;
1700}
1701
1702
1703/**
1704 * Returns the basic block handles referencing the given basic block.
1705 *
1706 * @returns VBox status code.
1707 * @retval VERR_BUFFER_OVERFLOW if the array can't hold all the basic blocks.
1708 * @param hCfgBb The basic block handle.
1709 * @param paCfgBbRef Pointer to the array containing the referencing basic block handles on success.
1710 * @param cRef Number of entries in the given array.
1711 */
1712VMMR3DECL(int) DBGFR3CfgBbGetRefBb(DBGFCFGBB hCfgBb, PDBGFCFGBB paCfgBbRef, uint32_t cRef)
1713{
1714 RT_NOREF3(hCfgBb, paCfgBbRef, cRef);
1715 return VERR_NOT_IMPLEMENTED;
1716}
1717
1718
1719/**
1720 * @callback_method_impl{FNRTSORTCMP}
1721 */
1722static DECLCALLBACK(int) dbgfR3CfgItSortCmp(void const *pvElement1, void const *pvElement2, void *pvUser)
1723{
1724 PDBGFCFGITORDER penmOrder = (PDBGFCFGITORDER)pvUser;
1725 PDBGFCFGBBINT pCfgBb1 = *(PDBGFCFGBBINT *)pvElement1;
1726 PDBGFCFGBBINT pCfgBb2 = *(PDBGFCFGBBINT *)pvElement2;
1727
1728 if (dbgfR3CfgBbAddrEqual(&pCfgBb1->AddrStart, &pCfgBb2->AddrStart))
1729 return 0;
1730
1731 if (*penmOrder == DBGFCFGITORDER_BY_ADDR_LOWEST_FIRST)
1732 {
1733 if (dbgfR3CfgBbAddrLower(&pCfgBb1->AddrStart, &pCfgBb2->AddrStart))
1734 return -1;
1735 else
1736 return 1;
1737 }
1738 else
1739 {
1740 if (dbgfR3CfgBbAddrLower(&pCfgBb1->AddrStart, &pCfgBb2->AddrStart))
1741 return 1;
1742 else
1743 return -1;
1744 }
1745
1746 AssertFailed();
1747}
1748
1749
1750/**
1751 * Creates a new iterator for the given control flow graph.
1752 *
1753 * @returns VBox status code.
1754 * @param hCfg The control flow graph handle.
1755 * @param enmOrder The order in which the basic blocks are enumerated.
1756 * @param phCfgIt Where to store the handle to the iterator on success.
1757 */
1758VMMR3DECL(int) DBGFR3CfgItCreate(DBGFCFG hCfg, DBGFCFGITORDER enmOrder, PDBGFCFGIT phCfgIt)
1759{
1760 int rc = VINF_SUCCESS;
1761 PDBGFCFGINT pCfg = hCfg;
1762 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
1763 AssertPtrReturn(phCfgIt, VERR_INVALID_POINTER);
1764 AssertReturn(enmOrder > DBGFCFGITORDER_INVALID && enmOrder < DBGFCFGITORDER_BREADTH_FIRST,
1765 VERR_INVALID_PARAMETER);
1766 AssertReturn(enmOrder < DBGFCFGITORDER_DEPTH_FRIST, VERR_NOT_IMPLEMENTED); /** @todo */
1767
1768 PDBGFCFGITINT pIt = (PDBGFCFGITINT)RTMemAllocZ(RT_OFFSETOF(DBGFCFGITINT, apBb[pCfg->cBbs]));
1769 if (RT_LIKELY(pIt))
1770 {
1771 DBGFR3CfgRetain(hCfg);
1772 pIt->pCfg = pCfg;
1773 pIt->idxBbNext = 0;
1774 /* Fill the list and then sort. */
1775 PDBGFCFGBBINT pCfgBb;
1776 uint32_t idxBb = 0;
1777 RTListForEach(&pCfg->LstCfgBb, pCfgBb, DBGFCFGBBINT, NdCfgBb)
1778 {
1779 DBGFR3CfgBbRetain(pCfgBb);
1780 pIt->apBb[idxBb++] = pCfgBb;
1781 }
1782
1783 /* Sort the blocks by address. */
1784 RTSortShell(&pIt->apBb[0], pCfg->cBbs, sizeof(PDBGFCFGBBINT), dbgfR3CfgItSortCmp, &enmOrder);
1785
1786 *phCfgIt = pIt;
1787 }
1788 else
1789 rc = VERR_NO_MEMORY;
1790
1791 return rc;
1792}
1793
1794
1795/**
1796 * Destroys a given control flow graph iterator.
1797 *
1798 * @returns nothing.
1799 * @param hCfgIt The control flow graph iterator handle.
1800 */
1801VMMR3DECL(void) DBGFR3CfgItDestroy(DBGFCFGIT hCfgIt)
1802{
1803 PDBGFCFGITINT pIt = hCfgIt;
1804 AssertPtrReturnVoid(pIt);
1805
1806 for (unsigned i = 0; i < pIt->pCfg->cBbs; i++)
1807 DBGFR3CfgBbRelease(pIt->apBb[i]);
1808
1809 DBGFR3CfgRelease(pIt->pCfg);
1810 RTMemFree(pIt);
1811}
1812
1813
1814/**
1815 * Returns the next basic block in the iterator or NULL if there is no
1816 * basic block left.
1817 *
1818 * @returns Handle to the next basic block in the iterator or NULL if the end
1819 * was reached.
1820 * @param hCfgIt The iterator handle.
1821 *
1822 * @note If a valid handle is returned it must be release with DBGFR3CfgBbRelease()
1823 * when not required anymore.
1824 */
1825VMMR3DECL(DBGFCFGBB) DBGFR3CfgItNext(DBGFCFGIT hCfgIt)
1826{
1827 PDBGFCFGITINT pIt = hCfgIt;
1828 AssertPtrReturn(pIt, NULL);
1829
1830 PDBGFCFGBBINT pCfgBb = NULL;
1831 if (pIt->idxBbNext < pIt->pCfg->cBbs)
1832 {
1833 pCfgBb = pIt->apBb[pIt->idxBbNext++];
1834 DBGFR3CfgBbRetain(pCfgBb);
1835 }
1836
1837 return pCfgBb;
1838}
1839
1840
1841/**
1842 * Resets the given iterator to the beginning.
1843 *
1844 * @returns VBox status code.
1845 * @param hCfgIt The iterator handle.
1846 */
1847VMMR3DECL(int) DBGFR3CfgItReset(DBGFCFGIT hCfgIt)
1848{
1849 PDBGFCFGITINT pIt = hCfgIt;
1850 AssertPtrReturn(pIt, VERR_INVALID_HANDLE);
1851
1852 pIt->idxBbNext = 0;
1853 return VINF_SUCCESS;
1854}
Note: See TracBrowser for help on using the repository browser.

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