VirtualBox

Changeset 64586 in vbox for trunk


Ignore:
Timestamp:
Nov 6, 2016 1:56:36 PM (8 years ago)
Author:
vboxsync
Message:

DBGFR3Flow: Started working on resolving indirect branches. Compilers tend to create a branch table for large switch() {} statements to avoid loads of conditional branches

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/vmm/dbgf.h

    r64559 r64586  
    25002500/** Pointer to a DBGF control flow graph basic block handle. */
    25012501typedef DBGFFLOWBB *PDBGFFLOWBB;
     2502/** A DBGF control flow graph branch table handle. */
     2503typedef struct DBGFFLOWBRANCHTBLINT *DBGFFLOWBRANCHTBL;
     2504/** Pointer to a DBGF flow control graph branch table handle. */
     2505typedef DBGFFLOWBRANCHTBL *PDBGFFLOWBRANCHTBL;
    25022506/** A DBGF control flow graph iterator. */
    25032507typedef struct DBGFFLOWITINT *DBGFFLOWIT;
     
    25132517/** The basic block is not complete because an error happened during disassembly. */
    25142518#define DBGF_FLOW_BB_F_INCOMPLETE_ERR    RT_BIT_32(2)
     2519/** The basic block is reached through a branch table. */
     2520#define DBGF_FLOW_BB_F_BRANCH_TABLE      RT_BIT_32(3)
     2521/** @} */
     2522
     2523/** @name Flags controlling the creating of a control flow graph.
     2524 * @{ */
     2525/** Default options. */
     2526#define DBGF_FLOW_CREATE_F_DEFAULT                       0
     2527/** Tries to resolve indirect branches, useful for code using
     2528 * jump tables generated for large switch statements by some compilers. */
     2529#define DBGF_FLOW_CREATE_F_TRY_RESOLVE_INDIRECT_BRANCHES RT_BIT_32(0)
    25152530/** @} */
    25162531
     
    25322547     * basic blocks. - 1 successor. */
    25332548    DBGFFLOWBBENDTYPE_UNCOND,
    2534     /** Unconditional control flow change because of a jump instruction - 1 successor. */
     2549    /** Unconditional control flow change because of an direct branch - 1 successor. */
    25352550    DBGFFLOWBBENDTYPE_UNCOND_JMP,
     2551    /** Unconditional control flow change because of an indirect branch - n successors. */
     2552    DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP,
    25362553    /** Conditional control flow change - 2 successors. */
    25372554    DBGFFLOWBBENDTYPE_COND,
     
    25582575    DBGFFLOWITORDER_32BIT_HACK = 0x7fffffff
    25592576} DBGFFLOWITORDER;
    2560 /** POinter to a iteration order enum. */
     2577/** Pointer to a iteration order enum. */
    25612578typedef DBGFFLOWITORDER *PDBGFFLOWITORDER;
    25622579
    25632580
    25642581VMMR3DECL(int)               DBGFR3FlowCreate(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddressStart, uint32_t cbDisasmMax,
    2565                                              uint32_t fFlags, PDBGFFLOW phFlow);
     2582                                              uint32_t fFlagsFlow, uint32_t fFlagsDisasm, PDBGFFLOW phFlow);
    25662583VMMR3DECL(uint32_t)          DBGFR3FlowRetain(DBGFFLOW hFlow);
    25672584VMMR3DECL(uint32_t)          DBGFR3FlowRelease(DBGFFLOW hFlow);
    25682585VMMR3DECL(int)               DBGFR3FlowQueryStartBb(DBGFFLOW hFlow, PDBGFFLOWBB phFlowBb);
    25692586VMMR3DECL(int)               DBGFR3FlowQueryBbByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBB phFlowBb);
     2587VMMR3DECL(int)               DBGFR3FlowQueryBranchTblByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBRANCHTBL phFlowBranchTbl);
    25702588VMMR3DECL(uint32_t)          DBGFR3FlowGetBbCount(DBGFFLOW hFlow);
     2589VMMR3DECL(uint32_t)          DBGFR3FlowGetBranchTblCount(DBGFFLOW hFlow);
     2590
    25712591VMMR3DECL(uint32_t)          DBGFR3FlowBbRetain(DBGFFLOWBB hFlowBb);
    25722592VMMR3DECL(uint32_t)          DBGFR3FlowBbRelease(DBGFFLOWBB hFlowBb);
     
    25782598VMMR3DECL(uint32_t)          DBGFR3FlowBbGetInstrCount(DBGFFLOWBB hFlowBb);
    25792599VMMR3DECL(uint32_t)          DBGFR3FlowBbGetFlags(DBGFFLOWBB hFlowBb);
     2600VMMR3DECL(int)               DBGFR3FlowBbQueryBranchTbl(DBGFFLOWBB hFlowBb, PDBGFFLOWBRANCHTBL phBranchTbl);
    25802601VMMR3DECL(int)               DBGFR3FlowBbQueryError(DBGFFLOWBB hFlowBb, const char **ppszErr);
    25812602VMMR3DECL(int)               DBGFR3FlowBbQueryInstr(DBGFFLOWBB hFlowBb, uint32_t idxInstr, PDBGFADDRESS pAddrInstr,
     
    25832604VMMR3DECL(int)               DBGFR3FlowBbQuerySuccessors(DBGFFLOWBB hFlowBb, PDBGFFLOWBB phFlowBbFollow,
    25842605                                                         PDBGFFLOWBB phFlowBbTarget);
     2606
    25852607VMMR3DECL(uint32_t)          DBGFR3FlowBbGetRefBbCount(DBGFFLOWBB hFlowBb);
    25862608VMMR3DECL(int)               DBGFR3FlowBbGetRefBb(DBGFFLOWBB hFlowBb, PDBGFFLOWBB pahFlowBbRef, uint32_t cRef);
     2609
     2610VMMR3DECL(uint32_t)          DBGFR3FlowBranchTblRetain(DBGFFLOWBRANCHTBL hFlowBranchTbl);
     2611VMMR3DECL(uint32_t)          DBGFR3FlowBranchTblRelease(DBGFFLOWBRANCHTBL hFlowBranchTbl);
     2612VMMR3DECL(uint32_t)          DBGFR3FlowBranchTblGetSlots(DBGFFLOWBRANCHTBL hFlowBranchTbl);
     2613VMMR3DECL(PDBGFADDRESS)      DBGFR3FlowBranchTblGetStartAddress(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS pAddrStart);
     2614VMMR3DECL(int)               DBGFR3FlowBranchTblQueryAddresses(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS paAddrs, uint32_t cAddrs);
     2615
    25872616VMMR3DECL(int)               DBGFR3FlowItCreate(DBGFFLOW hFlow, DBGFFLOWITORDER enmOrder, PDBGFFLOWIT phFlowIt);
    25882617VMMR3DECL(void)              DBGFR3FlowItDestroy(DBGFFLOWIT hFlowIt);
  • trunk/src/VBox/Debugger/DBGCEmulateCodeView.cpp

    r64577 r64586  
    16361636                            cchRightExtra++;
    16371637                        break;
     1638                    case DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP:
    16381639                    default:
    16391640                        AssertFailed();
     
    16661667                        case DBGFFLOWBBENDTYPE_LAST_DISASSEMBLED:
    16671668                        case DBGFFLOWBBENDTYPE_UNCOND_JMP:
     1669                        case DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP:
    16681670                            break;
    16691671                        case DBGFFLOWBBENDTYPE_UNCOND:
     
    17781780                            break;
    17791781                        }
     1782                        case DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP:
    17801783                        default:
    17811784                            AssertFailed();
     
    19421945
    19431946    DBGFFLOW hCfg;
    1944     rc = DBGFR3FlowCreate(pUVM, pDbgc->idCpu, &CurAddr, 0 /*cbDisasmMax*/, fFlags, &hCfg);
     1947    rc = DBGFR3FlowCreate(pUVM, pDbgc->idCpu, &CurAddr, 0 /*cbDisasmMax*/,
     1948                          DBGF_FLOW_CREATE_F_DEFAULT, fFlags, &hCfg);
    19451949    if (RT_SUCCESS(rc))
    19461950    {
  • trunk/src/VBox/Debugger/testcase/tstDBGCStubs.cpp

    r64559 r64586  
    382382
    383383VMMR3DECL(int) DBGFR3FlowCreate(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddressStart, uint32_t cbDisasmMax,
    384                                uint32_t fFlags, PDBGFFLOW phFlow)
     384                                uint32_t fFlagsFlow, uint32_t fFlagsDisasm, PDBGFFLOW phFlow)
    385385{
    386386    return VERR_INTERNAL_ERROR;
     
    402402    return VERR_INTERNAL_ERROR;
    403403}
     404VMMR3DECL(int) DBGFR3FlowQueryBranchTblByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBRANCHTBL phFlowBranchTbl)
     405{
     406    return VERR_INTERNAL_ERROR;
     407}
    404408VMMR3DECL(uint32_t) DBGFR3FlowGetBbCount(DBGFFLOW hFlow)
    405409{
    406410    return 0;
    407411}
     412VMMR3DECL(uint32_t) DBGFR3FlowGetBranchTblCount(DBGFFLOW hFlow)
     413{
     414    return 0;
     415}
    408416VMMR3DECL(uint32_t) DBGFR3FlowBbRetain(DBGFFLOWBB hFlowBb)
    409417{
     
    441449{
    442450    return 0;
     451}
     452VMMR3DECL(int) DBGFR3FlowBbQueryBranchTbl(DBGFFLOWBB hFlowBb, PDBGFFLOWBRANCHTBL phBranchTbl)
     453{
     454    return VERR_INTERNAL_ERROR;
    443455}
    444456VMMR3DECL(int) DBGFR3FlowBbQueryError(DBGFFLOWBB hFlowBb, const char **ppszErr)
     
    461473}
    462474VMMR3DECL(int) DBGFR3FlowBbGetRefBb(DBGFFLOWBB hFlowBb, PDBGFFLOWBB pahFlowBbRef, uint32_t cRef)
     475{
     476    return VERR_INTERNAL_ERROR;
     477}
     478VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRetain(DBGFFLOWBRANCHTBL hFlowBranchTbl)
     479{
     480    return 0;
     481}
     482VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRelease(DBGFFLOWBRANCHTBL hFlowBranchTbl)
     483{
     484    return 0;
     485}
     486VMMR3DECL(uint32_t) DBGFR3FlowBranchTblGetSlots(DBGFFLOWBRANCHTBL hFlowBranchTbl)
     487{
     488    return 0;
     489}
     490VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetStartAddress(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS pAddrStart)
     491{
     492    return NULL;
     493}
     494VMMR3DECL(int) DBGFR3FlowBranchTblQueryAddresses(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS paAddrs, uint32_t cAddrs)
    463495{
    464496    return VERR_INTERNAL_ERROR;
  • trunk/src/VBox/VMM/VMMR3/DBGFR3Flow.cpp

    r64563 r64586  
    6363    /** Internal reference counter for basic blocks. */
    6464    uint32_t volatile       cRefsBb;
     65    /** Flags during creation. */
     66    uint32_t                fFlags;
    6567    /** List of all basic blocks. */
    6668    RTLISTANCHOR            LstFlowBb;
     69    /** List of identified branch tables. */
     70    RTLISTANCHOR            LstBranchTbl;
    6771    /** Number of basic blocks in this control flow graph. */
    6872    uint32_t                cBbs;
     73    /** Number of branch tables in this control flow graph. */
     74    uint32_t                cBranchTbls;
    6975    /** The lowest addres of a basic block. */
    7076    DBGFADDRESS             AddrLowest;
     
    9197/** Pointer to an instruction record. */
    9298typedef DBGFFLOWBBINSTR *PDBGFFLOWBBINSTR;
     99
     100
     101/**
     102 * A branch table identified by the graph processor.
     103 */
     104typedef struct DBGFFLOWBRANCHTBLINT
     105{
     106    /** Node for the list of branch tables. */
     107    RTLISTNODE              NdBranchTbl;
     108    /** The owning control flow graph. */
     109    PDBGFFLOWINT            pFlow;
     110    /** Reference counter. */
     111    uint32_t volatile       cRefs;
     112    /** The general register index holding the bracnh table base. */
     113    uint8_t                 idxGenRegBase;
     114    /** Start address of the branch table. */
     115    DBGFADDRESS             AddrStart;
     116    /** Number of valid entries in the branch table. */
     117    uint32_t                cSlots;
     118    /** The addresses contained in the branch table - variable in size. */
     119    DBGFADDRESS             aAddresses[1];
     120} DBGFFLOWBRANCHTBLINT;
     121/** Pointer to a branch table structure. */
     122typedef DBGFFLOWBRANCHTBLINT *PDBGFFLOWBRANCHTBLINT;
     123
    93124
    94125/**
     
    115146     * if we can't infer the jump target (jmp *eax for example). */
    116147    DBGFADDRESS              AddrTarget;
     148    /** The indirect branch table identified for indirect branches. */
     149    PDBGFFLOWBRANCHTBLINT       pFlowBranchTbl;
    117150    /** Last status error code if DBGF_FLOW_BB_F_INCOMPLETE_ERR is set. */
    118151    int                      rcError;
     
    131164typedef DBGFFLOWBBINT *PDBGFFLOWBBINT;
    132165
     166
    133167/**
    134168 * Control flow graph iterator state.
     
    152186
    153187static uint32_t dbgfR3FlowBbReleaseInt(PDBGFFLOWBBINT pFlowBb, bool fMayDestroyFlow);
     188static void dbgfR3FlowBranchTblDestroy(PDBGFFLOWBRANCHTBLINT pFlowBranchTbl);
     189
     190
     191/**
     192 * Checks whether both addresses are equal.
     193 *
     194 * @returns true if both addresses point to the same location, false otherwise.
     195 * @param   pAddr1              First address.
     196 * @param   pAddr2              Second address.
     197 */
     198static bool dbgfR3FlowAddrEqual(PDBGFADDRESS pAddr1, PDBGFADDRESS pAddr2)
     199{
     200    return    pAddr1->Sel == pAddr2->Sel
     201           && pAddr1->off == pAddr2->off;
     202}
     203
     204
     205/**
     206 * Checks whether the first given address is lower than the second one.
     207 *
     208 * @returns true if both addresses point to the same location, false otherwise.
     209 * @param   pAddr1              First address.
     210 * @param   pAddr2              Second address.
     211 */
     212static bool dbgfR3FlowAddrLower(PDBGFADDRESS pAddr1, PDBGFADDRESS pAddr2)
     213{
     214    return    pAddr1->Sel == pAddr2->Sel
     215           && pAddr1->off < pAddr2->off;
     216}
     217
     218
     219/**
     220 * Checks whether the given basic block and address intersect.
     221 *
     222 * @returns true if they intersect, false otherwise.
     223 * @param   pFlowBb             The basic block to check.
     224 * @param   pAddr               The address to check for.
     225 */
     226static bool dbgfR3FlowAddrIntersect(PDBGFFLOWBBINT pFlowBb, PDBGFADDRESS pAddr)
     227{
     228    return    (pFlowBb->AddrStart.Sel == pAddr->Sel)
     229           && (pFlowBb->AddrStart.off <= pAddr->off)
     230           && (pFlowBb->AddrEnd.off >= pAddr->off);
     231}
     232
     233
     234/**
     235 * Returns the distance of the two given addresses.
     236 *
     237 * @returns Distance of the addresses.
     238 * @param   pAddr1              The first address.
     239 * @param   pAddr2              The second address.
     240 */
     241static RTGCUINTPTR dbgfR3FlowAddrGetDistance(PDBGFADDRESS pAddr1, PDBGFADDRESS pAddr2)
     242{
     243    if (pAddr1->Sel == pAddr2->Sel)
     244    {
     245        if (pAddr1->off >= pAddr2->off)
     246            return pAddr1->off - pAddr2->off;
     247        else
     248            return pAddr2->off - pAddr1->off;
     249    }
     250    else
     251        AssertFailed();
     252
     253    return 0;
     254}
     255
    154256
    155257/**
     
    159261 * @param   pThis               The control flow graph.
    160262 * @param   pAddrStart          The start of the basic block.
     263 * @param   fFlowBbFlags        Additional flags for this bascic block.
    161264 * @param   cInstrMax           Maximum number of instructions this block can hold initially.
    162265 */
    163 static PDBGFFLOWBBINT dbgfR3FlowBbCreate(PDBGFFLOWINT pThis, PDBGFADDRESS pAddrStart, uint32_t cInstrMax)
     266static PDBGFFLOWBBINT dbgfR3FlowBbCreate(PDBGFFLOWINT pThis, PDBGFADDRESS pAddrStart, uint32_t fFlowBbFlags,
     267                                         uint32_t cInstrMax)
    164268{
    165269    PDBGFFLOWBBINT pFlowBb = (PDBGFFLOWBBINT)RTMemAllocZ(RT_OFFSETOF(DBGFFLOWBBINT, aInstr[cInstrMax]));
     
    167271    {
    168272        RTListInit(&pFlowBb->NdFlowBb);
    169         pFlowBb->cRefs      = 1;
    170         pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_INVALID;
    171         pFlowBb->pFlow       = pThis;
    172         pFlowBb->fFlags     = DBGF_FLOW_BB_F_EMPTY;
    173         pFlowBb->AddrStart  = *pAddrStart;
    174         pFlowBb->AddrEnd    = *pAddrStart;
    175         pFlowBb->rcError    = VINF_SUCCESS;
    176         pFlowBb->pszErr     = NULL;
    177         pFlowBb->cInstr     = 0;
    178         pFlowBb->cInstrMax  = cInstrMax;
     273        pFlowBb->cRefs          = 1;
     274        pFlowBb->enmEndType     = DBGFFLOWBBENDTYPE_INVALID;
     275        pFlowBb->pFlow          = pThis;
     276        pFlowBb->fFlags         = DBGF_FLOW_BB_F_EMPTY | fFlowBbFlags;
     277        pFlowBb->AddrStart      = *pAddrStart;
     278        pFlowBb->AddrEnd        = *pAddrStart;
     279        pFlowBb->rcError        = VINF_SUCCESS;
     280        pFlowBb->pszErr         = NULL;
     281        pFlowBb->cInstr         = 0;
     282        pFlowBb->cInstrMax      = cInstrMax;
     283        pFlowBb->pFlowBranchTbl = NULL;
    179284        ASMAtomicIncU32(&pThis->cRefsBb);
    180285    }
    181286
    182287    return pFlowBb;
     288}
     289
     290
     291/**
     292 * Creates an empty branch table with the given size.
     293 *
     294 * @returns Pointer to the empty branch table on success or NULL if out of memory.
     295 * @param   pThis               The control flow graph.
     296 * @param   pAddrStart          The start of the branch table.
     297 * @param   idxGenRegBase       The general register index holding the base address.
     298 * @param   cSlots              Number of slots the table has.
     299 */
     300static PDBGFFLOWBRANCHTBLINT dbgfR3FlowBranchTblCreate(PDBGFFLOWINT pThis, PDBGFADDRESS pAddrStart, uint8_t idxGenRegBase, uint32_t cSlots)
     301{
     302    PDBGFFLOWBRANCHTBLINT pBranchTbl = (PDBGFFLOWBRANCHTBLINT)RTMemAllocZ(RT_OFFSETOF(DBGFFLOWBRANCHTBLINT, aAddresses[cSlots]));
     303    if (RT_LIKELY(pBranchTbl))
     304    {
     305        RTListInit(&pBranchTbl->NdBranchTbl);
     306        pBranchTbl->pFlow         = pThis;
     307        pBranchTbl->idxGenRegBase = idxGenRegBase;
     308        pBranchTbl->AddrStart     = *pAddrStart;
     309        pBranchTbl->cSlots        = cSlots;
     310        pBranchTbl->cRefs         = 1;
     311    }
     312
     313    return pBranchTbl;
    183314}
    184315
     
    203334    if (!pThis->cRefsBb)
    204335    {
     336        /* Destroy the branch tables. */
     337        PDBGFFLOWBRANCHTBLINT pTbl = NULL;
     338        PDBGFFLOWBRANCHTBLINT pTblNext = NULL;
     339        RTListForEachSafe(&pThis->LstBranchTbl, pTbl, pTblNext, DBGFFLOWBRANCHTBLINT, NdBranchTbl)
     340        {
     341            dbgfR3FlowBranchTblDestroy(pTbl);
     342        }
     343
    205344        RTStrCacheDestroy(pThis->hStrCacheInstr);
    206345        RTMemFree(pThis);
     
    234373
    235374/**
     375 * Destroys a given branch table.
     376 *
     377 * @returns nothing.
     378 * @param   pFlowBranchTbl      The flow branch table to destroy.
     379 */
     380static void dbgfR3FlowBranchTblDestroy(PDBGFFLOWBRANCHTBLINT pFlowBranchTbl)
     381{
     382    RTListNodeRemove(&pFlowBranchTbl->NdBranchTbl);
     383    RTMemFree(pFlowBranchTbl);
     384}
     385
     386
     387/**
    236388 * Internal basic block release worker.
    237389 *
     
    257409 * @returns nothing.
    258410 * @param   pThis               The control flow graph to link into.
    259  * @param   pFlowBb              The basic block to link.
     411 * @param   pFlowBb             The basic block to link.
    260412 */
    261413DECLINLINE(void) dbgfR3FlowLink(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb)
     
    267419
    268420/**
     421 * Links the given branch table into the control flow graph.
     422 *
     423 * @returns nothing.
     424 * @param   pThis               The control flow graph to link into.
     425 * @param   pBranchTbl          The branch table to link.
     426 */
     427DECLINLINE(void) dbgfR3FlowBranchTblLink(PDBGFFLOWINT pThis, PDBGFFLOWBRANCHTBLINT pBranchTbl)
     428{
     429    RTListAppend(&pThis->LstBranchTbl, &pBranchTbl->NdBranchTbl);
     430    pThis->cBranchTbls++;
     431}
     432
     433
     434/**
    269435 * Returns the first unpopulated basic block of the given control flow graph.
    270436 *
     
    286452
    287453/**
    288  * Resolves the jump target address if possible from the given instruction address
     454 * Returns the branch table with the given address if it exists.
     455 *
     456 * @returns Pointer to the branch table record or NULL if not found.
     457 * @param   pThis               The control flow graph.
     458 * @param   pAddrTbl            The branch table address.
     459 */
     460DECLINLINE(PDBGFFLOWBRANCHTBLINT) dbgfR3FlowBranchTblFindByAddr(PDBGFFLOWINT pThis, PDBGFADDRESS pAddrTbl)
     461{
     462    PDBGFFLOWBRANCHTBLINT pTbl = NULL;
     463    RTListForEach(&pThis->LstBranchTbl, pTbl, DBGFFLOWBRANCHTBLINT, NdBranchTbl)
     464    {
     465        if (dbgfR3FlowAddrEqual(&pTbl->AddrStart, pAddrTbl))
     466            return pTbl;
     467    }
     468
     469    return NULL;
     470}
     471
     472
     473/**
     474 * Sets the given error status for the basic block.
     475 *
     476 * @returns nothing.
     477 * @param   pFlowBb              The basic block causing the error.
     478 * @param   rcError             The error to set.
     479 * @param   pszFmt              Format string of the error description.
     480 * @param   ...                 Arguments for the format string.
     481 */
     482static void dbgfR3FlowBbSetError(PDBGFFLOWBBINT pFlowBb, int rcError, const char *pszFmt, ...)
     483{
     484    va_list va;
     485    va_start(va, pszFmt);
     486
     487    Assert(!(pFlowBb->fFlags & DBGF_FLOW_BB_F_INCOMPLETE_ERR));
     488    pFlowBb->fFlags |= DBGF_FLOW_BB_F_INCOMPLETE_ERR;
     489    pFlowBb->fFlags &= ~DBGF_FLOW_BB_F_EMPTY;
     490    pFlowBb->rcError = rcError;
     491    pFlowBb->pszErr = RTStrAPrintf2V(pszFmt, va);
     492    va_end(va);
     493}
     494
     495
     496/**
     497 * Checks whether the given control flow graph contains a basic block
     498 * with the given start address.
     499 *
     500 * @returns true if there is a basic block with the start address, false otherwise.
     501 * @param   pThis               The control flow graph.
     502 * @param   pAddr               The address to check for.
     503 */
     504static bool dbgfR3FlowHasBbWithStartAddr(PDBGFFLOWINT pThis, PDBGFADDRESS pAddr)
     505{
     506    PDBGFFLOWBBINT pFlowBb = NULL;
     507    RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
     508    {
     509        if (dbgfR3FlowAddrEqual(&pFlowBb->AddrStart, pAddr))
     510            return true;
     511    }
     512    return false;
     513}
     514
     515
     516/**
     517 * Splits a given basic block into two at the given address.
     518 *
     519 * @returns VBox status code.
     520 * @param   pThis               The control flow graph.
     521 * @param   pFlowBb              The basic block to split.
     522 * @param   pAddr               The address to split at.
     523 */
     524static int dbgfR3FlowBbSplit(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb, PDBGFADDRESS pAddr)
     525{
     526    int rc = VINF_SUCCESS;
     527    uint32_t idxInstrSplit;
     528
     529    /* If the block is empty it will get populated later so there is nothing to split,
     530     * same if the start address equals. */
     531    if (   pFlowBb->fFlags & DBGF_FLOW_BB_F_EMPTY
     532        || dbgfR3FlowAddrEqual(&pFlowBb->AddrStart, pAddr))
     533        return VINF_SUCCESS;
     534
     535    /* Find the instruction to split at. */
     536    for (idxInstrSplit = 1; idxInstrSplit < pFlowBb->cInstr; idxInstrSplit++)
     537        if (dbgfR3FlowAddrEqual(&pFlowBb->aInstr[idxInstrSplit].AddrInstr, pAddr))
     538            break;
     539
     540    Assert(idxInstrSplit > 0);
     541
     542    /*
     543     * Given address might not be on instruction boundary, this is not supported
     544     * so far and results in an error.
     545     */
     546    if (idxInstrSplit < pFlowBb->cInstr)
     547    {
     548        /* Create new basic block. */
     549        uint32_t cInstrNew = pFlowBb->cInstr - idxInstrSplit;
     550        PDBGFFLOWBBINT pFlowBbNew = dbgfR3FlowBbCreate(pThis, &pFlowBb->aInstr[idxInstrSplit].AddrInstr,
     551                                                       0 /*fFlowBbFlags*/, cInstrNew);
     552        if (pFlowBbNew)
     553        {
     554            /* Move instructions over. */
     555            pFlowBbNew->cInstr         = cInstrNew;
     556            pFlowBbNew->AddrEnd        = pFlowBb->AddrEnd;
     557            pFlowBbNew->enmEndType     = pFlowBb->enmEndType;
     558            pFlowBbNew->AddrTarget     = pFlowBb->AddrTarget;
     559            pFlowBbNew->fFlags         = pFlowBb->fFlags & ~DBGF_FLOW_BB_F_ENTRY;
     560            pFlowBbNew->pFlowBranchTbl = pFlowBb->pFlowBranchTbl;
     561            pFlowBb->pFlowBranchTbl    = NULL;
     562
     563            /* Move any error to the new basic block and clear them in the old basic block. */
     564            pFlowBbNew->rcError    = pFlowBb->rcError;
     565            pFlowBbNew->pszErr     = pFlowBb->pszErr;
     566            pFlowBb->rcError       = VINF_SUCCESS;
     567            pFlowBb->pszErr        = NULL;
     568            pFlowBb->fFlags       &= ~DBGF_FLOW_BB_F_INCOMPLETE_ERR;
     569
     570            memcpy(&pFlowBbNew->aInstr[0], &pFlowBb->aInstr[idxInstrSplit], cInstrNew * sizeof(DBGFFLOWBBINSTR));
     571            pFlowBb->cInstr     = idxInstrSplit;
     572            pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND;
     573            pFlowBb->AddrEnd    = pFlowBb->aInstr[idxInstrSplit-1].AddrInstr;
     574            pFlowBb->AddrTarget = pFlowBbNew->AddrStart;
     575            DBGFR3AddrAdd(&pFlowBb->AddrEnd, pFlowBb->aInstr[idxInstrSplit-1].cbInstr - 1);
     576            RT_BZERO(&pFlowBb->aInstr[idxInstrSplit], cInstrNew * sizeof(DBGFFLOWBBINSTR));
     577
     578            dbgfR3FlowLink(pThis, pFlowBbNew);
     579        }
     580        else
     581            rc = VERR_NO_MEMORY;
     582    }
     583    else
     584        AssertFailedStmt(rc = VERR_INVALID_STATE); /** @todo: Proper status code. */
     585
     586    return rc;
     587}
     588
     589
     590/**
     591 * Makes sure there is an successor at the given address splitting already existing
     592 * basic blocks if they intersect.
     593 *
     594 * @returns VBox status code.
     595 * @param   pThis               The control flow graph.
     596 * @param   pAddrSucc           The guest address the new successor should start at.
     597 * @param   fNewBbFlags         Flags for the new basic block.
     598 * @param   pBranchTbl          Branch table candidate for this basic block.
     599 */
     600static int dbgfR3FlowBbSuccessorAdd(PDBGFFLOWINT pThis, PDBGFADDRESS pAddrSucc,
     601                                    uint32_t fNewBbFlags, PDBGFFLOWBRANCHTBLINT pBranchTbl)
     602{
     603    PDBGFFLOWBBINT pFlowBb = NULL;
     604    RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
     605    {
     606        /*
     607         * The basic block must be split if it intersects with the given address
     608         * and the start address does not equal the given one.
     609         */
     610        if (dbgfR3FlowAddrIntersect(pFlowBb, pAddrSucc))
     611            return dbgfR3FlowBbSplit(pThis, pFlowBb, pAddrSucc);
     612    }
     613
     614    int rc = VINF_SUCCESS;
     615    pFlowBb = dbgfR3FlowBbCreate(pThis, pAddrSucc, fNewBbFlags, 10);
     616    if (pFlowBb)
     617    {
     618        pFlowBb->pFlowBranchTbl = pBranchTbl;
     619        dbgfR3FlowLink(pThis, pFlowBb);
     620    }
     621    else
     622        rc = VERR_NO_MEMORY;
     623
     624    return rc;
     625}
     626
     627
     628/**
     629 * Returns whether the parameter indicates an indirect branch.
     630 *
     631 * @returns Flag whether this is an indirect branch.
     632 * @param   pDisParam           The parameter from the disassembler.
     633 */
     634DECLINLINE(bool) dbgfR3FlowBranchTargetIsIndirect(PDISOPPARAM pDisParam)
     635{
     636    bool fIndirect = true;
     637
     638    if (   pDisParam->fUse & (DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32 | DISUSE_IMMEDIATE64)
     639        || pDisParam->fUse & (DISUSE_IMMEDIATE8_REL | DISUSE_IMMEDIATE16_REL | DISUSE_IMMEDIATE32_REL | DISUSE_IMMEDIATE64_REL))
     640        fIndirect = false;
     641
     642    return fIndirect;
     643}
     644
     645
     646/**
     647 * Resolves the direct branch target address if possible from the given instruction address
    289648 * and instruction parameter.
    290649 *
     
    292651 * @param   pUVM                The usermode VM handle.
    293652 * @param   idCpu               CPU id for resolving the address.
    294  * @param   pDisParam           The parmeter from the disassembler.
     653 * @param   pDisParam           The parameter from the disassembler.
    295654 * @param   pAddrInstr          The instruction address.
    296655 * @param   cbInstr             Size of instruction in bytes.
     
    298657 * @param   pAddrJmpTarget      Where to store the address to the jump target on success.
    299658 */
    300 static int dbgfR3FlowQueryJmpTarget(PUVM pUVM, VMCPUID idCpu, PDISOPPARAM pDisParam, PDBGFADDRESS pAddrInstr,
    301                                    uint32_t cbInstr, bool fRelJmp, PDBGFADDRESS pAddrJmpTarget)
     659static int dbgfR3FlowQueryDirectBranchTarget(PUVM pUVM, VMCPUID idCpu, PDISOPPARAM pDisParam, PDBGFADDRESS pAddrInstr,
     660                                             uint32_t cbInstr, bool fRelJmp, PDBGFADDRESS pAddrJmpTarget)
    302661{
    303662    int rc = VINF_SUCCESS;
     663
     664    Assert(!dbgfR3FlowBranchTargetIsIndirect(pDisParam));
    304665
    305666    /* Relative jumps are always from the beginning of the next instruction. */
     
    336697        }
    337698        else
    338             AssertFailedStmt(rc = VERR_NOT_SUPPORTED);
     699            AssertFailedStmt(rc = VERR_INVALID_STATE);
    339700    }
    340701
     
    344705
    345706/**
    346  * Checks whether both addresses are equal.
    347  *
    348  * @returns true if both addresses point to the same location, false otherwise.
    349  * @param   pAddr1              First address.
    350  * @param   pAddr2              Second address.
    351  */
    352 static bool dbgfR3FlowBbAddrEqual(PDBGFADDRESS pAddr1, PDBGFADDRESS pAddr2)
    353 {
    354     return    pAddr1->Sel == pAddr2->Sel
    355            && pAddr1->off == pAddr2->off;
    356 }
    357 
    358 
    359 /**
    360  * Checks whether the first given address is lower than the second one.
    361  *
    362  * @returns true if both addresses point to the same location, false otherwise.
    363  * @param   pAddr1              First address.
    364  * @param   pAddr2              Second address.
    365  */
    366 static bool dbgfR3FlowBbAddrLower(PDBGFADDRESS pAddr1, PDBGFADDRESS pAddr2)
    367 {
    368     return    pAddr1->Sel == pAddr2->Sel
    369            && pAddr1->off < pAddr2->off;
    370 }
    371 
    372 
    373 /**
    374  * Checks whether the given basic block and address intersect.
    375  *
    376  * @returns true if they intersect, false otherwise.
    377  * @param   pFlowBb              The basic block to check.
    378  * @param   pAddr               The address to check for.
    379  */
    380 static bool dbgfR3FlowBbAddrIntersect(PDBGFFLOWBBINT pFlowBb, PDBGFADDRESS pAddr)
    381 {
    382     return    (pFlowBb->AddrStart.Sel == pAddr->Sel)
    383            && (pFlowBb->AddrStart.off <= pAddr->off)
    384            && (pFlowBb->AddrEnd.off >= pAddr->off);
    385 }
    386 
    387 
    388 /**
    389  * Checks whether the given control flow graph contains a basic block
    390  * with the given start address.
    391  *
    392  * @returns true if there is a basic block with the start address, false otherwise.
    393  * @param   pThis               The control flow graph.
    394  * @param   pAddr               The address to check for.
    395  */
    396 static bool dbgfR3FlowHasBbWithStartAddr(PDBGFFLOWINT pThis, PDBGFADDRESS pAddr)
    397 {
    398     PDBGFFLOWBBINT pFlowBb = NULL;
    399     RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
    400     {
    401         if (dbgfR3FlowBbAddrEqual(&pFlowBb->AddrStart, pAddr))
    402             return true;
    403     }
    404     return false;
    405 }
    406 
    407 /**
    408  * Splits a given basic block into two at the given address.
    409  *
    410  * @returns VBox status code.
    411  * @param   pThis               The control flow graph.
    412  * @param   pFlowBb              The basic block to split.
    413  * @param   pAddr               The address to split at.
    414  */
    415 static int dbgfR3FlowBbSplit(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb, PDBGFADDRESS pAddr)
    416 {
    417     int rc = VINF_SUCCESS;
    418     uint32_t idxInstrSplit;
    419 
    420     /* If the block is empty it will get populated later so there is nothing to split,
    421      * same if the start address equals. */
    422     if (   pFlowBb->fFlags & DBGF_FLOW_BB_F_EMPTY
    423         || dbgfR3FlowBbAddrEqual(&pFlowBb->AddrStart, pAddr))
    424         return VINF_SUCCESS;
    425 
    426     /* Find the instruction to split at. */
    427     for (idxInstrSplit = 1; idxInstrSplit < pFlowBb->cInstr; idxInstrSplit++)
    428         if (dbgfR3FlowBbAddrEqual(&pFlowBb->aInstr[idxInstrSplit].AddrInstr, pAddr))
    429             break;
    430 
    431     Assert(idxInstrSplit > 0);
    432 
    433     /*
    434      * Given address might not be on instruction boundary, this is not supported
    435      * so far and results in an error.
    436      */
    437     if (idxInstrSplit < pFlowBb->cInstr)
    438     {
    439         /* Create new basic block. */
    440         uint32_t cInstrNew = pFlowBb->cInstr - idxInstrSplit;
    441         PDBGFFLOWBBINT pFlowBbNew = dbgfR3FlowBbCreate(pThis, &pFlowBb->aInstr[idxInstrSplit].AddrInstr,
    442                                                     cInstrNew);
    443         if (pFlowBbNew)
     707 * Returns the CPU mode based on the given assembler flags.
     708 *
     709 * @returns CPU mode.
     710 * @param   pUVM                The user mode VM handle.
     711 * @param   idCpu               CPU id for disassembling.
     712 * @param   fFlagsDisasm        The flags used for disassembling.
     713 */
     714static CPUMMODE dbgfR3FlowGetDisasCpuMode(PUVM pUVM, VMCPUID idCpu, uint32_t fFlagsDisasm)
     715{
     716    CPUMMODE enmMode = CPUMMODE_INVALID;
     717    uint32_t fDisasMode = fFlagsDisasm & DBGF_DISAS_FLAGS_MODE_MASK;
     718    if (fDisasMode == DBGF_DISAS_FLAGS_DEFAULT_MODE)
     719        enmMode = DBGFR3CpuGetMode(pUVM, idCpu);
     720    else if (   fDisasMode == DBGF_DISAS_FLAGS_16BIT_MODE
     721             || fDisasMode == DBGF_DISAS_FLAGS_16BIT_REAL_MODE)
     722        enmMode = CPUMMODE_REAL;
     723    else if (fDisasMode == DBGF_DISAS_FLAGS_32BIT_MODE)
     724        enmMode = CPUMMODE_PROTECTED;
     725    else if (fDisasMode == DBGF_DISAS_FLAGS_32BIT_MODE)
     726        enmMode = CPUMMODE_LONG;
     727    else
     728        AssertFailed();
     729
     730    return enmMode;
     731}
     732
     733
     734/**
     735 * Searches backwards in the given basic block starting the given instruction index for
     736 * a mov instruction with the given register as the target where the constant looks like
     737 * a pointer.
     738 *
     739 * @returns Flag whether a candidate was found.
     740 * @param   idxRegTgt           The general register the mov targets.
     741 * @param   cbPtr               The pointer size to look for.
     742 * @param   pUVM                The user mode VM handle.
     743 * @param   idCpu               CPU id for disassembling.
     744 * @param   fFlagsDisasm        The flags to use for disassembling.
     745 * @param   pidxInstrStart      The instruction index to start searching for on input,
     746 *                              The last instruction evaluated on output.
     747 * @param   pAddrDest           Where to store the candidate address on success.
     748 */
     749static bool dbgfR3FlowSearchMovWithConstantPtrSizeBackwards(PDBGFFLOWBBINT pFlowBb, uint8_t idxRegTgt, uint32_t cbPtr,
     750                                                            PUVM pUVM, VMCPUID idCpu, uint32_t fFlagsDisasm,
     751                                                            uint32_t *pidxInstrStart, PDBGFADDRESS pAddrDest)
     752{
     753    bool fFound = false;
     754    uint32_t idxInstrCur = *pidxInstrStart;
     755    uint32_t cInstrCheck = idxInstrCur + 1;
     756
     757    for (;;)
     758    {
     759        /** @todo: Avoid to disassemble again. */
     760        PDBGFFLOWBBINSTR pInstr = &pFlowBb->aInstr[idxInstrCur];
     761        DBGFDISSTATE DisState;
     762        char szOutput[_4K];
     763
     764        int rc = dbgfR3DisasInstrStateEx(pUVM, idCpu, &pInstr->AddrInstr, fFlagsDisasm,
     765                                         &szOutput[0], sizeof(szOutput), &DisState);
     766        if (RT_SUCCESS(rc))
    444767        {
    445             /* Move instructions over. */
    446             pFlowBbNew->cInstr     = cInstrNew;
    447             pFlowBbNew->AddrEnd    = pFlowBb->AddrEnd;
    448             pFlowBbNew->enmEndType = pFlowBb->enmEndType;
    449             pFlowBbNew->AddrTarget = pFlowBb->AddrTarget;
    450             pFlowBbNew->fFlags     = pFlowBb->fFlags & ~DBGF_FLOW_BB_F_ENTRY;
    451 
    452             /* Move any error to the new basic block and clear them in the old basic block. */
    453             pFlowBbNew->rcError    = pFlowBb->rcError;
    454             pFlowBbNew->pszErr     = pFlowBb->pszErr;
    455             pFlowBb->rcError       = VINF_SUCCESS;
    456             pFlowBb->pszErr        = NULL;
    457             pFlowBb->fFlags       &= ~DBGF_FLOW_BB_F_INCOMPLETE_ERR;
    458 
    459             memcpy(&pFlowBbNew->aInstr[0], &pFlowBb->aInstr[idxInstrSplit], cInstrNew * sizeof(DBGFFLOWBBINSTR));
    460             pFlowBb->cInstr     = idxInstrSplit;
    461             pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND;
    462             pFlowBb->AddrEnd    = pFlowBb->aInstr[idxInstrSplit-1].AddrInstr;
    463             pFlowBb->AddrTarget = pFlowBbNew->AddrStart;
    464             DBGFR3AddrAdd(&pFlowBb->AddrEnd, pFlowBb->aInstr[idxInstrSplit-1].cbInstr - 1);
    465             RT_BZERO(&pFlowBb->aInstr[idxInstrSplit], cInstrNew * sizeof(DBGFFLOWBBINSTR));
    466 
    467             dbgfR3FlowLink(pThis, pFlowBbNew);
     768            if (   DisState.pCurInstr->uOpcode == OP_MOV
     769                && (DisState.Param1.fUse & (DISUSE_REG_GEN16 | DISUSE_REG_GEN32 | DISUSE_REG_GEN64))
     770                && DisState.Param1.Base.idxGenReg == idxRegTgt
     771                /*&& DisState.Param1.cb == cbPtr*/
     772                && DisState.Param2.cb == cbPtr
     773                && (DisState.Param2.fUse & (DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32 | DISUSE_IMMEDIATE64)))
     774            {
     775                /* Found possible candidate. */
     776                fFound = true;
     777                if (DBGFADDRESS_IS_FLAT(&pInstr->AddrInstr))
     778                    DBGFR3AddrFromFlat(pUVM, pAddrDest, DisState.Param2.uValue);
     779                else
     780                    DBGFR3AddrFromSelOff(pUVM, idCpu, pAddrDest, pInstr->AddrInstr.Sel, DisState.Param2.uValue);
     781                break;
     782            }
    468783        }
    469784        else
    470             rc = VERR_NO_MEMORY;
     785            break;
     786
     787        cInstrCheck--;
     788        if (!cInstrCheck)
     789            break;
     790
     791        idxInstrCur--;
     792    }
     793
     794    *pidxInstrStart = idxInstrCur;
     795    return fFound;
     796}
     797
     798
     799/**
     800 * Verifies the given branch table candidate and adds it to the control flow graph on success.
     801 *
     802 * @returns VBox status code.
     803 * @param   pThis               The flow control graph.
     804 * @param   pFlowBb             The basic block causing the indirect branch.
     805 * @param   pAddrBranchTbl      Address of the branch table location.
     806 * @param   idxGenRegBase       The general register holding the base address.
     807 * @param   cbPtr               Guest pointer size.
     808 * @param   pUVM                The user mode VM handle.
     809 * @param   idCpu               CPU id for disassembling.
     810 *
     811 * @todo Handle branch tables greater than 4KB (lazy coder).
     812 */
     813static int dbgfR3FlowBranchTblVerifyAdd(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb, PDBGFADDRESS pAddrBranchTbl,
     814                                        uint8_t idxGenRegBase, uint32_t cbPtr, PUVM pUVM, VMCPUID idCpu)
     815{
     816    int rc = VINF_SUCCESS;
     817    PDBGFFLOWBRANCHTBLINT pBranchTbl = dbgfR3FlowBranchTblFindByAddr(pThis, pAddrBranchTbl);
     818
     819    if (!pBranchTbl)
     820    {
     821        uint32_t cSlots = 0;
     822        uint8_t abBuf[_4K];
     823
     824        rc = DBGFR3MemRead(pUVM, idCpu, pAddrBranchTbl, &abBuf[0], sizeof(abBuf));
     825        if (RT_SUCCESS(rc))
     826        {
     827            uint8_t *pbBuf = &abBuf[0];
     828            while (pbBuf < &abBuf[0] + sizeof(abBuf))
     829            {
     830                DBGFADDRESS AddrDest;
     831                RTGCUINTPTR GCPtr =   cbPtr == sizeof(uint64_t)
     832                                    ? *(uint64_t *)pbBuf
     833                                    : cbPtr == sizeof(uint32_t)
     834                                    ? *(uint32_t *)pbBuf
     835                                    : *(uint16_t *)pbBuf;
     836                pbBuf += cbPtr;
     837
     838                if (DBGFADDRESS_IS_FLAT(pAddrBranchTbl))
     839                    DBGFR3AddrFromFlat(pUVM, &AddrDest, GCPtr);
     840                else
     841                    DBGFR3AddrFromSelOff(pUVM, idCpu, &AddrDest, pAddrBranchTbl->Sel, GCPtr);
     842
     843                if (dbgfR3FlowAddrGetDistance(&AddrDest, &pFlowBb->AddrEnd) > _512K)
     844                    break;
     845
     846                cSlots++;
     847            }
     848
     849            /* If there are any slots use it. */
     850            if (cSlots)
     851            {
     852                pBranchTbl = dbgfR3FlowBranchTblCreate(pThis, pAddrBranchTbl, idxGenRegBase, cSlots);
     853                if (pBranchTbl)
     854                {
     855                    /* Get the addresses. */
     856                    for (unsigned i = 0; i < cSlots && RT_SUCCESS(rc); i++)
     857                    {
     858                        RTGCUINTPTR GCPtr =   cbPtr == sizeof(uint64_t)
     859                                            ? *(uint64_t *)&abBuf[i * cbPtr]
     860                                            : cbPtr == sizeof(uint32_t)
     861                                            ? *(uint32_t *)&abBuf[i * cbPtr]
     862                                            : *(uint16_t *)&abBuf[i * cbPtr];
     863
     864                        if (DBGFADDRESS_IS_FLAT(pAddrBranchTbl))
     865                            DBGFR3AddrFromFlat(pUVM, &pBranchTbl->aAddresses[i], GCPtr);
     866                        else
     867                            DBGFR3AddrFromSelOff(pUVM, idCpu, &pBranchTbl->aAddresses[i],
     868                                                 pAddrBranchTbl->Sel, GCPtr);
     869                        rc = dbgfR3FlowBbSuccessorAdd(pThis, &pBranchTbl->aAddresses[i], DBGF_FLOW_BB_F_BRANCH_TABLE,
     870                                                      pBranchTbl);
     871                    }
     872                    dbgfR3FlowBranchTblLink(pThis, pBranchTbl);
     873                }
     874                else
     875                    rc = VERR_NO_MEMORY;
     876            }
     877        }
     878    }
     879
     880    if (pBranchTbl)
     881        pFlowBb->pFlowBranchTbl = pBranchTbl;
     882
     883    return rc;
     884}
     885
     886
     887/**
     888 * Checks whether the location for the branch target candidate contains a valid code address.
     889 *
     890 * @returns VBox status code.
     891 * @param   pThis               The flow control graph.
     892 * @param   pFlowBb             The basic block causing the indirect branch.
     893 * @param   pAddrBranchTgt      Address of the branch target location.
     894 * @param   idxGenRegBase       The general register holding the address of the location.
     895 * @param   cbPtr               Guest pointer size.
     896 * @param   pUVM                The user mode VM handle.
     897 * @param   idCpu               CPU id for disassembling.
     898 * @param   fBranchTbl          Flag whether this is a possible branch table containing multiple
     899 *                              targets.
     900 */
     901static int dbgfR3FlowCheckBranchTargetLocation(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb, PDBGFADDRESS pAddrBranchTgt,
     902                                               uint8_t idxGenRegBase, uint32_t cbPtr, PUVM pUVM, VMCPUID idCpu, bool fBranchTbl)
     903{
     904    int rc = VINF_SUCCESS;
     905
     906    if (!fBranchTbl)
     907    {
     908        union { uint16_t u16Val; uint32_t u32Val; uint64_t u64Val; } uVal;
     909        rc = DBGFR3MemRead(pUVM, idCpu, pAddrBranchTgt, &uVal, cbPtr);
     910        if (RT_SUCCESS(rc))
     911        {
     912            DBGFADDRESS AddrTgt;
     913            RTGCUINTPTR GCPtr =   cbPtr == sizeof(uint64_t)
     914                                ? uVal.u64Val
     915                                : cbPtr == sizeof(uint32_t)
     916                                ? uVal.u32Val
     917                                : uVal.u16Val;
     918            if (DBGFADDRESS_IS_FLAT(pAddrBranchTgt))
     919                DBGFR3AddrFromFlat(pUVM, &AddrTgt, GCPtr);
     920            else
     921                DBGFR3AddrFromSelOff(pUVM, idCpu, &AddrTgt, pAddrBranchTgt->Sel, GCPtr);
     922
     923            if (dbgfR3FlowAddrGetDistance(&AddrTgt, &pFlowBb->AddrEnd) <= _128K)
     924            {
     925                /* Finish the basic block. */
     926                pFlowBb->AddrTarget = AddrTgt;
     927                rc = dbgfR3FlowBbSuccessorAdd(pThis, &AddrTgt,
     928                                              (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
     929                                              pFlowBb->pFlowBranchTbl);
     930            }
     931            else
     932                rc = VERR_NOT_FOUND;
     933        }
    471934    }
    472935    else
    473         AssertFailedStmt(rc = VERR_INVALID_STATE); /** @todo: Proper status code. */
     936        rc = dbgfR3FlowBranchTblVerifyAdd(pThis, pFlowBb, pAddrBranchTgt,
     937                                          idxGenRegBase, cbPtr, pUVM, idCpu);
    474938
    475939    return rc;
     
    478942
    479943/**
    480  * Makes sure there is an successor at the given address splitting already existing
    481  * basic blocks if they intersect.
     944 * Tries to resolve the indirect branch.
    482945 *
    483946 * @returns VBox status code.
    484  * @param   pThis               The control flow graph.
    485  * @param   pAddrSucc           The guest address the new successor should start at.
    486  */
    487 static int dbgfR3FlowBbSuccessorAdd(PDBGFFLOWINT pThis, PDBGFADDRESS pAddrSucc)
    488 {
    489     PDBGFFLOWBBINT pFlowBb = NULL;
    490     RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
    491     {
    492         /*
    493          * The basic block must be split if it intersects with the given address
    494          * and the start address does not equal the given one.
    495          */
    496         if (dbgfR3FlowBbAddrIntersect(pFlowBb, pAddrSucc))
    497             return dbgfR3FlowBbSplit(pThis, pFlowBb, pAddrSucc);
    498     }
    499 
     947 * @param   pThis               The flow control graph.
     948 * @param   pFlowBb             The basic block causing the indirect branch.
     949 * @param   pUVM                The user mode VM handle.
     950 * @param   idCpu               CPU id for disassembling.
     951 * @param   pDisParam           The parameter from the disassembler.
     952 * @param   fFlagsDisasm        Flags for the disassembler.
     953 */
     954static int dbgfR3FlowTryResolveIndirectBranch(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb, PUVM pUVM,
     955                                              VMCPUID idCpu, PDISOPPARAM pDisParam, uint32_t fFlagsDisasm)
     956{
     957    Assert(dbgfR3FlowBranchTargetIsIndirect(pDisParam));
     958
     959    uint32_t cbPtr = 0;
     960    CPUMMODE enmMode = dbgfR3FlowGetDisasCpuMode(pUVM, idCpu, fFlagsDisasm);
     961
     962    switch (enmMode)
     963    {
     964        case CPUMMODE_REAL:
     965            cbPtr = sizeof(uint16_t);
     966            break;
     967        case CPUMMODE_PROTECTED:
     968            cbPtr = sizeof(uint32_t);
     969            break;
     970        case CPUMMODE_LONG:
     971            cbPtr = sizeof(uint64_t);
     972            break;
     973        default:
     974            AssertMsgFailed(("Invalid CPU mode %u\n", enmMode));
     975    }
     976
     977    if (pDisParam->fUse & DISUSE_BASE)
     978    {
     979        uint8_t idxRegBase = pDisParam->Base.idxGenReg;
     980
     981        /* Check that the used register size and the pointer size match. */
     982        if (   ((pDisParam->fUse & DISUSE_REG_GEN16) && cbPtr == sizeof(uint16_t))
     983            || ((pDisParam->fUse & DISUSE_REG_GEN32) && cbPtr == sizeof(uint32_t))
     984            || ((pDisParam->fUse & DISUSE_REG_GEN64) && cbPtr == sizeof(uint64_t)))
     985        {
     986            /*
     987             * Search all instructions backwards until a move to the used general register
     988             * is detected with a constant using the pointer size.
     989             */
     990            uint32_t idxInstrStart = pFlowBb->cInstr - 1 - 1; /* Don't look at the branch. */
     991            bool fCandidateFound = false;
     992            bool fBranchTbl = RT_BOOL(pDisParam->fUse & DISUSE_INDEX);
     993            DBGFADDRESS AddrBranchTgt;
     994            do
     995            {
     996                fCandidateFound = dbgfR3FlowSearchMovWithConstantPtrSizeBackwards(pFlowBb, idxRegBase, cbPtr,
     997                                                                                  pUVM, idCpu, fFlagsDisasm,
     998                                                                                  &idxInstrStart, &AddrBranchTgt);
     999                if (fCandidateFound)
     1000                {
     1001                    /* Check that the address is not too far away from the instruction address. */
     1002                    RTGCUINTPTR offPtr = dbgfR3FlowAddrGetDistance(&AddrBranchTgt, &pFlowBb->AddrEnd);
     1003                    if (offPtr <= 20 * _1M)
     1004                    {
     1005                        /* Read the content at the address and check that it is near this basic block too. */
     1006                        int rc = dbgfR3FlowCheckBranchTargetLocation(pThis, pFlowBb, &AddrBranchTgt, idxRegBase,
     1007                                                                     cbPtr, pUVM, idCpu, fBranchTbl);
     1008                        if (RT_SUCCESS(rc))
     1009                            break;
     1010                        fCandidateFound = false;
     1011                    }
     1012
     1013                    if (idxInstrStart > 0)
     1014                        idxInstrStart--;
     1015                }
     1016            } while (idxInstrStart > 0 && !fCandidateFound);
     1017        }
     1018        else
     1019            dbgfR3FlowBbSetError(pFlowBb, VERR_INVALID_STATE,
     1020                                 "The base register size and selected pointer size do not match (fUse=%#x cbPtr=%u)",
     1021                                 pDisParam->fUse, cbPtr);
     1022    }
     1023
     1024    return VINF_SUCCESS;
     1025}
     1026
     1027
     1028/**
     1029 * Tries to resolve the indirect branch.
     1030 *
     1031 * @returns VBox status code.
     1032 * @param   pThis               The flow control graph.
     1033 * @param   pFlowBb             The basic block causing the indirect branch.
     1034 * @param   pUVM                The user mode VM handle.
     1035 * @param   idCpu               CPU id for disassembling.
     1036 * @param   pDisParam           The parameter from the disassembler.
     1037 * @param   fFlagsDisasm        Flags for the disassembler.
     1038 */
     1039static int dbgfR3FlowBbCheckBranchTblCandidate(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb, PUVM pUVM,
     1040                                               VMCPUID idCpu, PDISOPPARAM pDisParam, uint32_t fFlagsDisasm)
     1041{
    5001042    int rc = VINF_SUCCESS;
    501     pFlowBb = dbgfR3FlowBbCreate(pThis, pAddrSucc, 10);
    502     if (pFlowBb)
    503         dbgfR3FlowLink(pThis, pFlowBb);
     1043
     1044    Assert(pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE && pFlowBb->pFlowBranchTbl);
     1045
     1046    uint32_t cbPtr = 0;
     1047    CPUMMODE enmMode = dbgfR3FlowGetDisasCpuMode(pUVM, idCpu, fFlagsDisasm);
     1048
     1049    switch (enmMode)
     1050    {
     1051        case CPUMMODE_REAL:
     1052            cbPtr = sizeof(uint16_t);
     1053            break;
     1054        case CPUMMODE_PROTECTED:
     1055            cbPtr = sizeof(uint32_t);
     1056            break;
     1057        case CPUMMODE_LONG:
     1058            cbPtr = sizeof(uint64_t);
     1059            break;
     1060        default:
     1061            AssertMsgFailed(("Invalid CPU mode %u\n", enmMode));
     1062    }
     1063
     1064    if (pDisParam->fUse & DISUSE_BASE)
     1065    {
     1066        uint8_t idxRegBase = pDisParam->Base.idxGenReg;
     1067
     1068        /* Check that the used register size and the pointer size match. */
     1069        if (   ((pDisParam->fUse & DISUSE_REG_GEN16) && cbPtr == sizeof(uint16_t))
     1070            || ((pDisParam->fUse & DISUSE_REG_GEN32) && cbPtr == sizeof(uint32_t))
     1071            || ((pDisParam->fUse & DISUSE_REG_GEN64) && cbPtr == sizeof(uint64_t)))
     1072        {
     1073            if (idxRegBase != pFlowBb->pFlowBranchTbl->idxGenRegBase)
     1074            {
     1075                /* Try to find the new branch table. */
     1076                pFlowBb->pFlowBranchTbl = NULL;
     1077                rc = dbgfR3FlowTryResolveIndirectBranch(pThis, pFlowBb, pUVM, idCpu, pDisParam, fFlagsDisasm);
     1078            }
     1079            /** @todo: else check that the base register is not modified in this basic block. */
     1080        }
     1081        else
     1082            dbgfR3FlowBbSetError(pFlowBb, VERR_INVALID_STATE,
     1083                                 "The base register size and selected pointer size do not match (fUse=%#x cbPtr=%u)",
     1084                                 pDisParam->fUse, cbPtr);
     1085    }
    5041086    else
    505         rc = VERR_NO_MEMORY;
     1087        dbgfR3FlowBbSetError(pFlowBb, VERR_INVALID_STATE,
     1088                             "The instruction does not use a register");
    5061089
    5071090    return rc;
    508 }
    509 
    510 
    511 /**
    512  * Sets the given error status for the basic block.
    513  *
    514  * @returns nothing.
    515  * @param   pFlowBb              The basic block causing the error.
    516  * @param   rcError             The error to set.
    517  * @param   pszFmt              Format string of the error description.
    518  * @param   ...                 Arguments for the format string.
    519  */
    520 static void dbgfR3FlowBbSetError(PDBGFFLOWBBINT pFlowBb, int rcError, const char *pszFmt, ...)
    521 {
    522     va_list va;
    523     va_start(va, pszFmt);
    524 
    525     Assert(!(pFlowBb->fFlags & DBGF_FLOW_BB_F_INCOMPLETE_ERR));
    526     pFlowBb->fFlags |= DBGF_FLOW_BB_F_INCOMPLETE_ERR;
    527     pFlowBb->fFlags &= ~DBGF_FLOW_BB_F_EMPTY;
    528     pFlowBb->rcError = rcError;
    529     pFlowBb->pszErr = RTStrAPrintf2V(pszFmt, va);
    530     va_end(va);
    5311091}
    5321092
     
    5391099 * @param   idCpu               CPU id for disassembling.
    5401100 * @param   pThis               The control flow graph to populate.
    541  * @param   pFlowBb              The basic block to fill.
     1101 * @param   pFlowBb             The basic block to fill.
    5421102 * @param   cbDisasmMax         The maximum amount to disassemble.
    5431103 * @param   fFlags              Combination of DBGF_DISAS_FLAGS_*.
     
    6241184                    {
    6251185                        Assert(DisState.pCurInstr->fOpType & DISOPTYPE_UNCOND_CONTROLFLOW);
    626                         pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND_JMP;
    627 
    628                         /* Create one new basic block with the jump target address. */
    629                         rc = dbgfR3FlowQueryJmpTarget(pUVM, idCpu, &DisState.Param1, &pInstr->AddrInstr, pInstr->cbInstr,
    630                                                      RT_BOOL(DisState.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW),
    631                                                      &pFlowBb->AddrTarget);
    632                         if (RT_SUCCESS(rc))
    633                             rc = dbgfR3FlowBbSuccessorAdd(pThis, &pFlowBb->AddrTarget);
     1186
     1187                        if (dbgfR3FlowBranchTargetIsIndirect(&DisState.Param1))
     1188                        {
     1189                            pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP;
     1190
     1191                            if (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE)
     1192                            {
     1193                                Assert(pThis->fFlags & DBGF_FLOW_CREATE_F_TRY_RESOLVE_INDIRECT_BRANCHES);
     1194
     1195                                /*
     1196                                 * This basic block was already discovered by parsing a jump table and
     1197                                 * there should be a candidate for the branch table. Check whether it uses the
     1198                                 * same branch table.
     1199                                 */
     1200                                rc = dbgfR3FlowBbCheckBranchTblCandidate(pThis, pFlowBb, pUVM, idCpu,
     1201                                                                         &DisState.Param1, fFlags);
     1202                            }
     1203                            else
     1204                            {
     1205                                if (pThis->fFlags & DBGF_FLOW_CREATE_F_TRY_RESOLVE_INDIRECT_BRANCHES)
     1206                                    rc = dbgfR3FlowTryResolveIndirectBranch(pThis, pFlowBb, pUVM, idCpu,
     1207                                                                            &DisState.Param1, fFlags);
     1208                                else
     1209                                    dbgfR3FlowBbSetError(pFlowBb, VERR_NOT_SUPPORTED,
     1210                                                         "Detected indirect branch and resolving it not being enabled");
     1211                            }
     1212                        }
     1213                        else
     1214                        {
     1215                            pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND_JMP;
     1216
     1217                            /* Create one new basic block with the jump target address. */
     1218                            rc = dbgfR3FlowQueryDirectBranchTarget(pUVM, idCpu, &DisState.Param1, &pInstr->AddrInstr, pInstr->cbInstr,
     1219                                                                   RT_BOOL(DisState.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW),
     1220                                                                   &pFlowBb->AddrTarget);
     1221                            if (RT_SUCCESS(rc))
     1222                                rc = dbgfR3FlowBbSuccessorAdd(pThis, &pFlowBb->AddrTarget,
     1223                                                              (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
     1224                                                              pFlowBb->pFlowBranchTbl);
     1225                        }
    6341226                    }
    6351227                    else if (uOpc != OP_CALL)
     
    6421234                         * and one starting after the current instruction.
    6431235                         */
    644                         rc = dbgfR3FlowBbSuccessorAdd(pThis, &AddrDisasm);
     1236                        rc = dbgfR3FlowBbSuccessorAdd(pThis, &AddrDisasm,
     1237                                                      (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
     1238                                                      pFlowBb->pFlowBranchTbl);
    6451239                        if (RT_SUCCESS(rc))
    6461240                        {
    647                             rc = dbgfR3FlowQueryJmpTarget(pUVM, idCpu, &DisState.Param1, &pInstr->AddrInstr, pInstr->cbInstr,
    648                                                          RT_BOOL(DisState.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW),
    649                                                          &pFlowBb->AddrTarget);
     1241                            rc = dbgfR3FlowQueryDirectBranchTarget(pUVM, idCpu, &DisState.Param1, &pInstr->AddrInstr, pInstr->cbInstr,
     1242                                                                   RT_BOOL(DisState.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW),
     1243                                                                   &pFlowBb->AddrTarget);
    6501244                            if (RT_SUCCESS(rc))
    651                                 rc = dbgfR3FlowBbSuccessorAdd(pThis, &pFlowBb->AddrTarget);
     1245                                rc = dbgfR3FlowBbSuccessorAdd(pThis, &pFlowBb->AddrTarget,
     1246                                                              (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
     1247                                                              pFlowBb->pFlowBranchTbl);
    6521248                        }
    6531249                    }
     
    7111307 * @param   pAddressStart       Where to start creating the control flow graph.
    7121308 * @param   cbDisasmMax         Limit the amount of bytes to disassemble, 0 for no limit.
    713  * @param   fFlags              Combination of DBGF_DISAS_FLAGS_*.
     1309 * @param   fFlagsFlow          Combination of DBGF_FLOW_CREATE_F_* to control the creation of the flow graph.
     1310 * @param   fFlagsDisasm        Combination of DBGF_DISAS_FLAGS_* controlling the style of the disassembled
     1311 *                              instructions.
    7141312 * @param   phFlow              Where to store the handle to the control flow graph on success.
    7151313 */
    7161314VMMR3DECL(int) DBGFR3FlowCreate(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddressStart, uint32_t cbDisasmMax,
    717                                uint32_t fFlags, PDBGFFLOW phFlow)
     1315                                uint32_t fFlagsFlow, uint32_t fFlagsDisasm, PDBGFFLOW phFlow)
    7181316{
    7191317    UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
     
    7221320    AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
    7231321    AssertPtrReturn(pAddressStart, VERR_INVALID_POINTER);
    724     AssertReturn(!(fFlags & ~DBGF_DISAS_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
    725     AssertReturn((fFlags & DBGF_DISAS_FLAGS_MODE_MASK) <= DBGF_DISAS_FLAGS_64BIT_MODE, VERR_INVALID_PARAMETER);
     1322    AssertReturn(!(fFlagsDisasm & ~DBGF_DISAS_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
     1323    AssertReturn((fFlagsDisasm & DBGF_DISAS_FLAGS_MODE_MASK) <= DBGF_DISAS_FLAGS_64BIT_MODE, VERR_INVALID_PARAMETER);
    7261324
    7271325    /* Create the control flow graph container. */
     
    7331331        if (RT_SUCCESS(rc))
    7341332        {
    735             pThis->cRefs   = 1;
    736             pThis->cRefsBb = 0;
    737             pThis->cBbs    = 0;
     1333            pThis->cRefs       = 1;
     1334            pThis->cRefsBb     = 0;
     1335            pThis->cBbs        = 0;
     1336            pThis->cBranchTbls = 0;
     1337            pThis->fFlags      = fFlagsFlow;
    7381338            RTListInit(&pThis->LstFlowBb);
     1339            RTListInit(&pThis->LstBranchTbl);
    7391340            /* Create the entry basic block and start the work. */
    7401341
    741             PDBGFFLOWBBINT pFlowBb = dbgfR3FlowBbCreate(pThis, pAddressStart, 10);
     1342            PDBGFFLOWBBINT pFlowBb = dbgfR3FlowBbCreate(pThis, pAddressStart, DBGF_FLOW_BB_F_ENTRY, 10);
    7421343            if (RT_LIKELY(pFlowBb))
    7431344            {
    744                 pFlowBb->fFlags |= DBGF_FLOW_BB_F_ENTRY;
    7451345                dbgfR3FlowLink(pThis, pFlowBb);
    746                 rc = dbgfR3FlowPopulate(pUVM, idCpu, pThis, pAddressStart, cbDisasmMax, fFlags);
     1346                rc = dbgfR3FlowPopulate(pUVM, idCpu, pThis, pAddressStart, cbDisasmMax, fFlagsDisasm);
    7471347                if (RT_SUCCESS(rc))
    7481348                {
     
    8361436 * @returns VBox status code.
    8371437 * @retval  VERR_NOT_FOUND if there is no basic block intersecting with the address.
    838  * @param   hFlow                The control flow graph handle.
     1438 * @param   hFlow               The control flow graph handle.
    8391439 * @param   pAddr               The address to look for.
    840  * @param   phFlowBb             Where to store the basic block handle on success.
     1440 * @param   phFlowBb            Where to store the basic block handle on success.
    8411441 */
    8421442VMMR3DECL(int) DBGFR3FlowQueryBbByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBB phFlowBb)
     
    8441444    PDBGFFLOWINT pThis = hFlow;
    8451445    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     1446    AssertPtrReturn(pAddr, VERR_INVALID_POINTER);
    8461447    AssertPtrReturn(phFlowBb, VERR_INVALID_POINTER);
    8471448
     
    8491450    RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb)
    8501451    {
    851         if (dbgfR3FlowBbAddrIntersect(pFlowBb, pAddr))
     1452        if (dbgfR3FlowAddrIntersect(pFlowBb, pAddr))
    8521453        {
    8531454            DBGFR3FlowBbRetain(pFlowBb);
     
    8551456            return VINF_SUCCESS;
    8561457        }
     1458    }
     1459
     1460    return VERR_NOT_FOUND;
     1461}
     1462
     1463
     1464/**
     1465 * Queries a branch table in the given control flow graph by the given address.
     1466 *
     1467 * @returns VBox status code.
     1468 * @retval  VERR_NOT_FOUND if there is no branch table with the given address.
     1469 * @param   hFlow               The control flow graph handle.
     1470 * @param   pAddr               The address of the branch table.
     1471 * @param   phFlowBranchTbl     Where to store the handle to branch table on success.
     1472 *
     1473 * @note Call DBGFR3FlowBranchTblRelease() when the handle is not required anymore.
     1474 */
     1475VMMR3DECL(int) DBGFR3FlowQueryBranchTblByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBRANCHTBL phFlowBranchTbl)
     1476{
     1477    PDBGFFLOWINT pThis = hFlow;
     1478    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     1479    AssertPtrReturn(pAddr, VERR_INVALID_POINTER);
     1480    AssertPtrReturn(phFlowBranchTbl, VERR_INVALID_POINTER);
     1481
     1482    PDBGFFLOWBRANCHTBLINT pBranchTbl = dbgfR3FlowBranchTblFindByAddr(pThis, pAddr);
     1483    if (pBranchTbl)
     1484    {
     1485        DBGFR3FlowBranchTblRetain(pBranchTbl);
     1486        *phFlowBranchTbl = pBranchTbl;
     1487        return VINF_SUCCESS;
    8571488    }
    8581489
     
    10421673
    10431674/**
     1675 * Queries the branch table used if the given basic block ends with an indirect branch
     1676 * and has a branch table referenced.
     1677 *
     1678 * @returns VBox status code.
     1679 * @param   hFlowBb              The basic block handle.
     1680 * @param   phBranchTbl          Where to store the branch table handle on success.
     1681 *
     1682 * @note Release the branch table reference with DBGFR3FlowBranchTblRelease() when not required
     1683 *       anymore.
     1684 */
     1685VMMR3DECL(int) DBGFR3FlowBbQueryBranchTbl(DBGFFLOWBB hFlowBb, PDBGFFLOWBRANCHTBL phBranchTbl)
     1686{
     1687    PDBGFFLOWBBINT pFlowBb = hFlowBb;
     1688    AssertPtrReturn(pFlowBb, VERR_INVALID_HANDLE);
     1689    AssertReturn(pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP, VERR_INVALID_STATE);
     1690    AssertPtrReturn(pFlowBb->pFlowBranchTbl, VERR_INVALID_STATE);
     1691    AssertPtrReturn(phBranchTbl, VERR_INVALID_POINTER);
     1692
     1693    DBGFR3FlowBranchTblRetain(pFlowBb->pFlowBranchTbl);
     1694    *phBranchTbl = pFlowBb->pFlowBranchTbl;
     1695    return VINF_SUCCESS;
     1696}
     1697
     1698
     1699/**
    10441700 * Returns the error status and message if the given basic block has an error.
    10451701 *
     
    11501806            DBGFADDRESS AddrStart = pFlowBb->AddrEnd;
    11511807            DBGFR3AddrAdd(&AddrStart, 1);
    1152             if (dbgfR3FlowBbAddrEqual(&pFlowBbCur->AddrStart, &AddrStart))
     1808            if (dbgfR3FlowAddrEqual(&pFlowBbCur->AddrStart, &AddrStart))
    11531809                cRefsBb++;
    11541810        }
     
    11561812        if (   (   pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_JMP
    11571813                || pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_COND)
    1158             && dbgfR3FlowBbAddrEqual(&pFlowBbCur->AddrStart, &pFlowBb->AddrTarget))
     1814            && dbgfR3FlowAddrEqual(&pFlowBbCur->AddrStart, &pFlowBb->AddrTarget))
    11591815            cRefsBb++;
    11601816    }
     
    11681824 * @returns VBox status code.
    11691825 * @retval  VERR_BUFFER_OVERFLOW if the array can't hold all the basic blocks.
    1170  * @param   hFlowBb              The basic block handle.
    1171  * @param   paFlowBbRef          Pointer to the array containing the referencing basic block handles on success.
     1826 * @param   hFlowBb             The basic block handle.
     1827 * @param   paFlowBbRef         Pointer to the array containing the referencing basic block handles on success.
    11721828 * @param   cRef                Number of entries in the given array.
    11731829 */
     
    11761832    RT_NOREF3(hFlowBb, paFlowBbRef, cRef);
    11771833    return VERR_NOT_IMPLEMENTED;
     1834}
     1835
     1836
     1837/**
     1838 * Retains a reference for the given control flow graph branch table.
     1839 *
     1840 * @returns new reference count.
     1841 * @param   hFlowBranchTbl      The branch table handle.
     1842 */
     1843VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRetain(DBGFFLOWBRANCHTBL hFlowBranchTbl)
     1844{
     1845    PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
     1846    AssertPtrReturn(pFlowBranchTbl, UINT32_MAX);
     1847
     1848    uint32_t cRefs = ASMAtomicIncU32(&pFlowBranchTbl->cRefs);
     1849    AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pFlowBranchTbl));
     1850    return cRefs;
     1851}
     1852
     1853
     1854/**
     1855 * Releases a given branch table handle.
     1856 *
     1857 * @returns the new reference count of the given branch table, on 0 it is destroyed.
     1858 * @param   hFlowBranchTbl      The branch table handle.
     1859 */
     1860VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRelease(DBGFFLOWBRANCHTBL hFlowBranchTbl)
     1861{
     1862    PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
     1863    if (!pFlowBranchTbl)
     1864        return 0;
     1865    AssertPtrReturn(pFlowBranchTbl, UINT32_MAX);
     1866
     1867    uint32_t cRefs = ASMAtomicDecU32(&pFlowBranchTbl->cRefs);
     1868    AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pFlowBranchTbl));
     1869    if (cRefs == 0)
     1870        dbgfR3FlowBranchTblDestroy(pFlowBranchTbl);
     1871    return cRefs;
     1872}
     1873
     1874
     1875/**
     1876 * Return the number of slots the branch table has.
     1877 *
     1878 * @returns Number of slots in the branch table.
     1879 * @param   hFlowBranchTbl      The branch table handle.
     1880 */
     1881VMMR3DECL(uint32_t) DBGFR3FlowBranchTblGetSlots(DBGFFLOWBRANCHTBL hFlowBranchTbl)
     1882{
     1883    PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
     1884    AssertPtrReturn(pFlowBranchTbl, 0);
     1885
     1886    return pFlowBranchTbl->cSlots;
     1887}
     1888
     1889
     1890/**
     1891 * Returns the start address of the branch table in the guest.
     1892 *
     1893 * @returns Pointer to start address of the branch table (pAddrStart).
     1894 * @param   hFlowBranchTbl      The branch table handle.
     1895 * @param   pAddrStart          Where to store the branch table address.
     1896 */
     1897VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetStartAddress(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS pAddrStart)
     1898{
     1899    PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
     1900    AssertPtrReturn(pFlowBranchTbl, NULL);
     1901    AssertPtrReturn(pAddrStart, NULL);
     1902
     1903    *pAddrStart = pFlowBranchTbl->AddrStart;
     1904    return pAddrStart;
     1905}
     1906
     1907
     1908/**
     1909 * Query all addresses contained in the given branch table.
     1910 *
     1911 * @returns VBox status code.
     1912 * @retval  VERR_BUFFER_OVERFLOW if there is not enough space in the array to hold all addresses.
     1913 * @param   hFlowBranchTbl      The branch table handle.
     1914 * @param   paAddrs             Where to store the addresses on success.
     1915 * @param   cAddrs              Number of entries the array can hold.
     1916 */
     1917VMMR3DECL(int) DBGFR3FlowBranchTblQueryAddresses(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS paAddrs, uint32_t cAddrs)
     1918{
     1919    PDBGFFLOWBRANCHTBLINT pFlowBranchTbl = hFlowBranchTbl;
     1920    AssertPtrReturn(pFlowBranchTbl, VERR_INVALID_HANDLE);
     1921    AssertPtrReturn(paAddrs, VERR_INVALID_POINTER);
     1922    AssertReturn(cAddrs > 0, VERR_INVALID_PARAMETER);
     1923
     1924    if (cAddrs < pFlowBranchTbl->cSlots)
     1925        return VERR_BUFFER_OVERFLOW;
     1926
     1927    memcpy(paAddrs, &pFlowBranchTbl->aAddresses[0], pFlowBranchTbl->cSlots * sizeof(DBGFADDRESS));
     1928    return VINF_SUCCESS;
    11781929}
    11791930
     
    11881939    PDBGFFLOWBBINT pFlowBb2 = *(PDBGFFLOWBBINT *)pvElement2;
    11891940
    1190     if (dbgfR3FlowBbAddrEqual(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
     1941    if (dbgfR3FlowAddrEqual(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
    11911942        return 0;
    11921943
    11931944    if (*penmOrder == DBGFFLOWITORDER_BY_ADDR_LOWEST_FIRST)
    11941945    {
    1195         if (dbgfR3FlowBbAddrLower(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
     1946        if (dbgfR3FlowAddrLower(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
    11961947            return -1;
    11971948        else
     
    12001951    else
    12011952    {
    1202         if (dbgfR3FlowBbAddrLower(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
     1953        if (dbgfR3FlowAddrLower(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))
    12031954            return 1;
    12041955        else
  • trunk/src/VBox/VMM/VMMR3/VMMR3.def

    r64582 r64586  
    135135    DBGFR3FlowQueryStartBb
    136136    DBGFR3FlowQueryBbByAddress
     137    DBGFR3FlowQueryBranchTblByAddress
    137138    DBGFR3FlowGetBbCount
     139    DBGFR3FlowGetBranchTblCount
    138140    DBGFR3FlowBbRetain
    139141    DBGFR3FlowBbRelease
     
    145147    DBGFR3FlowBbGetInstrCount
    146148    DBGFR3FlowBbGetFlags
     149    DBGFR3FlowBbQueryBranchTbl
    147150    DBGFR3FlowBbQueryError
    148151    DBGFR3FlowBbQueryInstr
     
    150153    DBGFR3FlowBbGetRefBbCount
    151154    DBGFR3FlowBbGetRefBb
     155    DBGFR3FlowBranchTblRetain
     156    DBGFR3FlowBranchTblRelease
     157    DBGFR3FlowBranchTblGetSlots
     158    DBGFR3FlowBranchTblGetStartAddress
     159    DBGFR3FlowBranchTblQueryAddresses
    152160    DBGFR3FlowItCreate
    153161    DBGFR3FlowItDestroy
Note: See TracChangeset for help on using the changeset viewer.

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