- Timestamp:
- Nov 6, 2016 1:56:36 PM (8 years ago)
- Location:
- trunk
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/vmm/dbgf.h
r64559 r64586 2500 2500 /** Pointer to a DBGF control flow graph basic block handle. */ 2501 2501 typedef DBGFFLOWBB *PDBGFFLOWBB; 2502 /** A DBGF control flow graph branch table handle. */ 2503 typedef struct DBGFFLOWBRANCHTBLINT *DBGFFLOWBRANCHTBL; 2504 /** Pointer to a DBGF flow control graph branch table handle. */ 2505 typedef DBGFFLOWBRANCHTBL *PDBGFFLOWBRANCHTBL; 2502 2506 /** A DBGF control flow graph iterator. */ 2503 2507 typedef struct DBGFFLOWITINT *DBGFFLOWIT; … … 2513 2517 /** The basic block is not complete because an error happened during disassembly. */ 2514 2518 #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) 2515 2530 /** @} */ 2516 2531 … … 2532 2547 * basic blocks. - 1 successor. */ 2533 2548 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. */ 2535 2550 DBGFFLOWBBENDTYPE_UNCOND_JMP, 2551 /** Unconditional control flow change because of an indirect branch - n successors. */ 2552 DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP, 2536 2553 /** Conditional control flow change - 2 successors. */ 2537 2554 DBGFFLOWBBENDTYPE_COND, … … 2558 2575 DBGFFLOWITORDER_32BIT_HACK = 0x7fffffff 2559 2576 } DBGFFLOWITORDER; 2560 /** P Ointer to a iteration order enum. */2577 /** Pointer to a iteration order enum. */ 2561 2578 typedef DBGFFLOWITORDER *PDBGFFLOWITORDER; 2562 2579 2563 2580 2564 2581 VMMR3DECL(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); 2566 2583 VMMR3DECL(uint32_t) DBGFR3FlowRetain(DBGFFLOW hFlow); 2567 2584 VMMR3DECL(uint32_t) DBGFR3FlowRelease(DBGFFLOW hFlow); 2568 2585 VMMR3DECL(int) DBGFR3FlowQueryStartBb(DBGFFLOW hFlow, PDBGFFLOWBB phFlowBb); 2569 2586 VMMR3DECL(int) DBGFR3FlowQueryBbByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBB phFlowBb); 2587 VMMR3DECL(int) DBGFR3FlowQueryBranchTblByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBRANCHTBL phFlowBranchTbl); 2570 2588 VMMR3DECL(uint32_t) DBGFR3FlowGetBbCount(DBGFFLOW hFlow); 2589 VMMR3DECL(uint32_t) DBGFR3FlowGetBranchTblCount(DBGFFLOW hFlow); 2590 2571 2591 VMMR3DECL(uint32_t) DBGFR3FlowBbRetain(DBGFFLOWBB hFlowBb); 2572 2592 VMMR3DECL(uint32_t) DBGFR3FlowBbRelease(DBGFFLOWBB hFlowBb); … … 2578 2598 VMMR3DECL(uint32_t) DBGFR3FlowBbGetInstrCount(DBGFFLOWBB hFlowBb); 2579 2599 VMMR3DECL(uint32_t) DBGFR3FlowBbGetFlags(DBGFFLOWBB hFlowBb); 2600 VMMR3DECL(int) DBGFR3FlowBbQueryBranchTbl(DBGFFLOWBB hFlowBb, PDBGFFLOWBRANCHTBL phBranchTbl); 2580 2601 VMMR3DECL(int) DBGFR3FlowBbQueryError(DBGFFLOWBB hFlowBb, const char **ppszErr); 2581 2602 VMMR3DECL(int) DBGFR3FlowBbQueryInstr(DBGFFLOWBB hFlowBb, uint32_t idxInstr, PDBGFADDRESS pAddrInstr, … … 2583 2604 VMMR3DECL(int) DBGFR3FlowBbQuerySuccessors(DBGFFLOWBB hFlowBb, PDBGFFLOWBB phFlowBbFollow, 2584 2605 PDBGFFLOWBB phFlowBbTarget); 2606 2585 2607 VMMR3DECL(uint32_t) DBGFR3FlowBbGetRefBbCount(DBGFFLOWBB hFlowBb); 2586 2608 VMMR3DECL(int) DBGFR3FlowBbGetRefBb(DBGFFLOWBB hFlowBb, PDBGFFLOWBB pahFlowBbRef, uint32_t cRef); 2609 2610 VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRetain(DBGFFLOWBRANCHTBL hFlowBranchTbl); 2611 VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRelease(DBGFFLOWBRANCHTBL hFlowBranchTbl); 2612 VMMR3DECL(uint32_t) DBGFR3FlowBranchTblGetSlots(DBGFFLOWBRANCHTBL hFlowBranchTbl); 2613 VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetStartAddress(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS pAddrStart); 2614 VMMR3DECL(int) DBGFR3FlowBranchTblQueryAddresses(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS paAddrs, uint32_t cAddrs); 2615 2587 2616 VMMR3DECL(int) DBGFR3FlowItCreate(DBGFFLOW hFlow, DBGFFLOWITORDER enmOrder, PDBGFFLOWIT phFlowIt); 2588 2617 VMMR3DECL(void) DBGFR3FlowItDestroy(DBGFFLOWIT hFlowIt); -
trunk/src/VBox/Debugger/DBGCEmulateCodeView.cpp
r64577 r64586 1636 1636 cchRightExtra++; 1637 1637 break; 1638 case DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP: 1638 1639 default: 1639 1640 AssertFailed(); … … 1666 1667 case DBGFFLOWBBENDTYPE_LAST_DISASSEMBLED: 1667 1668 case DBGFFLOWBBENDTYPE_UNCOND_JMP: 1669 case DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP: 1668 1670 break; 1669 1671 case DBGFFLOWBBENDTYPE_UNCOND: … … 1778 1780 break; 1779 1781 } 1782 case DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP: 1780 1783 default: 1781 1784 AssertFailed(); … … 1942 1945 1943 1946 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); 1945 1949 if (RT_SUCCESS(rc)) 1946 1950 { -
trunk/src/VBox/Debugger/testcase/tstDBGCStubs.cpp
r64559 r64586 382 382 383 383 VMMR3DECL(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) 385 385 { 386 386 return VERR_INTERNAL_ERROR; … … 402 402 return VERR_INTERNAL_ERROR; 403 403 } 404 VMMR3DECL(int) DBGFR3FlowQueryBranchTblByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBRANCHTBL phFlowBranchTbl) 405 { 406 return VERR_INTERNAL_ERROR; 407 } 404 408 VMMR3DECL(uint32_t) DBGFR3FlowGetBbCount(DBGFFLOW hFlow) 405 409 { 406 410 return 0; 407 411 } 412 VMMR3DECL(uint32_t) DBGFR3FlowGetBranchTblCount(DBGFFLOW hFlow) 413 { 414 return 0; 415 } 408 416 VMMR3DECL(uint32_t) DBGFR3FlowBbRetain(DBGFFLOWBB hFlowBb) 409 417 { … … 441 449 { 442 450 return 0; 451 } 452 VMMR3DECL(int) DBGFR3FlowBbQueryBranchTbl(DBGFFLOWBB hFlowBb, PDBGFFLOWBRANCHTBL phBranchTbl) 453 { 454 return VERR_INTERNAL_ERROR; 443 455 } 444 456 VMMR3DECL(int) DBGFR3FlowBbQueryError(DBGFFLOWBB hFlowBb, const char **ppszErr) … … 461 473 } 462 474 VMMR3DECL(int) DBGFR3FlowBbGetRefBb(DBGFFLOWBB hFlowBb, PDBGFFLOWBB pahFlowBbRef, uint32_t cRef) 475 { 476 return VERR_INTERNAL_ERROR; 477 } 478 VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRetain(DBGFFLOWBRANCHTBL hFlowBranchTbl) 479 { 480 return 0; 481 } 482 VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRelease(DBGFFLOWBRANCHTBL hFlowBranchTbl) 483 { 484 return 0; 485 } 486 VMMR3DECL(uint32_t) DBGFR3FlowBranchTblGetSlots(DBGFFLOWBRANCHTBL hFlowBranchTbl) 487 { 488 return 0; 489 } 490 VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetStartAddress(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS pAddrStart) 491 { 492 return NULL; 493 } 494 VMMR3DECL(int) DBGFR3FlowBranchTblQueryAddresses(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS paAddrs, uint32_t cAddrs) 463 495 { 464 496 return VERR_INTERNAL_ERROR; -
trunk/src/VBox/VMM/VMMR3/DBGFR3Flow.cpp
r64563 r64586 63 63 /** Internal reference counter for basic blocks. */ 64 64 uint32_t volatile cRefsBb; 65 /** Flags during creation. */ 66 uint32_t fFlags; 65 67 /** List of all basic blocks. */ 66 68 RTLISTANCHOR LstFlowBb; 69 /** List of identified branch tables. */ 70 RTLISTANCHOR LstBranchTbl; 67 71 /** Number of basic blocks in this control flow graph. */ 68 72 uint32_t cBbs; 73 /** Number of branch tables in this control flow graph. */ 74 uint32_t cBranchTbls; 69 75 /** The lowest addres of a basic block. */ 70 76 DBGFADDRESS AddrLowest; … … 91 97 /** Pointer to an instruction record. */ 92 98 typedef DBGFFLOWBBINSTR *PDBGFFLOWBBINSTR; 99 100 101 /** 102 * A branch table identified by the graph processor. 103 */ 104 typedef 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. */ 122 typedef DBGFFLOWBRANCHTBLINT *PDBGFFLOWBRANCHTBLINT; 123 93 124 94 125 /** … … 115 146 * if we can't infer the jump target (jmp *eax for example). */ 116 147 DBGFADDRESS AddrTarget; 148 /** The indirect branch table identified for indirect branches. */ 149 PDBGFFLOWBRANCHTBLINT pFlowBranchTbl; 117 150 /** Last status error code if DBGF_FLOW_BB_F_INCOMPLETE_ERR is set. */ 118 151 int rcError; … … 131 164 typedef DBGFFLOWBBINT *PDBGFFLOWBBINT; 132 165 166 133 167 /** 134 168 * Control flow graph iterator state. … … 152 186 153 187 static uint32_t dbgfR3FlowBbReleaseInt(PDBGFFLOWBBINT pFlowBb, bool fMayDestroyFlow); 188 static 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 */ 198 static 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 */ 212 static 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 */ 226 static 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 */ 241 static 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 154 256 155 257 /** … … 159 261 * @param pThis The control flow graph. 160 262 * @param pAddrStart The start of the basic block. 263 * @param fFlowBbFlags Additional flags for this bascic block. 161 264 * @param cInstrMax Maximum number of instructions this block can hold initially. 162 265 */ 163 static PDBGFFLOWBBINT dbgfR3FlowBbCreate(PDBGFFLOWINT pThis, PDBGFADDRESS pAddrStart, uint32_t cInstrMax) 266 static PDBGFFLOWBBINT dbgfR3FlowBbCreate(PDBGFFLOWINT pThis, PDBGFADDRESS pAddrStart, uint32_t fFlowBbFlags, 267 uint32_t cInstrMax) 164 268 { 165 269 PDBGFFLOWBBINT pFlowBb = (PDBGFFLOWBBINT)RTMemAllocZ(RT_OFFSETOF(DBGFFLOWBBINT, aInstr[cInstrMax])); … … 167 271 { 168 272 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; 179 284 ASMAtomicIncU32(&pThis->cRefsBb); 180 285 } 181 286 182 287 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 */ 300 static 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; 183 314 } 184 315 … … 203 334 if (!pThis->cRefsBb) 204 335 { 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 205 344 RTStrCacheDestroy(pThis->hStrCacheInstr); 206 345 RTMemFree(pThis); … … 234 373 235 374 /** 375 * Destroys a given branch table. 376 * 377 * @returns nothing. 378 * @param pFlowBranchTbl The flow branch table to destroy. 379 */ 380 static void dbgfR3FlowBranchTblDestroy(PDBGFFLOWBRANCHTBLINT pFlowBranchTbl) 381 { 382 RTListNodeRemove(&pFlowBranchTbl->NdBranchTbl); 383 RTMemFree(pFlowBranchTbl); 384 } 385 386 387 /** 236 388 * Internal basic block release worker. 237 389 * … … 257 409 * @returns nothing. 258 410 * @param pThis The control flow graph to link into. 259 * @param pFlowBb 411 * @param pFlowBb The basic block to link. 260 412 */ 261 413 DECLINLINE(void) dbgfR3FlowLink(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb) … … 267 419 268 420 /** 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 */ 427 DECLINLINE(void) dbgfR3FlowBranchTblLink(PDBGFFLOWINT pThis, PDBGFFLOWBRANCHTBLINT pBranchTbl) 428 { 429 RTListAppend(&pThis->LstBranchTbl, &pBranchTbl->NdBranchTbl); 430 pThis->cBranchTbls++; 431 } 432 433 434 /** 269 435 * Returns the first unpopulated basic block of the given control flow graph. 270 436 * … … 286 452 287 453 /** 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 */ 460 DECLINLINE(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 */ 482 static 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 */ 504 static 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 */ 524 static 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 */ 600 static 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 */ 634 DECLINLINE(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 289 648 * and instruction parameter. 290 649 * … … 292 651 * @param pUVM The usermode VM handle. 293 652 * @param idCpu CPU id for resolving the address. 294 * @param pDisParam The par meter from the disassembler.653 * @param pDisParam The parameter from the disassembler. 295 654 * @param pAddrInstr The instruction address. 296 655 * @param cbInstr Size of instruction in bytes. … … 298 657 * @param pAddrJmpTarget Where to store the address to the jump target on success. 299 658 */ 300 static int dbgfR3FlowQuery JmpTarget(PUVM pUVM, VMCPUID idCpu, PDISOPPARAM pDisParam, PDBGFADDRESS pAddrInstr,301 uint32_t cbInstr, bool fRelJmp, PDBGFADDRESS pAddrJmpTarget)659 static int dbgfR3FlowQueryDirectBranchTarget(PUVM pUVM, VMCPUID idCpu, PDISOPPARAM pDisParam, PDBGFADDRESS pAddrInstr, 660 uint32_t cbInstr, bool fRelJmp, PDBGFADDRESS pAddrJmpTarget) 302 661 { 303 662 int rc = VINF_SUCCESS; 663 664 Assert(!dbgfR3FlowBranchTargetIsIndirect(pDisParam)); 304 665 305 666 /* Relative jumps are always from the beginning of the next instruction. */ … … 336 697 } 337 698 else 338 AssertFailedStmt(rc = VERR_ NOT_SUPPORTED);699 AssertFailedStmt(rc = VERR_INVALID_STATE); 339 700 } 340 701 … … 344 705 345 706 /** 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 */ 714 static 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 */ 749 static 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)) 444 767 { 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 } 468 783 } 469 784 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 */ 813 static 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 */ 901 static 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 } 471 934 } 472 935 else 473 AssertFailedStmt(rc = VERR_INVALID_STATE); /** @todo: Proper status code. */ 936 rc = dbgfR3FlowBranchTblVerifyAdd(pThis, pFlowBb, pAddrBranchTgt, 937 idxGenRegBase, cbPtr, pUVM, idCpu); 474 938 475 939 return rc; … … 478 942 479 943 /** 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. 482 945 * 483 946 * @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 */ 954 static 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 */ 1039 static int dbgfR3FlowBbCheckBranchTblCandidate(PDBGFFLOWINT pThis, PDBGFFLOWBBINT pFlowBb, PUVM pUVM, 1040 VMCPUID idCpu, PDISOPPARAM pDisParam, uint32_t fFlagsDisasm) 1041 { 500 1042 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 } 504 1086 else 505 rc = VERR_NO_MEMORY; 1087 dbgfR3FlowBbSetError(pFlowBb, VERR_INVALID_STATE, 1088 "The instruction does not use a register"); 506 1089 507 1090 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);531 1091 } 532 1092 … … 539 1099 * @param idCpu CPU id for disassembling. 540 1100 * @param pThis The control flow graph to populate. 541 * @param pFlowBb 1101 * @param pFlowBb The basic block to fill. 542 1102 * @param cbDisasmMax The maximum amount to disassemble. 543 1103 * @param fFlags Combination of DBGF_DISAS_FLAGS_*. … … 624 1184 { 625 1185 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 } 634 1226 } 635 1227 else if (uOpc != OP_CALL) … … 642 1234 * and one starting after the current instruction. 643 1235 */ 644 rc = dbgfR3FlowBbSuccessorAdd(pThis, &AddrDisasm); 1236 rc = dbgfR3FlowBbSuccessorAdd(pThis, &AddrDisasm, 1237 (pFlowBb->fFlags & DBGF_FLOW_BB_F_BRANCH_TABLE), 1238 pFlowBb->pFlowBranchTbl); 645 1239 if (RT_SUCCESS(rc)) 646 1240 { 647 rc = dbgfR3FlowQuery JmpTarget(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); 650 1244 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); 652 1248 } 653 1249 } … … 711 1307 * @param pAddressStart Where to start creating the control flow graph. 712 1308 * @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. 714 1312 * @param phFlow Where to store the handle to the control flow graph on success. 715 1313 */ 716 1314 VMMR3DECL(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) 718 1316 { 719 1317 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); … … 722 1320 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID); 723 1321 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); 726 1324 727 1325 /* Create the control flow graph container. */ … … 733 1331 if (RT_SUCCESS(rc)) 734 1332 { 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; 738 1338 RTListInit(&pThis->LstFlowBb); 1339 RTListInit(&pThis->LstBranchTbl); 739 1340 /* Create the entry basic block and start the work. */ 740 1341 741 PDBGFFLOWBBINT pFlowBb = dbgfR3FlowBbCreate(pThis, pAddressStart, 10);1342 PDBGFFLOWBBINT pFlowBb = dbgfR3FlowBbCreate(pThis, pAddressStart, DBGF_FLOW_BB_F_ENTRY, 10); 742 1343 if (RT_LIKELY(pFlowBb)) 743 1344 { 744 pFlowBb->fFlags |= DBGF_FLOW_BB_F_ENTRY;745 1345 dbgfR3FlowLink(pThis, pFlowBb); 746 rc = dbgfR3FlowPopulate(pUVM, idCpu, pThis, pAddressStart, cbDisasmMax, fFlags );1346 rc = dbgfR3FlowPopulate(pUVM, idCpu, pThis, pAddressStart, cbDisasmMax, fFlagsDisasm); 747 1347 if (RT_SUCCESS(rc)) 748 1348 { … … 836 1436 * @returns VBox status code. 837 1437 * @retval VERR_NOT_FOUND if there is no basic block intersecting with the address. 838 * @param hFlow 1438 * @param hFlow The control flow graph handle. 839 1439 * @param pAddr The address to look for. 840 * @param phFlowBb 1440 * @param phFlowBb Where to store the basic block handle on success. 841 1441 */ 842 1442 VMMR3DECL(int) DBGFR3FlowQueryBbByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBB phFlowBb) … … 844 1444 PDBGFFLOWINT pThis = hFlow; 845 1445 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 1446 AssertPtrReturn(pAddr, VERR_INVALID_POINTER); 846 1447 AssertPtrReturn(phFlowBb, VERR_INVALID_POINTER); 847 1448 … … 849 1450 RTListForEach(&pThis->LstFlowBb, pFlowBb, DBGFFLOWBBINT, NdFlowBb) 850 1451 { 851 if (dbgfR3Flow BbAddrIntersect(pFlowBb, pAddr))1452 if (dbgfR3FlowAddrIntersect(pFlowBb, pAddr)) 852 1453 { 853 1454 DBGFR3FlowBbRetain(pFlowBb); … … 855 1456 return VINF_SUCCESS; 856 1457 } 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 */ 1475 VMMR3DECL(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; 857 1488 } 858 1489 … … 1042 1673 1043 1674 /** 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 */ 1685 VMMR3DECL(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 /** 1044 1700 * Returns the error status and message if the given basic block has an error. 1045 1701 * … … 1150 1806 DBGFADDRESS AddrStart = pFlowBb->AddrEnd; 1151 1807 DBGFR3AddrAdd(&AddrStart, 1); 1152 if (dbgfR3Flow BbAddrEqual(&pFlowBbCur->AddrStart, &AddrStart))1808 if (dbgfR3FlowAddrEqual(&pFlowBbCur->AddrStart, &AddrStart)) 1153 1809 cRefsBb++; 1154 1810 } … … 1156 1812 if ( ( pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_UNCOND_JMP 1157 1813 || pFlowBbCur->enmEndType == DBGFFLOWBBENDTYPE_COND) 1158 && dbgfR3Flow BbAddrEqual(&pFlowBbCur->AddrStart, &pFlowBb->AddrTarget))1814 && dbgfR3FlowAddrEqual(&pFlowBbCur->AddrStart, &pFlowBb->AddrTarget)) 1159 1815 cRefsBb++; 1160 1816 } … … 1168 1824 * @returns VBox status code. 1169 1825 * @retval VERR_BUFFER_OVERFLOW if the array can't hold all the basic blocks. 1170 * @param hFlowBb 1171 * @param paFlowBbRef 1826 * @param hFlowBb The basic block handle. 1827 * @param paFlowBbRef Pointer to the array containing the referencing basic block handles on success. 1172 1828 * @param cRef Number of entries in the given array. 1173 1829 */ … … 1176 1832 RT_NOREF3(hFlowBb, paFlowBbRef, cRef); 1177 1833 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 */ 1843 VMMR3DECL(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 */ 1860 VMMR3DECL(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 */ 1881 VMMR3DECL(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 */ 1897 VMMR3DECL(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 */ 1917 VMMR3DECL(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; 1178 1929 } 1179 1930 … … 1188 1939 PDBGFFLOWBBINT pFlowBb2 = *(PDBGFFLOWBBINT *)pvElement2; 1189 1940 1190 if (dbgfR3Flow BbAddrEqual(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))1941 if (dbgfR3FlowAddrEqual(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart)) 1191 1942 return 0; 1192 1943 1193 1944 if (*penmOrder == DBGFFLOWITORDER_BY_ADDR_LOWEST_FIRST) 1194 1945 { 1195 if (dbgfR3Flow BbAddrLower(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))1946 if (dbgfR3FlowAddrLower(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart)) 1196 1947 return -1; 1197 1948 else … … 1200 1951 else 1201 1952 { 1202 if (dbgfR3Flow BbAddrLower(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart))1953 if (dbgfR3FlowAddrLower(&pFlowBb1->AddrStart, &pFlowBb2->AddrStart)) 1203 1954 return 1; 1204 1955 else -
trunk/src/VBox/VMM/VMMR3/VMMR3.def
r64582 r64586 135 135 DBGFR3FlowQueryStartBb 136 136 DBGFR3FlowQueryBbByAddress 137 DBGFR3FlowQueryBranchTblByAddress 137 138 DBGFR3FlowGetBbCount 139 DBGFR3FlowGetBranchTblCount 138 140 DBGFR3FlowBbRetain 139 141 DBGFR3FlowBbRelease … … 145 147 DBGFR3FlowBbGetInstrCount 146 148 DBGFR3FlowBbGetFlags 149 DBGFR3FlowBbQueryBranchTbl 147 150 DBGFR3FlowBbQueryError 148 151 DBGFR3FlowBbQueryInstr … … 150 153 DBGFR3FlowBbGetRefBbCount 151 154 DBGFR3FlowBbGetRefBb 155 DBGFR3FlowBranchTblRetain 156 DBGFR3FlowBranchTblRelease 157 DBGFR3FlowBranchTblGetSlots 158 DBGFR3FlowBranchTblGetStartAddress 159 DBGFR3FlowBranchTblQueryAddresses 152 160 DBGFR3FlowItCreate 153 161 DBGFR3FlowItDestroy
Note:
See TracChangeset
for help on using the changeset viewer.