VirtualBox

Changeset 88366 in vbox for trunk


Ignore:
Timestamp:
Apr 5, 2021 7:08:37 AM (4 years ago)
Author:
vboxsync
Message:

VMM/DBGFR3Flow: Add ability to put call instructions into separate basic blocks which will aid the flow tracing code to instrument calls to other functions more easily

Location:
trunk
Files:
3 edited

Legend:

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

    r87776 r88366  
    29182918 * @{ */
    29192919/** The basic block is the entry into the owning control flow graph. */
    2920 #define DBGF_FLOW_BB_F_ENTRY             RT_BIT_32(0)
     2920#define DBGF_FLOW_BB_F_ENTRY                                RT_BIT_32(0)
    29212921/** The basic block was not populated because the limit was reached. */
    2922 #define DBGF_FLOW_BB_F_EMPTY             RT_BIT_32(1)
     2922#define DBGF_FLOW_BB_F_EMPTY                                RT_BIT_32(1)
    29232923/** The basic block is not complete because an error happened during disassembly. */
    2924 #define DBGF_FLOW_BB_F_INCOMPLETE_ERR    RT_BIT_32(2)
     2924#define DBGF_FLOW_BB_F_INCOMPLETE_ERR                       RT_BIT_32(2)
    29252925/** The basic block is reached through a branch table. */
    2926 #define DBGF_FLOW_BB_F_BRANCH_TABLE      RT_BIT_32(3)
     2926#define DBGF_FLOW_BB_F_BRANCH_TABLE                         RT_BIT_32(3)
     2927/** The basic block consists only of a single call instruction because
     2928 * DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB was given. */
     2929#define DBGF_FLOW_BB_F_CALL_INSN                            RT_BIT_32(4)
     2930/** The branch target of the call instruction could be deduced and can be queried with
     2931 * DBGFR3FlowBbGetBranchAddress(). May only be available when DBGF_FLOW_BB_F_CALL_INSN
     2932 * is set. */
     2933#define DBGF_FLOW_BB_F_CALL_INSN_TARGET_KNOWN               RT_BIT_32(5)
    29272934/** @} */
    29282935
     
    29302937 * @{ */
    29312938/** Default options. */
    2932 #define DBGF_FLOW_CREATE_F_DEFAULT                       0
     2939#define DBGF_FLOW_CREATE_F_DEFAULT                          0
    29332940/** Tries to resolve indirect branches, useful for code using
    29342941 * jump tables generated for large switch statements by some compilers. */
    2935 #define DBGF_FLOW_CREATE_F_TRY_RESOLVE_INDIRECT_BRANCHES RT_BIT_32(0)
     2942#define DBGF_FLOW_CREATE_F_TRY_RESOLVE_INDIRECT_BRANCHES    RT_BIT_32(0)
     2943/** Call instructions are placed in a separate basic block. */
     2944#define DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB            RT_BIT_32(1)
    29362945/** @} */
    29372946
     
    29943003VMMR3DECL(uint32_t)          DBGFR3FlowGetBbCount(DBGFFLOW hFlow);
    29953004VMMR3DECL(uint32_t)          DBGFR3FlowGetBranchTblCount(DBGFFLOW hFlow);
     3005VMMR3DECL(uint32_t)          DBGFR3FlowGetCallInsnCount(DBGFFLOW hFlow);
    29963006
    29973007VMMR3DECL(uint32_t)          DBGFR3FlowBbRetain(DBGFFLOWBB hFlowBb);
  • trunk/src/VBox/VMM/VMMR3/DBGFR3Flow.cpp

    r82968 r88366  
    6868    /** Number of branch tables in this control flow graph. */
    6969    uint32_t                cBranchTbls;
     70    /** Number of call instructions in this control flow graph. */
     71    uint32_t                cCallInsns;
    7072    /** The lowest addres of a basic block. */
    7173    DBGFADDRESS             AddrLowest;
     
    11481150        }
    11491151
    1150         pFlowBb->fFlags &= ~DBGF_FLOW_BB_F_EMPTY;
    1151 
    11521152        rc = dbgfR3DisasInstrStateEx(pUVM, idCpu, &AddrDisasm, fFlags,
    11531153                                     &szOutput[0], sizeof(szOutput), &DisState);
    11541154        if (RT_SUCCESS(rc))
    11551155        {
     1156            if (   pThis->fFlags & DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB
     1157                && DisState.pCurInstr->uOpcode == OP_CALL
     1158                && !(pFlowBb->fFlags & DBGF_FLOW_BB_F_EMPTY))
     1159            {
     1160                /*
     1161                 * If the basic block is not empty, the basic block is terminated and the successor is added
     1162                 * which will contain the call instruction.
     1163                 */
     1164                pFlowBb->AddrTarget = AddrDisasm;
     1165                pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND;
     1166                rc = dbgfR3FlowBbSuccessorAdd(pThis, &AddrDisasm,
     1167                                              (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
     1168                                              pFlowBb->pFlowBranchTbl);
     1169                if (RT_FAILURE(rc))
     1170                    dbgfR3FlowBbSetError(pFlowBb, rc, "Adding successor blocks failed with %Rrc", rc);
     1171                break;
     1172            }
     1173
     1174            pFlowBb->fFlags &= ~DBGF_FLOW_BB_F_EMPTY;
    11561175            cbDisasmLeft -= DisState.cbInstr;
    11571176
     
    11921211                {
    11931212                    uint16_t uOpc = DisState.pCurInstr->uOpcode;
     1213
     1214                    if (uOpc == OP_CALL)
     1215                        pThis->cCallInsns++;
    11941216
    11951217                    if (   uOpc == OP_RETN || uOpc == OP_RETF || uOpc == OP_IRET
     
    12631285                        }
    12641286                    }
     1287                    else if (pThis->fFlags & DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB)
     1288                    {
     1289                        pFlowBb->enmEndType = DBGFFLOWBBENDTYPE_UNCOND;
     1290                        pFlowBb->fFlags    |= DBGF_FLOW_BB_F_CALL_INSN;
     1291
     1292                        /* Add new basic block coming after the call instruction. */
     1293                        rc = dbgfR3FlowBbSuccessorAdd(pThis, &AddrDisasm,
     1294                                                      (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE),
     1295                                                      pFlowBb->pFlowBranchTbl);
     1296                        if (   RT_SUCCESS(rc)
     1297                            && !dbgfR3FlowBranchTargetIsIndirect(&DisState.Param1))
     1298                        {
     1299                            /* Resolve the branch target. */
     1300                            rc = dbgfR3FlowQueryDirectBranchTarget(pUVM, idCpu, &DisState.Param1, &pInstr->AddrInstr, pInstr->cbInstr,
     1301                                                                   RT_BOOL(DisState.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW),
     1302                                                                   &pFlowBb->AddrTarget);
     1303                            if (RT_SUCCESS(rc))
     1304                                pFlowBb->fFlags |= DBGF_FLOW_BB_F_CALL_INSN_TARGET_KNOWN;
     1305                        }
     1306                    }
    12651307
    12661308                    if (RT_FAILURE(rc))
     
    12681310
    12691311                    /* Quit disassembling. */
    1270                     if (   uOpc != OP_CALL
     1312                    if (   (   uOpc != OP_CALL
     1313                            || (pThis->fFlags & DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB))
    12711314                        || RT_FAILURE(rc))
    12721315                        break;
     
    12901333 * @param   idCpu               CPU id for disassembling.
    12911334 * @param   pThis               The control flow graph to populate.
    1292  * @param   pAddrStart          The start address to disassemble at.
    12931335 * @param   cbDisasmMax         The maximum amount to disassemble.
    12941336 * @param   fFlags              Combination of DBGF_DISAS_FLAGS_*.
    12951337 */
    1296 static int dbgfR3FlowPopulate(PUVM pUVM, VMCPUID idCpu, PDBGFFLOWINT pThis, PDBGFADDRESS pAddrStart,
     1338static int dbgfR3FlowPopulate(PUVM pUVM, VMCPUID idCpu, PDBGFFLOWINT pThis,
    12971339                             uint32_t cbDisasmMax, uint32_t fFlags)
    12981340{
    12991341    int rc = VINF_SUCCESS;
    13001342    PDBGFFLOWBBINT pFlowBb = dbgfR3FlowGetUnpopulatedBb(pThis);
    1301     DBGFADDRESS AddrEnd = *pAddrStart;
    1302     DBGFR3AddrAdd(&AddrEnd, cbDisasmMax);
    13031343
    13041344    while (VALID_PTR(pFlowBb))
     
    13501390            pThis->cBbs        = 0;
    13511391            pThis->cBranchTbls = 0;
     1392            pThis->cCallInsns  = 0;
    13521393            pThis->fFlags      = fFlagsFlow;
    13531394            RTListInit(&pThis->LstFlowBb);
     
    13591400            {
    13601401                dbgfR3FlowLink(pThis, pFlowBb);
    1361                 rc = dbgfR3FlowPopulate(pUVM, idCpu, pThis, pAddressStart, cbDisasmMax, fFlagsDisasm);
     1402                rc = dbgfR3FlowPopulate(pUVM, idCpu, pThis, cbDisasmMax, fFlagsDisasm);
    13621403                if (RT_SUCCESS(rc))
    13631404                {
     
    15381579
    15391580/**
     1581 * Returns the number of call instructions encountered in the given
     1582 * control flow graph.
     1583 *
     1584 * @returns Number of call instructions.
     1585 * @param   hFlow                The control flow graph handle.
     1586 */
     1587VMMR3DECL(uint32_t) DBGFR3FlowGetCallInsnCount(DBGFFLOW hFlow)
     1588{
     1589    PDBGFFLOWINT pThis = hFlow;
     1590    AssertPtrReturn(pThis, 0);
     1591
     1592    return pThis->cCallInsns;
     1593}
     1594
     1595
     1596/**
    15401597 * Retains the basic block handle.
    15411598 *
     
    16131670 * @param   pAddrTarget         Where to store the branch address of the basic block.
    16141671 *
    1615  * @note This is only valid for unconditional or conditional branches and will assert
    1616  *       for every other basic block type.
     1672 * @note This is only valid for unconditional or conditional branches, or for a basic block
     1673 *       containing only a call instruction when DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB was given
     1674 *       during creation and the branch target could be deduced as indicated by the DBGF_FLOW_BB_F_CALL_INSN_TARGET_KNOWN
     1675 *       flag for the basic block. This method will assert for every other basic block type.
    16171676 * @note For indirect unconditional branches using a branch table this will return the start address
    16181677 *       of the branch table.
     
    16251684    AssertReturn(   pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_JMP
    16261685                 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_COND
    1627                  || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP,
     1686                 || pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP
     1687                 || (   pFlowBb->enmEndType == DBGFFLOWBBENDTYPE_UNCOND
     1688                     && (pFlowBb->fFlags & DBGF_FLOW_BB_F_CALL_INSN_TARGET_KNOWN)),
    16281689                 NULL);
    16291690
  • trunk/src/VBox/VMM/VMMR3/VMMR3.def

    r87787 r88366  
    163163    DBGFR3FlowGetBbCount
    164164    DBGFR3FlowGetBranchTblCount
     165    DBGFR3FlowGetCallInsnCount
    165166    DBGFR3FlowBbRetain
    166167    DBGFR3FlowBbRelease
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