Changeset 64720 in vbox for trunk/src/VBox/VMM/VMMR3
- Timestamp:
- Nov 20, 2016 2:00:02 AM (8 years ago)
- svn:sync-xref-src-repo-rev:
- 112004
- Location:
- trunk/src/VBox/VMM/VMMR3
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR3/DBGF.cpp
r63560 r64720 94 94 95 95 /********************************************************************************************************************************* 96 * Structures and Typedefs * 97 *********************************************************************************************************************************/ 98 /** 99 * Instruction type returned by dbgfStepGetCurInstrType. 100 */ 101 typedef enum DBGFSTEPINSTRTYPE 102 { 103 DBGFSTEPINSTRTYPE_INVALID = 0, 104 DBGFSTEPINSTRTYPE_OTHER, 105 DBGFSTEPINSTRTYPE_RET, 106 DBGFSTEPINSTRTYPE_CALL, 107 DBGFSTEPINSTRTYPE_END, 108 DBGFSTEPINSTRTYPE_32BIT_HACK = 0x7fffffff 109 } DBGFSTEPINSTRTYPE; 110 111 112 /********************************************************************************************************************************* 96 113 * Internal Functions * 97 114 *********************************************************************************************************************************/ … … 99 116 static int dbgfR3VMMCmd(PVM pVM, DBGFCMD enmCmd, PDBGFCMDDATA pCmdData, bool *pfResumeExecution); 100 117 static DECLCALLBACK(int) dbgfR3Attach(PVM pVM); 118 static DBGFSTEPINSTRTYPE dbgfStepGetCurInstrType(PVM pVM, PVMCPU pVCpu); 119 static bool dbgfStepAreWeThereYet(PVM pVM, PVMCPU pVCpu); 101 120 102 121 … … 140 159 AssertCompile(sizeof(pUVM->dbgf.s) <= sizeof(pUVM->dbgf.padding)); 141 160 AssertCompile(sizeof(pUVM->aCpus[0].dbgf.s) <= sizeof(pUVM->aCpus[0].dbgf.padding)); 161 162 pVM->dbgf.s.SteppingFilter.idCpu = NIL_VMCPUID; 142 163 143 164 /* … … 550 571 static int dbgfR3SendEvent(PVM pVM) 551 572 { 573 pVM->dbgf.s.SteppingFilter.idCpu = NIL_VMCPUID; 574 552 575 int rc = RTSemPing(&pVM->dbgf.s.PingPong); 553 576 if (RT_SUCCESS(rc)) … … 613 636 VMMR3DECL(int) DBGFR3Event(PVM pVM, DBGFEVENTTYPE enmEvent) 614 637 { 638 /* 639 * Do stepping filtering. 640 */ 641 /** @todo Would be better if we did some of this inside the execution 642 * engines. */ 643 if ( enmEvent == DBGFEVENT_STEPPED 644 || enmEvent == DBGFEVENT_STEPPED_HYPER) 645 { 646 if (!dbgfStepAreWeThereYet(pVM, VMMGetCpu(pVM))) 647 return VINF_EM_DBG_STEP; 648 } 649 615 650 int rc = dbgfR3EventPrologue(pVM, enmEvent); 616 651 if (RT_FAILURE(rc)) … … 891 926 /** 892 927 * Executes command from debugger. 928 * 893 929 * The caller is responsible for waiting or resuming execution based on the 894 930 * value returned in the *pfResumeExecution indicator. … … 947 983 pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_DETACH_DONE; 948 984 pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_OTHER; 985 pVM->dbgf.s.SteppingFilter.idCpu = NIL_VMCPUID; 949 986 fSendEvent = true; 950 987 fResume = true; … … 969 1006 { 970 1007 Log2(("Single step\n")); 971 rc = VINF_EM_DBG_STEP;972 1008 /** @todo SMP */ 973 1009 PVMCPU pVCpu = VMMGetCpu0(pVM); 974 pVCpu->dbgf.s.fSingleSteppingRaw = true; 975 fSendEvent = false; 976 fResume = true; 1010 if (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_OVER) 1011 { 1012 if (dbgfStepGetCurInstrType(pVM, pVCpu) == DBGFSTEPINSTRTYPE_CALL) 1013 pVM->dbgf.s.SteppingFilter.uCallDepth++; 1014 } 1015 if (pVM->dbgf.s.SteppingFilter.cMaxSteps > 0) 1016 { 1017 pVCpu->dbgf.s.fSingleSteppingRaw = true; 1018 fSendEvent = false; 1019 fResume = true; 1020 rc = VINF_EM_DBG_STEP; 1021 } 1022 else 1023 { 1024 /* Stop after zero steps. Nonsense, but whatever. */ 1025 pVM->dbgf.s.SteppingFilter.idCpu = NIL_VMCPUID; 1026 pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM); 1027 pVM->dbgf.s.DbgEvent.enmType = pVM->dbgf.s.DbgEvent.enmCtx != DBGFEVENTCTX_HYPER 1028 ? DBGFEVENT_STEPPED : DBGFEVENT_STEPPED_HYPER; 1029 fSendEvent = false; 1030 fResume = false; 1031 } 977 1032 break; 978 1033 } … … 1279 1334 1280 1335 /** 1336 * Classifies the current instruction. 1337 * 1338 * @returns Type of instruction. 1339 * @param pVM The cross context VM structure. 1340 * @param pVCpu The current CPU. 1341 * @thread EMT(pVCpu) 1342 */ 1343 static DBGFSTEPINSTRTYPE dbgfStepGetCurInstrType(PVM pVM, PVMCPU pVCpu) 1344 { 1345 /* 1346 * Read the instruction. 1347 */ 1348 bool fIsHyper = dbgfR3FigureEventCtx(pVM) == DBGFEVENTCTX_HYPER; 1349 size_t cbRead = 0; 1350 uint8_t abOpcode[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 1351 int rc = PGMR3DbgReadGCPtr(pVM, abOpcode, !fIsHyper ? CPUMGetGuestFlatPC(pVCpu) : CPUMGetHyperRIP(pVCpu), 1352 sizeof(abOpcode) - 1, 0 /*fFlags*/, &cbRead); 1353 if (RT_SUCCESS(rc)) 1354 { 1355 /* 1356 * Do minimal parsing. No real need to involve the disassembler here. 1357 */ 1358 uint8_t *pb = abOpcode; 1359 for (;;) 1360 { 1361 switch (*pb++) 1362 { 1363 default: 1364 return DBGFSTEPINSTRTYPE_OTHER; 1365 1366 case 0xe8: /* call rel16/32 */ 1367 case 0x9a: /* call farptr */ 1368 case 0xcc: /* int3 */ 1369 case 0xcd: /* int xx */ 1370 // case 0xce: /* into */ 1371 return DBGFSTEPINSTRTYPE_CALL; 1372 1373 case 0xc2: /* ret xx */ 1374 case 0xc3: /* ret */ 1375 case 0xca: /* retf xx */ 1376 case 0xcb: /* retf */ 1377 case 0xcf: /* iret */ 1378 return DBGFSTEPINSTRTYPE_RET; 1379 1380 case 0xff: 1381 if ( ((*pb >> X86_MODRM_REG_SHIFT) & X86_MODRM_REG_SMASK) == 2 /* call indir */ 1382 || ((*pb >> X86_MODRM_REG_SHIFT) & X86_MODRM_REG_SMASK) == 3) /* call indir-farptr */ 1383 return DBGFSTEPINSTRTYPE_CALL; 1384 return DBGFSTEPINSTRTYPE_OTHER; 1385 1386 case 0x0f: 1387 switch (*pb++) 1388 { 1389 case 0x05: /* syscall */ 1390 case 0x34: /* sysenter */ 1391 return DBGFSTEPINSTRTYPE_CALL; 1392 case 0x07: /* sysret */ 1393 case 0x35: /* sysexit */ 1394 return DBGFSTEPINSTRTYPE_RET; 1395 } 1396 break; 1397 1398 /* Must handle some REX prefixes. So we do all normal prefixes. */ 1399 case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: 1400 case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: 1401 if (fIsHyper) /* ASSUMES 32-bit raw-mode! */ 1402 return DBGFSTEPINSTRTYPE_OTHER; 1403 if (!CPUMIsGuestIn64BitCode(pVCpu)) 1404 return DBGFSTEPINSTRTYPE_OTHER; 1405 break; 1406 1407 case 0x2e: /* CS */ 1408 case 0x36: /* SS */ 1409 case 0x3e: /* DS */ 1410 case 0x26: /* ES */ 1411 case 0x64: /* FS */ 1412 case 0x65: /* GS */ 1413 case 0x66: /* op size */ 1414 case 0x67: /* addr size */ 1415 case 0xf0: /* lock */ 1416 case 0xf2: /* REPNZ */ 1417 case 0xf3: /* REPZ */ 1418 break; 1419 } 1420 } 1421 } 1422 1423 return DBGFSTEPINSTRTYPE_INVALID; 1424 } 1425 1426 1427 /** 1428 * Checks if the stepping has reached a stop point. 1429 * 1430 * Called when raising a stepped event. 1431 * 1432 * @returns true if the event should be raised, false if we should take one more 1433 * step first. 1434 * @param pVM The cross context VM structure. 1435 * @param pVCpu The cross context per CPU structure of the calling EMT. 1436 * @thread EMT(pVCpu) 1437 */ 1438 static bool dbgfStepAreWeThereYet(PVM pVM, PVMCPU pVCpu) 1439 { 1440 /* 1441 * Check valid pVCpu and that it matches the CPU one stepping. 1442 */ 1443 if (pVCpu) 1444 { 1445 if (pVCpu->idCpu == pVM->dbgf.s.SteppingFilter.idCpu) 1446 { 1447 /* 1448 * Increase the number of steps and see if we've reached the max. 1449 */ 1450 pVM->dbgf.s.SteppingFilter.cSteps++; 1451 if (pVM->dbgf.s.SteppingFilter.cSteps < pVM->dbgf.s.SteppingFilter.cMaxSteps) 1452 { 1453 /* 1454 * Check PC and SP address filtering. 1455 */ 1456 if (pVM->dbgf.s.SteppingFilter.fFlags & (DBGF_STEP_F_STOP_ON_ADDRESS || DBGF_STEP_F_STOP_ON_STACK_POP)) 1457 { 1458 bool fIsHyper = dbgfR3FigureEventCtx(pVM) == DBGFEVENTCTX_HYPER; 1459 if ( (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_ON_ADDRESS) 1460 && pVM->dbgf.s.SteppingFilter.AddrPc == (!fIsHyper ? CPUMGetGuestFlatPC(pVCpu) : CPUMGetHyperRIP(pVCpu))) 1461 return true; 1462 if ( (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_ON_STACK_POP) 1463 && (!fIsHyper ? CPUMGetGuestFlatSP(pVCpu) : (uint64_t)CPUMGetHyperESP(pVCpu)) 1464 - pVM->dbgf.s.SteppingFilter.AddrStackPop 1465 < pVM->dbgf.s.SteppingFilter.cbStackPop) 1466 return true; 1467 } 1468 1469 /* 1470 * Do step-over filtering separate from the step-into one. 1471 */ 1472 if (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_OVER) 1473 { 1474 DBGFSTEPINSTRTYPE enmType = dbgfStepGetCurInstrType(pVM, pVCpu); 1475 switch (enmType) 1476 { 1477 default: 1478 if ( pVM->dbgf.s.SteppingFilter.uCallDepth != 0 1479 || (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_FILTER_MASK)) 1480 break; 1481 return true; 1482 case DBGFSTEPINSTRTYPE_CALL: 1483 if ( (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_ON_CALL) 1484 && pVM->dbgf.s.SteppingFilter.uCallDepth == 0) 1485 return true; 1486 pVM->dbgf.s.SteppingFilter.uCallDepth++; 1487 break; 1488 case DBGFSTEPINSTRTYPE_RET: 1489 if (pVM->dbgf.s.SteppingFilter.uCallDepth == 0) 1490 { 1491 if (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_ON_RET) 1492 return true; 1493 /* If after return, we use the cMaxStep limit to stop the next time. */ 1494 if (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_AFTER_RET) 1495 pVM->dbgf.s.SteppingFilter.cMaxSteps = pVM->dbgf.s.SteppingFilter.cSteps + 1; 1496 } 1497 else if (pVM->dbgf.s.SteppingFilter.uCallDepth > 0) 1498 pVM->dbgf.s.SteppingFilter.uCallDepth--; 1499 break; 1500 } 1501 return false; 1502 } 1503 /* 1504 * Filtered step-into. 1505 */ 1506 else if ( pVM->dbgf.s.SteppingFilter.fFlags 1507 & (DBGF_STEP_F_STOP_ON_CALL | DBGF_STEP_F_STOP_ON_RET | DBGF_STEP_F_STOP_AFTER_RET)) 1508 { 1509 DBGFSTEPINSTRTYPE enmType = dbgfStepGetCurInstrType(pVM, pVCpu); 1510 switch (enmType) 1511 { 1512 default: 1513 break; 1514 case DBGFSTEPINSTRTYPE_CALL: 1515 if (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_ON_CALL) 1516 return true; 1517 break; 1518 case DBGFSTEPINSTRTYPE_RET: 1519 if (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_ON_RET) 1520 return true; 1521 /* If after return, we use the cMaxStep limit to stop the next time. */ 1522 if (pVM->dbgf.s.SteppingFilter.fFlags & DBGF_STEP_F_STOP_AFTER_RET) 1523 pVM->dbgf.s.SteppingFilter.cMaxSteps = pVM->dbgf.s.SteppingFilter.cSteps + 1; 1524 break; 1525 } 1526 return false; 1527 } 1528 } 1529 } 1530 } 1531 1532 return true; 1533 } 1534 1535 1536 /** 1281 1537 * Step Into. 1282 1538 * … … 1289 1545 */ 1290 1546 VMMR3DECL(int) DBGFR3Step(PUVM pUVM, VMCPUID idCpu) 1547 { 1548 return DBGFR3StepEx(pUVM, idCpu, DBGF_STEP_F_INTO, NULL, NULL, 0, 1); 1549 } 1550 1551 1552 /** 1553 * Full fleged step. 1554 * 1555 * This extended stepping API allows for doing multiple steps before raising an 1556 * event, helping implementing step over, step out and other more advanced 1557 * features. 1558 * 1559 * Like the DBGFR3Step() API, this will normally generate a DBGFEVENT_STEPPED or 1560 * DBGFEVENT_STEPPED_EVENT. However the stepping may be interrupted by other 1561 * events, which will abort the stepping. 1562 * 1563 * The stop on pop area feature is for safeguarding step out. 1564 * 1565 * Please note though, that it will always use stepping and never breakpoints. 1566 * While this allows for a much greater flexibility it can at times be rather 1567 * slow. 1568 * 1569 * @returns VBox status code. 1570 * @param pUVM The user mode VM handle. 1571 * @param idCpu The ID of the CPU to single step on. 1572 * @param fFlags Flags controlling the stepping, DBGF_STEP_F_XXX. 1573 * Either DBGF_STEP_F_INTO or DBGF_STEP_F_OVER must 1574 * always be specified. 1575 * @param pStopPcAddr Address to stop executing at. Completely ignored 1576 * unless DBGF_STEP_F_STOP_ON_ADDRESS is specified. 1577 * @param pStopPopAddr Stack address that SP must be lower than when 1578 * performing DBGF_STEP_F_STOP_ON_STACK_POP filtering. 1579 * @param cbStopPop The range starting at @a pStopPopAddr which is 1580 * considered to be within the same thread stack. Note 1581 * that the API allows @a pStopPopAddr and @a cbStopPop 1582 * to form an area that wraps around and it will 1583 * consider the part starting at 0 as included. 1584 * @param cMaxStep The maximum number of steps to take. This is to 1585 * prevent stepping for ever, so passing UINT32_MAX is 1586 * not recommended. 1587 * 1588 * @remarks The two address arguments must be guest context virtual addresses, 1589 * or HMA. The code doesn't make much of a point of out HMA, though. 1590 */ 1591 VMMR3DECL(int) DBGFR3StepEx(PUVM pUVM, VMCPUID idCpu, uint32_t fFlags, PCDBGFADDRESS pStopPcAddr, 1592 PCDBGFADDRESS pStopPopAddr, RTGCUINTPTR cbStopPop, uint32_t cMaxSteps) 1291 1593 { 1292 1594 /* … … 1297 1599 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); 1298 1600 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER); 1601 AssertReturn(!(fFlags & ~DBGF_STEP_F_VALID_MASK), VERR_INVALID_FLAGS); 1602 AssertReturn(RT_BOOL(fFlags & DBGF_STEP_F_INTO) != RT_BOOL(fFlags & DBGF_STEP_F_OVER), VERR_INVALID_FLAGS); 1603 if (fFlags & DBGF_STEP_F_STOP_ON_ADDRESS) 1604 { 1605 AssertReturn(RT_VALID_PTR(pStopPcAddr), VERR_INVALID_POINTER); 1606 AssertReturn(DBGFADDRESS_IS_VALID(pStopPcAddr), VERR_INVALID_PARAMETER); 1607 AssertReturn(DBGFADDRESS_IS_VIRT_GC(pStopPcAddr), VERR_INVALID_PARAMETER); 1608 } 1609 AssertReturn(!(fFlags & DBGF_STEP_F_STOP_ON_STACK_POP) || RT_VALID_PTR(pStopPopAddr), VERR_INVALID_POINTER); 1610 if (fFlags & DBGF_STEP_F_STOP_ON_STACK_POP) 1611 { 1612 AssertReturn(RT_VALID_PTR(pStopPopAddr), VERR_INVALID_POINTER); 1613 AssertReturn(DBGFADDRESS_IS_VALID(pStopPopAddr), VERR_INVALID_PARAMETER); 1614 AssertReturn(DBGFADDRESS_IS_VIRT_GC(pStopPopAddr), VERR_INVALID_PARAMETER); 1615 AssertReturn(cbStopPop > 0, VERR_INVALID_PARAMETER); 1616 } 1617 1299 1618 AssertReturn(pVM->dbgf.s.fAttached, VERR_DBGF_NOT_ATTACHED); 1300 1619 if (RT_LIKELY(RTSemPongIsSpeaker(&pVM->dbgf.s.PingPong))) … … 1302 1621 else 1303 1622 return VERR_SEM_OUT_OF_TURN; 1623 Assert(pVM->dbgf.s.SteppingFilter.idCpu == NIL_VMCPUID); 1304 1624 1305 1625 /* 1306 1626 * Send the ping back to the emulation thread telling it to run. 1307 1627 */ 1628 if (fFlags == DBGF_STEP_F_INTO) 1629 pVM->dbgf.s.SteppingFilter.idCpu = NIL_VMCPUID; 1630 else 1631 pVM->dbgf.s.SteppingFilter.idCpu = idCpu; 1632 pVM->dbgf.s.SteppingFilter.fFlags = fFlags; 1633 if (fFlags & DBGF_STEP_F_STOP_ON_ADDRESS) 1634 pVM->dbgf.s.SteppingFilter.AddrPc = pStopPcAddr->FlatPtr; 1635 else 1636 pVM->dbgf.s.SteppingFilter.AddrPc = 0; 1637 if (fFlags & DBGF_STEP_F_STOP_ON_STACK_POP) 1638 { 1639 pVM->dbgf.s.SteppingFilter.AddrStackPop = pStopPopAddr->FlatPtr; 1640 pVM->dbgf.s.SteppingFilter.cbStackPop = cbStopPop; 1641 } 1642 else 1643 { 1644 pVM->dbgf.s.SteppingFilter.AddrStackPop = 0; 1645 pVM->dbgf.s.SteppingFilter.cbStackPop = RTGCPTR_MAX; 1646 } 1647 1648 pVM->dbgf.s.SteppingFilter.cMaxSteps = cMaxSteps; 1649 pVM->dbgf.s.SteppingFilter.cSteps = 0; 1650 pVM->dbgf.s.SteppingFilter.uCallDepth = 0; 1651 1308 1652 /** @todo SMP (idCpu) */ 1309 1653 dbgfR3SetCmd(pVM, DBGFCMD_SINGLE_STEP); -
trunk/src/VBox/VMM/VMMR3/DBGFCpu.cpp
r62478 r64720 109 109 110 110 /** 111 * Wrapper around CPUMIsGuestInV86Code. 112 * 113 * @returns VINF_SUCCESS. 114 * @param pVM The cross context VM structure. 115 * @param idCpu The current CPU ID. 116 * @param pfInV86Code Where to return the result. 117 */ 118 static DECLCALLBACK(int) dbgfR3CpuInV86Code(PVM pVM, VMCPUID idCpu, bool *pfInV86Code) 119 { 120 Assert(idCpu == VMMGetCpuId(pVM)); 121 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu); 122 *pfInV86Code = CPUMIsGuestInV86ModeEx(CPUMQueryGuestCtxPtr(pVCpu)); 123 return VINF_SUCCESS; 124 } 125 126 127 /** 128 * Checks if the given CPU is executing V8086 code or not. 129 * 130 * @returns true / false accordingly. 131 * @param pUVM The user mode VM handle. 132 * @param idCpu The target CPU ID. 133 */ 134 VMMR3DECL(bool) DBGFR3CpuIsInV86Code(PUVM pUVM, VMCPUID idCpu) 135 { 136 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false); 137 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, false); 138 AssertReturn(idCpu < pUVM->pVM->cCpus, false); 139 140 bool fInV86Code; 141 int rc = VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3CpuInV86Code, 3, pUVM->pVM, idCpu, &fInV86Code); 142 if (RT_FAILURE(rc)) 143 return false; 144 return fInV86Code; 145 } 146 147 148 /** 111 149 * Get the number of CPUs (or threads if you insist). 112 150 *
Note:
See TracChangeset
for help on using the changeset viewer.