- Timestamp:
- Oct 21, 2020 3:01:32 PM (4 years ago)
- Location:
- trunk
- Files:
-
- 9 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/Config.kmk
r86643 r86666 446 446 VBOX_WITH_RAM_IN_KERNEL := 1 447 447 endif 448 # Enables the new breakpoint handling code, see @bugref{9837} 449 # VBOX_WITH_LOTS_OF_DBGF_BPS = 1 448 450 ## @} 449 451 -
trunk/include/VBox/err.h
r86099 r86666 326 326 /** Internal processing error \#1 in the DBGF core code. */ 327 327 #define VERR_DBGF_IPE_1 (-1223) 328 /** Returned by a breakpoint callback when guest execution should be suspended 329 * and the VM should be dropped into the debugger. */ 330 #define VINF_DBGF_BP_HALT (1224) 331 /** The breakpoint owner handle is still used by one or more breakpoints. */ 332 #define VERR_DBGF_OWNER_BUSY (-1225) 328 333 /** @} */ 329 334 -
trunk/include/VBox/types.h
r84826 r86666 521 521 /** RC pointer to a DBGF tracer instance. */ 522 522 typedef RCPTRTYPE(struct DBGFTRACERINSRC *) PDBGFTRACERINSRC; 523 524 #ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 525 /** A cross context DBGF breakpoint owner handle. */ 526 typedef uint32_t DBGFBPOWNER; 527 /** Pointer to a cross context DBGF breakpoint owner handle. */ 528 typedef DBGFBPOWNER *PDBGFBPOWNER; 529 /** A NIL DBGF breakpoint owner handle. */ 530 #define NIL_DBGFBPOWNER ((uint32_t)UINT32_MAX) 531 532 /** A cross context DBGF breakpoint handle. */ 533 typedef uint32_t DBGFBP; 534 /** Pointer to a cross context DBGF breakpoint handle. */ 535 typedef DBGFBP *PDBGFBP; 536 /** A NIL DBGF breakpoint handle. */ 537 #define NIL_DBGFBP ((uint32_t)UINT32_MAX) 538 #endif 523 539 /** @} */ 524 540 -
trunk/include/VBox/vmm/dbgf.h
r86361 r86666 529 529 struct DBGFEVENTBP 530 530 { 531 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 531 532 /** The identifier of the breakpoint which was hit. */ 532 533 RTUINT iBp; 534 #else 535 /** The handle of the breakpoint which was hit. */ 536 DBGFBP hBp; 537 #endif 533 538 } Bp; 534 539 … … 744 749 typedef enum DBGFBPTYPE 745 750 { 751 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 746 752 /** Free breakpoint entry. */ 747 753 DBGFBPTYPE_FREE = 0, 754 #else 755 /** Invalid breakpoint type. */ 756 DBGFBPTYPE_INVALID = 0, 757 #endif 748 758 /** Debug register. */ 749 759 DBGFBPTYPE_REG, 750 760 /** INT 3 instruction. */ 751 761 DBGFBPTYPE_INT3, 762 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 752 763 /** Recompiler. */ 753 764 DBGFBPTYPE_REM, 765 #endif 754 766 /** Port I/O breakpoint. */ 755 767 DBGFBPTYPE_PORT_IO, … … 798 810 /** @} */ 799 811 812 #ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 813 /** 814 * The visible breakpoint state (read-only). 815 */ 816 typedef struct DBGFBPPUB 817 { 818 /** The number of breakpoint hits. */ 819 uint64_t cHits; 820 /** The hit number which starts to trigger the breakpoint. */ 821 uint64_t iHitTrigger; 822 /** The hit number which stops triggering the breakpoint (disables it). 823 * Use ~(uint64_t)0 if it should never stop. */ 824 uint64_t iHitDisable; 825 /** The breakpoint owner handle (a nil owner defers the breakpoint to the 826 * debugger). */ 827 DBGFBPOWNER hOwner; 828 /** The breakpoint type. */ 829 DBGFBPTYPE enmType; 830 /** The breakpoint handle this state belongs to. */ 831 DBGFBP hBp; 832 /** Breakpoint flags, see DBGF_BP_F_XXX. */ 833 uint32_t fFlags; 834 835 /** Union of type specific data. */ 836 union 837 { 838 /** The flat GC address breakpoint address for REG and INT3 breakpoints. */ 839 RTGCUINTPTR GCPtr; 840 841 /** Debug register data. */ 842 struct DBGFBPREG 843 { 844 /** The flat GC address of the breakpoint. */ 845 RTGCUINTPTR GCPtr; 846 /** The debug register number. */ 847 uint8_t iReg; 848 /** The access type (one of the X86_DR7_RW_* value). */ 849 uint8_t fType; 850 /** The access size. */ 851 uint8_t cb; 852 } Reg; 853 854 /** INT3 breakpoint data. */ 855 struct DBGFBPINT3 856 { 857 /** The flat GC address of the breakpoint. */ 858 RTGCUINTPTR GCPtr; 859 /** The physical address of the breakpoint. */ 860 RTGCPHYS PhysAddr; 861 /** The byte value we replaced by the INT 3 instruction. */ 862 uint8_t bOrg; 863 } Int3; 864 865 /** I/O port breakpoint data. */ 866 struct DBGFBPPORTIO 867 { 868 /** The first port. */ 869 RTIOPORT uPort; 870 /** The number of ports. */ 871 RTIOPORT cPorts; 872 /** Valid DBGFBPIOACCESS_XXX selection, max DWORD size. */ 873 uint32_t fAccess; 874 } PortIo; 875 876 /** Memory mapped I/O breakpoint data. */ 877 struct DBGFBPMMIO 878 { 879 /** The first MMIO address. */ 880 RTGCPHYS PhysAddr; 881 /** The size of the MMIO range in bytes. */ 882 uint32_t cb; 883 /** Valid DBGFBPIOACCESS_XXX selection, max QWORD size. */ 884 uint32_t fAccess; 885 } Mmio; 886 887 /** Padding to the anticipated size. */ 888 uint64_t u64Padding[3]; 889 } u; 890 } DBGFBPPUB; 891 AssertCompileSize(DBGFBPPUB, 64); 892 AssertCompileMembersAtSameOffset(DBGFBPPUB, u.GCPtr, DBGFBPPUB, u.Reg.GCPtr); 893 AssertCompileMembersAtSameOffset(DBGFBPPUB, u.GCPtr, DBGFBPPUB, u.Int3.GCPtr); 894 895 /** Pointer to the visible breakpoint state. */ 896 typedef DBGFBPPUB *PDBGFBPPUB; 897 /** Pointer to a const visible breakpoint state. */ 898 typedef const DBGFBPPUB *PCDBGFBPPUB; 899 900 /** @name Possible DBGFBPPUB::fFlags flags. 901 * @{ */ 902 /** Flag whether the breakpoint is enabled currently. */ 903 #define DBGF_BP_F_ENABLED RT_BIT_32(0) 904 /** @} */ 905 906 /** 907 * Breakpoint hit handler. 908 * 909 * @returns Strict VBox status code. 910 * @retval VINF_SUCCESS if the breakpoint was handled and guest execution can resume. 911 * @retval VINF_DBGF_BP_HALT if guest execution should be stopped and the debugger should be invoked. 912 * 913 * @param pVM The cross-context VM structure pointer. 914 * @param idCpu ID of the vCPU triggering the breakpoint. 915 * @param pvUser User argument of the set breakpoint. 916 * @param pBpPub Pointer to the readonly public state of the breakpoint. 917 * 918 * @remarks The handler is called on the EMT of vCPU triggering the breakpoint and no locks are held. 919 * @remarks Any status code returned other than the ones mentioned will send the VM straight into a 920 * guru meditation. 921 */ 922 typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNDBGFBPHIT,(PVM pVM, VMCPUID idCpu, void *pvUserBp, PCDBGFBPPUB pBpPub)); 923 /** Pointer to a FNDBGFBPHIT(). */ 924 typedef FNDBGFBPHIT *PFNDBGFBPHIT; 925 926 927 #ifdef IN_RING3 928 /** @defgroup grp_dbgf_bp_r3 The DBGF Breakpoint Host Context Ring-3 API 929 * @{ */ 930 VMMR3DECL(int) DBGFR3BpOwnerCreate(PUVM pUVM, PFNDBGFBPHIT pfnBpHit, PDBGFBPOWNER phBpOwner); 931 VMMR3DECL(int) DBGFR3BpOwnerDestroy(PUVM pUVM, DBGFBPOWNER hBpOwner); 932 933 VMMR3DECL(int) DBGFR3BpSetInt3(PUVM pUVM, VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, 934 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); 935 VMMR3DECL(int) DBGFR3BpSetInt3Ex(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, 936 VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, 937 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); 938 VMMR3DECL(int) DBGFR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, 939 uint64_t iHitDisable, uint8_t fType, uint8_t cb, PDBGFBP phBp); 940 VMMR3DECL(int) DBGFR3BpSetRegEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, 941 PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, 942 uint8_t fType, uint8_t cb, PDBGFBP phBp); 943 VMMR3DECL(int) DBGFR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, 944 uint64_t iHitDisable, PDBGFBP phBp); 945 VMMR3DECL(int) DBGFR3BpSetPortIo(PUVM pUVM, RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess, 946 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); 947 VMMR3DECL(int) DBGFR3BpSetPortIoEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, 948 RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess, 949 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); 950 VMMR3DECL(int) DBGFR3BpSetMmio(PUVM pUVM, RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess, 951 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); 952 VMMR3DECL(int) DBGFR3BpSetMmioEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, 953 RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess, 954 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); 955 VMMR3DECL(int) DBGFR3BpClear(PUVM pUVM, DBGFBP hBp); 956 VMMR3DECL(int) DBGFR3BpEnable(PUVM pUVM, DBGFBP hBp); 957 VMMR3DECL(int) DBGFR3BpDisable(PUVM pUVM, DBGFBP hBp); 958 959 /** 960 * Breakpoint enumeration callback function. 961 * 962 * @returns VBox status code. 963 * The enumeration stops on failure status and VINF_CALLBACK_RETURN. 964 * @param pUVM The user mode VM handle. 965 * @param pvUser The user argument. 966 * @param pBp Pointer to the breakpoint information. (readonly) 967 */ 968 typedef DECLCALLBACKTYPE(int, FNDBGFBPENUM,(PUVM pUVM, PCDBGFBPPUB pBpPub)); 969 /** Pointer to a breakpoint enumeration callback function. */ 970 typedef FNDBGFBPENUM *PFNDBGFBPENUM; 971 972 VMMR3DECL(int) DBGFR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser); 973 /** @} */ 974 #endif /* !IN_RING3 */ 975 976 977 #if defined(IN_RING0) || defined(DOXYGEN_RUNNING) 978 /** @defgroup grp_dbgf_bp_r0 The DBGF Breakpoint Host Context Ring-0 API 979 * @{ */ 980 VMMR0_INT_DECL(void) DBGFR0InitPerVMData(PGVM pGVM); 981 VMMR0_INT_DECL(void) DBGFR0CleanupVM(PGVM pGVM); 982 983 VMMR0_INT_DECL(int) DBGFR0BpOwnerSetUpContext(PGVM pGVM, DBGFBPOWNER hBpOwner, PFNDBGFBPHIT pfnBpHit); 984 VMMR0_INT_DECL(int) DBGFR0BpOwnerDestroyContext(PGVM pGVM, DBGFBPOWNER hBpOwner); 985 986 VMMR0_INT_DECL(int) DBGFR0BpSetUpContext(PGVM pGVM, DBGFBP hBp, void *pvUser); 987 VMMR0_INT_DECL(int) DBGFR0BpDestroyContext(PGVM pGVM, DBGFBP hBp); 988 /** @} */ 989 #endif /* IN_RING0 || DOXYGEN_RUNNING */ 990 991 #else /* !VBOX_WITH_LOTS_OF_DBGF_BPS */ 800 992 /** 801 993 * A Breakpoint. … … 890 1082 typedef const DBGFBP *PCDBGFBP; 891 1083 892 # ifdef IN_RING3 /* The breakpoint management API is only available in ring-3. */1084 # ifdef IN_RING3 /* The breakpoint management API is only available in ring-3. */ 893 1085 VMMR3DECL(int) DBGFR3BpSetInt3(PUVM pUVM, VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp); 894 1086 VMMR3DECL(int) DBGFR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, … … 917 1109 918 1110 VMMR3DECL(int) DBGFR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser); 919 #endif /* IN_RING3 */ 1111 # endif /* IN_RING3 */ 1112 #endif /* !VBOX_WITH_LOTS_OF_DBGF_BPS */ 920 1113 921 1114 VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR7(PVM pVM); -
trunk/src/VBox/VMM/Makefile.kmk
r86121 r86666 71 71 ifdef VBOX_WITH_DBGF_TRACING 72 72 VBoxVMM_DEFS += VBOX_WITH_DBGF_TRACING 73 endif 74 ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 75 VBoxVMM_DEFS += VBOX_WITH_LOTS_OF_DBGF_BPS 73 76 endif 74 77 ifdef VBOX_WITH_VMM_R0_SWITCH_STACK … … 96 99 VMMR3/DBGFAddr.cpp \ 97 100 VMMR3/DBGFAddrSpace.cpp \ 98 VMMR3/DBGFBp.cpp\101 $(if-expr defined(VBOX_WITH_LOTS_OF_DBGF_BPS), VMMR3/DBGFR3Bp.cpp, VMMR3/DBGFBp.cpp) \ 99 102 VMMR3/DBGFR3BugCheck.cpp \ 100 103 VMMR3/DBGFCoreWrite.cpp \ -
trunk/src/VBox/VMM/VMMAll/DBGFAll.cpp
r82968 r86666 50 50 { 51 51 RTGCUINTREG uDr7 = X86_DR7_GD | X86_DR7_GE | X86_DR7_LE | X86_DR7_RA1_MASK; 52 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 52 53 PDBGFBP pBp = &pVM->dbgf.s.aHwBreakpoints[0]; 53 54 unsigned cLeft = RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); … … 68 69 pBp++; 69 70 } 71 #else 72 for (uint32_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++) 73 { 74 PCDBGFBPHW pBp = &pVM->dbgf.s.aHwBreakpoints[i]; 75 76 if ( pBp->hBp != NIL_DBGFBP 77 && pBp->fEnabled) 78 { 79 static const uint8_t s_au8Sizes[8] = 80 { 81 X86_DR7_LEN_BYTE, X86_DR7_LEN_BYTE, X86_DR7_LEN_WORD, X86_DR7_LEN_BYTE, 82 X86_DR7_LEN_DWORD,X86_DR7_LEN_BYTE, X86_DR7_LEN_BYTE, X86_DR7_LEN_QWORD 83 }; 84 uDr7 |= X86_DR7_G(i) 85 | X86_DR7_RW(i, pBp->fType) 86 | X86_DR7_LEN(i, s_au8Sizes[pBp->cb]); 87 } 88 pBp++; 89 } 90 #endif 70 91 return uDr7; 71 92 } … … 80 101 VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR0(PVM pVM) 81 102 { 103 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 82 104 PCDBGFBP pBp = &pVM->dbgf.s.aHwBreakpoints[0]; 83 105 Assert(pBp->u.Reg.iReg == 0); 84 106 return pBp->u.Reg.GCPtr; 107 #else 108 PCDBGFBPHW pBp = &pVM->dbgf.s.aHwBreakpoints[0]; 109 return pBp->GCPtr; 110 #endif 85 111 } 86 112 … … 94 120 VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR1(PVM pVM) 95 121 { 122 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 96 123 PCDBGFBP pBp = &pVM->dbgf.s.aHwBreakpoints[1]; 97 124 Assert(pBp->u.Reg.iReg == 1); 98 125 return pBp->u.Reg.GCPtr; 126 #else 127 PCDBGFBPHW pBp = &pVM->dbgf.s.aHwBreakpoints[1]; 128 return pBp->GCPtr; 129 #endif 99 130 } 100 131 … … 108 139 VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR2(PVM pVM) 109 140 { 141 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 110 142 PCDBGFBP pBp = &pVM->dbgf.s.aHwBreakpoints[2]; 111 143 Assert(pBp->u.Reg.iReg == 2); 112 144 return pBp->u.Reg.GCPtr; 145 #else 146 PCDBGFBPHW pBp = &pVM->dbgf.s.aHwBreakpoints[2]; 147 return pBp->GCPtr; 148 #endif 113 149 } 114 150 … … 122 158 VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR3(PVM pVM) 123 159 { 160 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 124 161 PCDBGFBP pBp = &pVM->dbgf.s.aHwBreakpoints[3]; 125 162 Assert(pBp->u.Reg.iReg == 3); 126 163 return pBp->u.Reg.GCPtr; 164 #else 165 PCDBGFBPHW pBp = &pVM->dbgf.s.aHwBreakpoints[3]; 166 return pBp->GCPtr; 167 #endif 127 168 } 128 169 … … 163 204 VMM_INT_DECL(bool) DBGFBpIsInt3Armed(PVM pVM) 164 205 { 206 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 165 207 return pVM->dbgf.s.cEnabledInt3Breakpoints > 0; 208 #else 209 RT_NOREF(pVM); 210 return false; /** @todo */ 211 #endif 166 212 } 167 213 … … 186 232 uint32_t const uIoPortFirst = uIoPort; 187 233 uint32_t const uIoPortLast = uIoPortFirst + cbValue - 1; 188 189 234 190 235 /* 191 236 * Check hyper breakpoints first as the VMM debugger has priority over … … 196 241 for (unsigned iBp = 0; iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); iBp++) 197 242 { 243 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 198 244 if ( pVM->dbgf.s.aHwBreakpoints[iBp].u.Reg.fType == X86_DR7_RW_IO 199 245 && pVM->dbgf.s.aHwBreakpoints[iBp].fEnabled … … 214 260 } 215 261 } 262 #else 263 PCDBGFBPHW pBp = &pVM->dbgf.s.aHwBreakpoints[iBp]; 264 265 if ( pBp->fType == X86_DR7_RW_IO 266 && pBp->hBp == NIL_DBGFBP 267 && pBp->fEnabled) 268 { 269 uint8_t cbReg = pBp->cb; Assert(RT_IS_POWER_OF_TWO(cbReg)); 270 uint64_t uDrXFirst = pBp->GCPtr & ~(uint64_t)(cbReg - 1); 271 uint64_t uDrXLast = uDrXFirst + cbReg - 1; 272 if (uDrXFirst <= uIoPortLast && uDrXLast >= uIoPortFirst) 273 { 274 /* (See also DBGFRZTrap01Handler.) */ 275 pVCpu->dbgf.s.hBpActive = pBp->hBp; 276 pVCpu->dbgf.s.fSingleSteppingRaw = false; 277 278 LogFlow(("DBGFBpCheckIo: hit hw breakpoint %d at %04x:%RGv (iop %#x)\n", 279 iBp, pCtx->cs.Sel, pCtx->rip, uIoPort)); 280 return VINF_EM_DBG_BREAKPOINT; 281 } 282 } 283 #endif 216 284 } 217 285 } … … 254 322 pCtx->dr[7] &= ~X86_DR7_GD; 255 323 LogFlow(("DBGFBpCheckIo: hit hw breakpoint %d at %04x:%RGv (iop %#x)\n", 256 pVM->dbgf.s.aHwBreakpoints[iBp].iBp, pCtx->cs.Sel, pCtx->rip, uIoPort));324 iBp, pCtx->cs.Sel, pCtx->rip, uIoPort)); 257 325 return VINF_EM_RAW_GUEST_TRAP; 258 326 } -
trunk/src/VBox/VMM/VMMR3/DBGF.cpp
r86392 r86666 174 174 dbgfR3OSTermPart2(pUVM); 175 175 } 176 #ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 177 dbgfR3BpTerm(pVM); 178 #endif 176 179 } 177 180 dbgfR3AsTerm(pUVM); … … 203 206 dbgfR3PlugInTerm(pUVM); 204 207 dbgfR3OSTermPart2(pUVM); 208 #ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 209 dbgfR3BpTerm(pVM); 210 #endif 205 211 dbgfR3AsTerm(pUVM); 206 212 dbgfR3RegTerm(pUVM); … … 775 781 */ 776 782 DBGFEVENT DbgEvent; 783 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 777 784 RTUINT iBp = DbgEvent.u.Bp.iBp = pVCpu->dbgf.s.iActiveBp; 778 785 pVCpu->dbgf.s.iActiveBp = ~0U; … … 782 789 return dbgfR3SendEventWaitEx(pVM, pVCpu, enmEvent, DBGFEVENTCTX_RAW, &DbgEvent.u, sizeof(DbgEvent.u.Bp)); 783 790 } 784 791 #else 792 DbgEvent.u.Bp.hBp = pVCpu->dbgf.s.hBpActive; 793 pVCpu->dbgf.s.hBpActive = NIL_DBGFBP; 794 if (DbgEvent.u.Bp.hBp != NIL_DBGFBP) 795 { 796 DbgEvent.enmCtx = DBGFEVENTCTX_RAW; 797 return dbgfR3SendEventWaitEx(pVM, pVCpu, enmEvent, DBGFEVENTCTX_RAW, &DbgEvent.u, sizeof(DbgEvent.u.Bp)); 798 } 799 #endif 800 801 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 785 802 AssertFailed(); /** @todo this should be obsolete now... */ 786 803 … … 801 818 AssertMsg(DbgEvent.u.Bp.iBp != ~0U, ("eip=%08x\n", eip)); 802 819 return dbgfR3SendEventWaitEx(pVM, pVCpu, enmEvent, DBGFEVENTCTX_REM, &DbgEvent.u, sizeof(DbgEvent.u.Bp)); 820 #else 821 return VERR_DBGF_IPE_1; 822 #endif 803 823 } 804 824 -
trunk/src/VBox/VMM/VMMR3/DBGFR3Bp.cpp
r86660 r86666 14 14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the 15 15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. 16 */ 17 18 19 /** @page pg_dbgf_bp DBGF - The Debugger Facility, Breakpoint Management 20 * 21 * The debugger facilities breakpoint managers purpose is to efficiently manage 22 * large amounts of breakpoints for various use cases like dtrace like operations 23 * or execution flow tracing for instance. Especially execution flow tracing can 24 * require thousands of breakpoints which need to be managed efficiently to not slow 25 * down guest operation too much. Before the rewrite starting end of 2020, DBGF could 26 * only handle 32 breakpoints (+ 4 hardware assisted breakpoints). The new 27 * manager is supposed to be able to handle up to one million breakpoints. 28 * 29 * @see grp_dbgf 30 * 31 * 32 * @section sec_dbgf_bp_owner Breakpoint owners 33 * 34 * A single breakpoint owner has a mandatory ring-3 callback and an optional ring-0 35 * callback assigned which is called whenever a breakpoint with the owner assigned is hit. 36 * The common part of the owner is managed by a single table mapped into both ring-0 37 * and ring-3 and the handle being the index into the table. This allows resolving 38 * the handle to the internal structure efficiently. Searching for a free entry is 39 * done using a bitmap indicating free and occupied entries. For the optional 40 * ring-0 owner part there is a separate ring-0 only table for security reasons. 41 * 42 * The callback of the owner can be used to gather and log guest state information 43 * and decide whether to continue guest execution or stop and drop into the debugger. 44 * Breakpoints which don't have an owner assigned will always drop the VM right into 45 * the debugger. 46 * 47 * 48 * @section sec_dbgf_bp_bps Breakpoints 49 * 50 * Breakpoints are referenced by an opaque handle which acts as an index into a global table 51 * mapped into ring-3 and ring-0. Each entry contains the necessary state to manage the breakpoint 52 * like trigger conditions, type, owner, etc. If an owner is given an optional opaque user argument 53 * can be supplied which is passed in the respective owner callback. For owners with ring-0 callbacks 54 * a dedicated ring-0 table is held saving possible ring-0 user arguments. 55 * 56 * To keep memory consumption under control and still support large amounts of 57 * breakpoints the table is split into fixed sized chunks and the chunk index and index 58 * into the chunk can be derived from the handle with only a few logical operations. 59 * 60 * 61 * @section sec_dbgf_bp_resolv Resolving breakpoint addresses 62 * 63 * Whenever a \#BP(0) event is triggered DBGF needs to decide whether the event originated 64 * from within the guest or whether a DBGF breakpoint caused it. This has to happen as fast 65 * as possible. The following scheme is employed to achieve this: 66 * 67 * @verbatim 68 * 7 6 5 4 3 2 1 0 69 * +---+---+---+---+---+---+---+---+ 70 * | | | | | | | | | BP address 71 * +---+---+---+---+---+---+---+---+ 72 * \_____________________/ \_____/ 73 * | | 74 * | +---------------+ 75 * | | 76 * BP table | v 77 * +------------+ | +-----------+ 78 * | hBp 0 | | X <- | 0 | xxxxx | 79 * | hBp 1 | <----------------+------------------------ | 1 | hBp 1 | 80 * | | | +--- | 2 | idxL2 | 81 * | hBp <m> | <---+ v | |...| ... | 82 * | | | +-----------+ | |...| ... | 83 * | | | | | | |...| ... | 84 * | hBp <n> | <-+ +----- | +> leaf | | | . | 85 * | | | | | | | | . | 86 * | | | | + root + | <------------+ | . | 87 * | | | | | | +-----------+ 88 * | | +------- | leaf<+ | L1: 65536 89 * | . | | . | 90 * | . | | . | 91 * | . | | . | 92 * +------------+ +-----------+ 93 * L2 idx AVL 94 * @endverbatim 95 * 96 * -# Take the lowest 16 bits of the breakpoint address and use it as an direct index 97 * into the L1 table. The L1 table is contiguous and consists of 4 byte entries 98 * resulting in 256KiB of memory used. The topmost 4 bits indicate how to proceed 99 * and the meaning of the remaining 28bits depends on the topmost 4 bits: 100 * - A 0 type entry means no breakpoint is registered with the matching lowest 16bits, 101 * so forward the event to the guest. 102 * - A 1 in the topmost 4 bits means that the remaining 28bits directly denote a breakpoint 103 * handle which can be resolved by extracting the chunk index and index into the chunk 104 * of the global breakpoint table. If the address matches the breakpoint is processed 105 * according to the configuration. Otherwise the breakpoint is again forwarded to the guest. 106 * - A 2 in the topmost 4 bits means that there are multiple breakpoints registered 107 * matching the lowest 16bits and the search must continue in the L2 table with the 108 * remaining 28bits acting as an index into the L2 table indicating the search root. 109 * -# The L2 table consists of multiple index based AVL trees, there is one for each reference 110 * from the L1 table. The key for the table are the upper 6 bytes of the breakpoint address 111 * used for searching. This tree is traversed until either a matching address is found and 112 * the breakpoint is being processed or again forwardedto the guest if it isn't successful. 113 * Each entry in the L2 table is 16 bytes big and densly packed to avoid excessive memory usage. 114 * 115 * 116 * @section sec_dbgf_bp_note Random thoughts and notes for the implementation 117 * 118 * - The assumption for this approach is that the lowest 16bits of the breakpoint address are 119 * hopefully the ones being the most varying ones across breakpoints so the traversal 120 * can skip the L2 table in most of the cases. Even if the L2 table must be taken the 121 * individual trees should be quite shallow resulting in low overhead when walking it 122 * (though only real world testing can assert this assumption). 123 * - Index based tables and trees are used instead of pointers because the tables 124 * are always mapped into ring-0 and ring-3 with different base addresses. 125 * - Efficent breakpoint allocation is done by having a global bitmap indicating free 126 * and occupied breakpoint entries. Same applies for the L2 AVL table. 127 * - Special care must be taken when modifying the L1 and L2 tables as other EMTs 128 * might still access it (want to try a lockless approach first using 129 * atomic updates, have to resort to locking if that turns out to be too difficult). 130 * - Each BP entry is supposed to be 64 byte big and each chunk should contain 65536 131 * breakpoints which results in 4MiB for each chunk plus the allocation bitmap. 132 * - ring-0 has to take special care when traversing the L2 AVL tree to not run into cycles 133 * and do strict bounds checking before accessing anything. The L1 and L2 table 134 * are written to from ring-3 only. Same goes for the breakpoint table with the 135 * exception being the opaque user argument for ring-0 which is stored in ring-0 only 136 * memory. 16 137 */ 17 138 … … 40 161 * Structures and Typedefs * 41 162 *********************************************************************************************************************************/ 42 /**43 * DBGF INT3-breakpoint set callback arguments.44 */45 typedef struct DBGFBPINT3ARGS46 {47 /** The source virtual CPU ID (used for breakpoint address resolution). */48 VMCPUID idSrcCpu;49 /** The breakpoint address. */50 PCDBGFADDRESS pAddress;51 /** The hit count at which the breakpoint starts triggering. */52 uint64_t iHitTrigger;53 /** The hit count at which disables the breakpoint. */54 uint64_t iHitDisable;55 /** Where to store the breakpoint Id (optional). */56 uint32_t *piBp;57 } DBGFBPINT3ARGS;58 /** Pointer to a DBGF INT3 breakpoint set callback argument. */59 typedef DBGFBPINT3ARGS *PDBGFBPINT3ARGS;60 163 61 164 … … 64 167 *********************************************************************************************************************************/ 65 168 RT_C_DECLS_BEGIN 66 static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp);67 static int dbgfR3BpInt3Arm(PVM pVM, PDBGFBP pBp);68 169 RT_C_DECLS_END 69 170 … … 71 172 72 173 /** 73 * Initialize the breakpoint stuff. 74 * 75 * @returns VINF_SUCCESS 76 * @param pVM The cross context VM structure. 77 */ 78 int dbgfR3BpInit(PVM pVM) 174 * Initialize the breakpoint mangement. 175 * 176 * @returns VBox status code. 177 * @param pVM The cross context VM structure. 178 */ 179 DECLHIDDEN(int) dbgfR3BpInit(PVM pVM) 180 { 181 RT_NOREF(pVM); 182 return VINF_SUCCESS; 183 } 184 185 186 /** 187 * Terminates the breakpoint mangement. 188 * 189 * @returns VBox status code. 190 * @param pVM The cross context VM structure. 191 */ 192 DECLHIDDEN(int) dbgfR3BpTerm(PVM pVM) 193 { 194 RT_NOREF(pVM); 195 return VINF_SUCCESS; 196 } 197 198 199 /** 200 * Creates a new breakpoint owner returning a handle which can be used when setting breakpoints. 201 * 202 * @returns VBox status code. 203 * @param pUVM The user mode VM handle. 204 * @param pfnBpHit The R3 callback which is called when a breakpoint with the owner handle is hit. 205 * @param phBpOwner Where to store the owner handle on success. 206 */ 207 VMMR3DECL(int) DBGFR3BpOwnerCreate(PUVM pUVM, PFNDBGFBPHIT pfnBpHit, PDBGFBPOWNER phBpOwner) 79 208 { 80 209 /* 81 * Init structures.210 * Validate the input. 82 211 */ 83 unsigned i; 84 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++) 85 { 86 pVM->dbgf.s.aHwBreakpoints[i].iBp = i; 87 pVM->dbgf.s.aHwBreakpoints[i].enmType = DBGFBPTYPE_FREE; 88 pVM->dbgf.s.aHwBreakpoints[i].u.Reg.iReg = i; 89 } 90 91 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++) 92 { 93 pVM->dbgf.s.aBreakpoints[i].iBp = i + RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); 94 pVM->dbgf.s.aBreakpoints[i].enmType = DBGFBPTYPE_FREE; 95 } 96 97 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++) 98 { 99 PVMCPU pVCpu = pVM->apCpusR3[idCpu]; 100 pVCpu->dbgf.s.iActiveBp = ~0U; 101 } 102 212 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); 213 AssertPtrReturn(pfnBpHit, VERR_INVALID_PARAMETER); 214 AssertPtrReturn(phBpOwner, VERR_INVALID_POINTER); 215 216 return VERR_NOT_IMPLEMENTED; 217 } 218 219 220 /** 221 * Destroys the owner identified by the given handle. 222 * 223 * @returns VBox status code. 224 * @retval VERR_DBGF_OWNER_BUSY if there are still breakpoints set with the given owner handle. 225 * @param pUVM The user mode VM handle. 226 * @param hBpOwner The breakpoint owner handle to destroy. 227 */ 228 VMMR3DECL(int) DBGFR3BpOwnerDestroy(PUVM pUVM, DBGFBPOWNER hBpOwner) 229 { 103 230 /* 104 * Register saved state.231 * Validate the input. 105 232 */ 106 /** @todo */ 107 108 return VINF_SUCCESS; 109 } 110 111 112 113 /** 114 * Allocate a breakpoint. 115 * 116 * @returns Pointer to the allocated breakpoint. 117 * @returns NULL if we're out of breakpoints. 118 * @param pVM The cross context VM structure. 119 * @param enmType The type to allocate. 120 */ 121 static PDBGFBP dbgfR3BpAlloc(PVM pVM, DBGFBPTYPE enmType) 122 { 123 /* 124 * Determine which array to search and where in the array to start 125 * searching (latter for grouping similar BPs, reducing runtime overhead). 126 */ 127 unsigned iStart; 128 unsigned cBps; 129 PDBGFBP paBps; 130 switch (enmType) 131 { 132 case DBGFBPTYPE_REG: 133 cBps = RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); 134 paBps = &pVM->dbgf.s.aHwBreakpoints[0]; 135 iStart = 0; 136 break; 137 138 case DBGFBPTYPE_INT3: 139 case DBGFBPTYPE_REM: 140 case DBGFBPTYPE_PORT_IO: 141 case DBGFBPTYPE_MMIO: 142 cBps = RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); 143 paBps = &pVM->dbgf.s.aBreakpoints[0]; 144 if (enmType == DBGFBPTYPE_PORT_IO) 145 iStart = cBps / 4 * 2; 146 else if (enmType == DBGFBPTYPE_MMIO) 147 iStart = cBps / 4 * 1; 148 else if (enmType == DBGFBPTYPE_REM) 149 iStart = cBps / 4 * 3; 150 else 151 iStart = 0; 152 break; 153 154 default: 155 AssertMsgFailed(("enmType=%d\n", enmType)); 156 return NULL; 157 } 158 159 /* 160 * Search for a free breakpoint entry. 161 */ 162 unsigned iBp; 163 for (iBp = iStart; iBp < cBps; iBp++) 164 if (paBps[iBp].enmType == DBGFBPTYPE_FREE) 165 break; 166 if (iBp >= cBps && iStart != 0) 167 for (iBp = 0; iBp < cBps; iBp++) 168 if (paBps[iBp].enmType == DBGFBPTYPE_FREE) 169 break; 170 if (iBp < cBps) 171 { 172 /* 173 * Return what we found. 174 */ 175 paBps[iBp].fEnabled = false; 176 paBps[iBp].cHits = 0; 177 paBps[iBp].enmType = enmType; 178 return &paBps[iBp]; 179 } 180 181 LogFlow(("dbgfR3BpAlloc: returns NULL - we're out of breakpoint slots! cBps=%u\n", cBps)); 182 return NULL; 183 } 184 185 186 /** 187 * Updates the search optimization structure for enabled breakpoints of the 188 * specified type. 189 * 190 * @returns VINF_SUCCESS. 191 * @param pVM The cross context VM structure. 192 * @param enmType The breakpoint type. 193 * @param pOpt The breakpoint optimization structure to update. 194 */ 195 static int dbgfR3BpUpdateSearchOptimizations(PVM pVM, DBGFBPTYPE enmType, PDBGFBPSEARCHOPT pOpt) 196 { 197 DBGFBPSEARCHOPT Opt = { UINT32_MAX, 0 }; 198 199 for (uint32_t iBp = 0; iBp < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); iBp++) 200 if ( pVM->dbgf.s.aBreakpoints[iBp].enmType == enmType 201 && pVM->dbgf.s.aBreakpoints[iBp].fEnabled) 202 { 203 if (Opt.iStartSearch > iBp) 204 Opt.iStartSearch = iBp; 205 Opt.cToSearch = iBp - Opt.iStartSearch + 1; 206 } 207 208 *pOpt = Opt; 209 return VINF_SUCCESS; 210 } 211 212 213 /** 214 * Get a breakpoint give by breakpoint id. 215 * 216 * @returns Pointer to the allocated breakpoint. 217 * @returns NULL if the breakpoint is invalid. 218 * @param pVM The cross context VM structure. 219 * @param iBp The breakpoint id. 220 */ 221 static PDBGFBP dbgfR3BpGet(PVM pVM, uint32_t iBp) 222 { 223 /* Find it. */ 224 PDBGFBP pBp; 225 if (iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints)) 226 pBp = &pVM->dbgf.s.aHwBreakpoints[iBp]; 227 else 228 { 229 iBp -= RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); 230 if (iBp >= RT_ELEMENTS(pVM->dbgf.s.aBreakpoints)) 231 return NULL; 232 pBp = &pVM->dbgf.s.aBreakpoints[iBp]; 233 } 234 235 /* check if it's valid. */ 236 switch (pBp->enmType) 237 { 238 case DBGFBPTYPE_FREE: 239 return NULL; 240 241 case DBGFBPTYPE_REG: 242 case DBGFBPTYPE_INT3: 243 case DBGFBPTYPE_REM: 244 case DBGFBPTYPE_PORT_IO: 245 case DBGFBPTYPE_MMIO: 246 break; 247 248 default: 249 AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType)); 250 return NULL; 251 } 252 253 return pBp; 254 } 255 256 257 /** 258 * Get a breakpoint give by address. 259 * 260 * @returns Pointer to the allocated breakpoint. 261 * @returns NULL if the breakpoint is invalid. 262 * @param pVM The cross context VM structure. 263 * @param enmType The breakpoint type. 264 * @param GCPtr The breakpoint address. 265 */ 266 static PDBGFBP dbgfR3BpGetByAddr(PVM pVM, DBGFBPTYPE enmType, RTGCUINTPTR GCPtr) 267 { 268 /* 269 * Determine which array to search. 270 */ 271 unsigned cBps; 272 PDBGFBP paBps; 273 switch (enmType) 274 { 275 case DBGFBPTYPE_REG: 276 cBps = RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); 277 paBps = &pVM->dbgf.s.aHwBreakpoints[0]; 278 break; 279 280 case DBGFBPTYPE_INT3: 281 case DBGFBPTYPE_REM: 282 cBps = RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); 283 paBps = &pVM->dbgf.s.aBreakpoints[0]; 284 break; 285 286 default: 287 AssertMsgFailed(("enmType=%d\n", enmType)); 288 return NULL; 289 } 290 291 /* 292 * Search. 293 */ 294 for (unsigned iBp = 0; iBp < cBps; iBp++) 295 if ( paBps[iBp].enmType == enmType 296 && paBps[iBp].u.GCPtr == GCPtr) 297 return &paBps[iBp]; 298 299 return NULL; 300 } 301 302 303 /** 304 * Frees a breakpoint. 305 * 306 * @param pVM The cross context VM structure. 307 * @param pBp The breakpoint to free. 308 */ 309 static void dbgfR3BpFree(PVM pVM, PDBGFBP pBp) 310 { 311 switch (pBp->enmType) 312 { 313 case DBGFBPTYPE_FREE: 314 AssertMsgFailed(("Already freed!\n")); 315 return; 316 317 case DBGFBPTYPE_REG: 318 Assert((uintptr_t)(pBp - &pVM->dbgf.s.aHwBreakpoints[0]) < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints)); 319 break; 320 321 case DBGFBPTYPE_INT3: 322 case DBGFBPTYPE_REM: 323 case DBGFBPTYPE_PORT_IO: 324 case DBGFBPTYPE_MMIO: 325 Assert((uintptr_t)(pBp - &pVM->dbgf.s.aBreakpoints[0]) < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints)); 326 break; 327 328 default: 329 AssertMsgFailed(("Invalid enmType=%d!\n", pBp->enmType)); 330 return; 331 332 } 333 pBp->enmType = DBGFBPTYPE_FREE; 334 NOREF(pVM); 335 } 336 337 338 /** 339 * @callback_method_impl{FNVMMEMTRENDEZVOUS} 340 */ 341 static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpEnableInt3OnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser) 342 { 343 /* 344 * Validate input. 345 */ 346 PDBGFBP pBp = (PDBGFBP)pvUser; 347 AssertReturn(pBp, VERR_INVALID_PARAMETER); 348 Assert(pBp->enmType == DBGFBPTYPE_INT3); 349 VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu); 350 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); 351 352 /* 353 * Arm the breakpoint. 354 */ 355 return dbgfR3BpInt3Arm(pVM, pBp); 356 } 357 358 359 /** 360 * @callback_method_impl{FNVMMEMTRENDEZVOUS} 361 */ 362 static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpSetInt3OnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser) 363 { 364 /* 365 * Validate input. 366 */ 367 PDBGFBPINT3ARGS pBpArgs = (PDBGFBPINT3ARGS)pvUser; 368 AssertReturn(pBpArgs, VERR_INVALID_PARAMETER); 369 VMCPU_ASSERT_EMT(pVCpu); 370 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); 371 372 AssertMsgReturn(!pBpArgs->piBp || VALID_PTR(pBpArgs->piBp), ("piBp=%p\n", pBpArgs->piBp), VERR_INVALID_POINTER); 373 PCDBGFADDRESS pAddress = pBpArgs->pAddress; 374 if (!DBGFR3AddrIsValid(pVM->pUVM, pAddress)) 375 return VERR_INVALID_PARAMETER; 376 377 if (pBpArgs->iHitTrigger > pBpArgs->iHitDisable) 378 return VERR_INVALID_PARAMETER; 379 380 /* 381 * Check if we're on the source CPU where we can resolve the breakpoint address. 382 */ 383 if (pVCpu->idCpu == pBpArgs->idSrcCpu) 384 { 385 if (pBpArgs->piBp) 386 *pBpArgs->piBp = UINT32_MAX; 387 388 /* 389 * Check if the breakpoint already exists. 390 */ 391 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_INT3, pAddress->FlatPtr); 392 if (pBp) 393 { 394 int rc = VINF_SUCCESS; 395 if (!pBp->fEnabled) 396 rc = dbgfR3BpInt3Arm(pVM, pBp); 397 if (RT_SUCCESS(rc)) 398 { 399 if (pBpArgs->piBp) 400 *pBpArgs->piBp = pBp->iBp; 401 402 /* 403 * Returning VINF_DBGF_BP_ALREADY_EXIST here causes a VBOXSTRICTRC out-of-range assertion 404 * in VMMR3EmtRendezvous(). Re-setting of an existing breakpoint shouldn't cause an assertion 405 * killing the VM (and debugging session), so for now we'll pretend success. 406 */ 407 #if 0 408 rc = VINF_DBGF_BP_ALREADY_EXIST; 409 #endif 410 } 411 else 412 dbgfR3BpFree(pVM, pBp); 413 return rc; 414 } 415 416 /* 417 * Allocate the breakpoint. 418 */ 419 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_INT3); 420 if (!pBp) 421 return VERR_DBGF_NO_MORE_BP_SLOTS; 422 423 /* 424 * Translate & save the breakpoint address into a guest-physical address. 425 */ 426 int rc = DBGFR3AddrToPhys(pVM->pUVM, pBpArgs->idSrcCpu, pAddress, &pBp->u.Int3.PhysAddr); 427 if (RT_SUCCESS(rc)) 428 { 429 /* The physical address from DBGFR3AddrToPhys() is the start of the page, 430 we need the exact byte offset into the page while writing to it in dbgfR3BpInt3Arm(). */ 431 pBp->u.Int3.PhysAddr |= (pAddress->FlatPtr & X86_PAGE_OFFSET_MASK); 432 pBp->u.Int3.GCPtr = pAddress->FlatPtr; 433 pBp->iHitTrigger = pBpArgs->iHitTrigger; 434 pBp->iHitDisable = pBpArgs->iHitDisable; 435 436 /* 437 * Now set the breakpoint in guest memory. 438 */ 439 rc = dbgfR3BpInt3Arm(pVM, pBp); 440 if (RT_SUCCESS(rc)) 441 { 442 if (pBpArgs->piBp) 443 *pBpArgs->piBp = pBp->iBp; 444 return VINF_SUCCESS; 445 } 446 } 447 448 dbgfR3BpFree(pVM, pBp); 449 return rc; 450 } 451 452 return VINF_SUCCESS; 233 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); 234 AssertReturn(hBpOwner != NIL_DBGFBPOWNER, VERR_INVALID_HANDLE); 235 236 return VERR_NOT_IMPLEMENTED; 453 237 } 454 238 … … 466 250 * @param iHitDisable The hit count which disables the breakpoint. 467 251 * Use ~(uint64_t) if it's never gonna be disabled. 468 * @param piBp Where to store the breakpoint id. (optional) 469 * @thread Any thread. 470 */ 471 VMMR3DECL(int) DBGFR3BpSetInt3(PUVM pUVM, VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, 472 uint32_t *piBp) 473 { 474 AssertReturn(idSrcCpu <= pUVM->cCpus, VERR_INVALID_CPU_ID); 475 476 DBGFBPINT3ARGS BpArgs; 477 RT_ZERO(BpArgs); 478 BpArgs.idSrcCpu = idSrcCpu; 479 BpArgs.iHitTrigger = iHitTrigger; 480 BpArgs.iHitDisable = iHitDisable; 481 BpArgs.pAddress = pAddress; 482 BpArgs.piBp = piBp; 483 484 int rc = VMMR3EmtRendezvous(pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpSetInt3OnCpu, &BpArgs); 485 LogFlow(("DBGFR3BpSet: returns %Rrc\n", rc)); 486 return rc; 487 } 488 489 490 /** 491 * Arms an int 3 breakpoint. 492 * 493 * This is used to implement both DBGFR3BpSetInt3() and 494 * DBGFR3BpEnable(). 495 * 496 * @returns VBox status code. 497 * @param pVM The cross context VM structure. 498 * @param pBp The breakpoint. 499 */ 500 static int dbgfR3BpInt3Arm(PVM pVM, PDBGFBP pBp) 501 { 502 VM_ASSERT_EMT(pVM); 503 504 /* 505 * Save current byte and write the int3 instruction byte. 506 */ 507 int rc = PGMPhysSimpleReadGCPhys(pVM, &pBp->u.Int3.bOrg, pBp->u.Int3.PhysAddr, sizeof(pBp->u.Int3.bOrg)); 508 if (RT_SUCCESS(rc)) 509 { 510 static const uint8_t s_bInt3 = 0xcc; 511 rc = PGMPhysSimpleWriteGCPhys(pVM, pBp->u.Int3.PhysAddr, &s_bInt3, sizeof(s_bInt3)); 512 if (RT_SUCCESS(rc)) 513 { 514 pBp->fEnabled = true; 515 dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_INT3, &pVM->dbgf.s.Int3); 516 pVM->dbgf.s.cEnabledInt3Breakpoints = pVM->dbgf.s.Int3.cToSearch; 517 Log(("DBGF: Set breakpoint at %RGv (Phys %RGp) cEnabledInt3Breakpoints=%u\n", pBp->u.Int3.GCPtr, 518 pBp->u.Int3.PhysAddr, pVM->dbgf.s.cEnabledInt3Breakpoints)); 519 } 520 } 521 return rc; 522 } 523 524 525 /** 526 * Disarms an int 3 breakpoint. 527 * 528 * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable(). 529 * 530 * @returns VBox status code. 531 * @param pVM The cross context VM structure. 532 * @param pBp The breakpoint. 533 */ 534 static int dbgfR3BpInt3Disarm(PVM pVM, PDBGFBP pBp) 535 { 536 VM_ASSERT_EMT(pVM); 537 538 /* 539 * Check that the current byte is the int3 instruction, and restore the original one. 540 * We currently ignore invalid bytes. 541 */ 542 uint8_t bCurrent = 0; 543 int rc = PGMPhysSimpleReadGCPhys(pVM, &bCurrent, pBp->u.Int3.PhysAddr, sizeof(bCurrent)); 544 if ( RT_SUCCESS(rc) 545 && bCurrent == 0xcc) 546 { 547 rc = PGMPhysSimpleWriteGCPhys(pVM, pBp->u.Int3.PhysAddr, &pBp->u.Int3.bOrg, sizeof(pBp->u.Int3.bOrg)); 548 if (RT_SUCCESS(rc)) 549 { 550 pBp->fEnabled = false; 551 dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_INT3, &pVM->dbgf.s.Int3); 552 pVM->dbgf.s.cEnabledInt3Breakpoints = pVM->dbgf.s.Int3.cToSearch; 553 Log(("DBGF: Removed breakpoint at %RGv (Phys %RGp) cEnabledInt3Breakpoints=%u\n", pBp->u.Int3.GCPtr, 554 pBp->u.Int3.PhysAddr, pVM->dbgf.s.cEnabledInt3Breakpoints)); 555 } 556 } 557 return rc; 558 } 559 560 561 /** 562 * @callback_method_impl{FNVMMEMTRENDEZVOUS} 563 */ 564 static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpDisableInt3OnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser) 565 { 566 /* 567 * Validate input. 568 */ 569 PDBGFBP pBp = (PDBGFBP)pvUser; 570 AssertReturn(pBp, VERR_INVALID_PARAMETER); 571 Assert(pBp->enmType == DBGFBPTYPE_INT3); 572 VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu); 573 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); 574 575 /* 576 * Disarm the breakpoint. 577 */ 578 return dbgfR3BpInt3Disarm(pVM, pBp); 252 * @param phBp Where to store the breakpoint handle on success. 253 * 254 * @thread Any thread. 255 */ 256 VMMR3DECL(int) DBGFR3BpSetInt3(PUVM pUVM, VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, 257 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp) 258 { 259 return DBGFR3BpSetInt3Ex(pUVM, NIL_DBGFBPOWNER, NULL /*pvUser*/, idSrcCpu, pAddress, 260 iHitTrigger, iHitDisable, phBp); 261 } 262 263 264 /** 265 * Sets a breakpoint (int 3 based) - extended version. 266 * 267 * @returns VBox status code. 268 * @param pUVM The user mode VM handle. 269 * @param hOwner The owner handle, use NIL_DBGFBPOWNER if no special owner attached. 270 * @param pvUser Opaque user data to pass in the owner callback. 271 * @param idSrcCpu The ID of the virtual CPU used for the 272 * breakpoint address resolution. 273 * @param pAddress The address of the breakpoint. 274 * @param iHitTrigger The hit count at which the breakpoint start triggering. 275 * Use 0 (or 1) if it's gonna trigger at once. 276 * @param iHitDisable The hit count which disables the breakpoint. 277 * Use ~(uint64_t) if it's never gonna be disabled. 278 * @param phBp Where to store the breakpoint handle on success. 279 * 280 * @thread Any thread. 281 */ 282 VMMR3DECL(int) DBGFR3BpSetInt3Ex(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, 283 VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, 284 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp) 285 { 286 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); 287 AssertReturn(hOwner != NIL_DBGFBPOWNER || pvUser != NULL, VERR_INVALID_PARAMETER); 288 AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER); 289 AssertReturn(iHitTrigger <= iHitDisable, VERR_INVALID_PARAMETER); 290 AssertPtrReturn(phBp, VERR_INVALID_POINTER); 291 292 RT_NOREF(idSrcCpu); 293 294 return VERR_NOT_IMPLEMENTED; 579 295 } 580 296 … … 586 302 * @param pUVM The user mode VM handle. 587 303 * @param pAddress The address of the breakpoint. 588 * @param piHitTriggerThe hit count at which the breakpoint start triggering.304 * @param iHitTrigger The hit count at which the breakpoint start triggering. 589 305 * Use 0 (or 1) if it's gonna trigger at once. 590 * @param piHitDisableThe hit count which disables the breakpoint.306 * @param iHitDisable The hit count which disables the breakpoint. 591 307 * Use ~(uint64_t) if it's never gonna be disabled. 592 308 * @param fType The access type (one of the X86_DR7_RW_* defines). 593 309 * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only. 594 310 * Must be 1 if fType is X86_DR7_RW_EO. 595 * @param piBp Where to store the breakpoint id. (optional) 596 * @thread EMT 597 * @internal 598 */ 599 static DECLCALLBACK(int) dbgfR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable, 600 uint8_t fType, uint8_t cb, uint32_t *piBp) 601 { 602 /* 603 * Validate input. 604 */ 605 PVM pVM = pUVM->pVM; 606 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); 607 if (!DBGFR3AddrIsValid(pUVM, pAddress)) 608 return VERR_INVALID_PARAMETER; 609 if (*piHitTrigger > *piHitDisable) 610 return VERR_INVALID_PARAMETER; 611 AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER); 612 if (piBp) 613 *piBp = UINT32_MAX; 311 * @param phBp Where to store the breakpoint handle. 312 * 313 * @thread Any thread. 314 */ 315 VMMR3DECL(int) DBGFR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, 316 uint64_t iHitDisable, uint8_t fType, uint8_t cb, PDBGFBP phBp) 317 { 318 return DBGFR3BpSetRegEx(pUVM, NIL_DBGFBPOWNER, NULL /*pvUser*/, pAddress, 319 iHitTrigger, iHitDisable, fType, cb, phBp); 320 } 321 322 323 /** 324 * Sets a register breakpoint - extended version. 325 * 326 * @returns VBox status code. 327 * @param pUVM The user mode VM handle. 328 * @param hOwner The owner handle, use NIL_DBGFBPOWNER if no special owner attached. 329 * @param pvUser Opaque user data to pass in the owner callback. 330 * @param pAddress The address of the breakpoint. 331 * @param iHitTrigger The hit count at which the breakpoint start triggering. 332 * Use 0 (or 1) if it's gonna trigger at once. 333 * @param iHitDisable The hit count which disables the breakpoint. 334 * Use ~(uint64_t) if it's never gonna be disabled. 335 * @param fType The access type (one of the X86_DR7_RW_* defines). 336 * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only. 337 * Must be 1 if fType is X86_DR7_RW_EO. 338 * @param phBp Where to store the breakpoint handle. 339 * 340 * @thread Any thread. 341 */ 342 VMMR3DECL(int) DBGFR3BpSetRegEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, 343 PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, 344 uint8_t fType, uint8_t cb, PDBGFBP phBp) 345 { 346 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); 347 AssertReturn(hOwner != NIL_DBGFBPOWNER || pvUser != NULL, VERR_INVALID_PARAMETER); 348 AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER); 349 AssertReturn(iHitTrigger <= iHitDisable, VERR_INVALID_PARAMETER); 350 AssertReturn(cb > 0 && cb <= 8 && RT_IS_POWER_OF_TWO(cb), VERR_INVALID_PARAMETER); 351 AssertPtrReturn(phBp, VERR_INVALID_POINTER); 614 352 switch (fType) 615 353 { … … 617 355 if (cb == 1) 618 356 break; 619 AssertMsgFailed(("fType=%#x cb=%d != 1\n", fType, cb)); 620 return VERR_INVALID_PARAMETER; 357 AssertMsgFailedReturn(("fType=%#x cb=%d != 1\n", fType, cb), VERR_INVALID_PARAMETER); 621 358 case X86_DR7_RW_IO: 622 359 case X86_DR7_RW_RW: … … 624 361 break; 625 362 default: 626 AssertMsgFailed(("fType=%#x\n", fType)); 627 return VERR_INVALID_PARAMETER; 363 AssertMsgFailedReturn(("fType=%#x\n", fType), VERR_INVALID_PARAMETER); 628 364 } 629 switch (cb) 630 { 631 case 1: 632 case 2: 633 case 4: 634 break; 635 default: 636 AssertMsgFailed(("cb=%#x\n", cb)); 637 return VERR_INVALID_PARAMETER; 638 } 639 640 /* 641 * Check if the breakpoint already exists. 642 */ 643 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REG, pAddress->FlatPtr); 644 if ( pBp 645 && pBp->u.Reg.cb == cb 646 && pBp->u.Reg.fType == fType) 647 { 648 int rc = VINF_SUCCESS; 649 if (!pBp->fEnabled) 650 rc = dbgfR3BpRegArm(pVM, pBp); 651 if (RT_SUCCESS(rc)) 652 { 653 rc = VINF_DBGF_BP_ALREADY_EXIST; 654 if (piBp) 655 *piBp = pBp->iBp; 656 } 657 return rc; 658 } 659 660 /* 661 * Allocate and initialize the bp. 662 */ 663 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REG); 664 if (!pBp) 665 return VERR_DBGF_NO_MORE_BP_SLOTS; 666 pBp->iHitTrigger = *piHitTrigger; 667 pBp->iHitDisable = *piHitDisable; 668 Assert(pBp->iBp == pBp->u.Reg.iReg); 669 pBp->u.Reg.GCPtr = pAddress->FlatPtr; 670 pBp->u.Reg.fType = fType; 671 pBp->u.Reg.cb = cb; 672 ASMCompilerBarrier(); 673 pBp->fEnabled = true; 674 675 /* 676 * Arm the breakpoint. 677 */ 678 int rc = dbgfR3BpRegArm(pVM, pBp); 679 if (RT_SUCCESS(rc)) 680 { 681 if (piBp) 682 *piBp = pBp->iBp; 683 } 684 else 685 dbgfR3BpFree(pVM, pBp); 686 687 return rc; 688 } 689 690 691 /** 692 * Sets a register breakpoint. 693 * 694 * @returns VBox status code. 695 * @param pUVM The user mode VM handle. 696 * @param pAddress The address of the breakpoint. 697 * @param iHitTrigger The hit count at which the breakpoint start triggering. 698 * Use 0 (or 1) if it's gonna trigger at once. 699 * @param iHitDisable The hit count which disables the breakpoint. 700 * Use ~(uint64_t) if it's never gonna be disabled. 701 * @param fType The access type (one of the X86_DR7_RW_* defines). 702 * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only. 703 * Must be 1 if fType is X86_DR7_RW_EO. 704 * @param piBp Where to store the breakpoint id. (optional) 705 * @thread Any thread. 706 */ 707 VMMR3DECL(int) DBGFR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, 708 uint8_t fType, uint8_t cb, uint32_t *piBp) 709 { 710 /* 711 * This must be done on EMT. 712 */ 713 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetReg, 7, 714 pUVM, pAddress, &iHitTrigger, &iHitDisable, fType, cb, piBp); 715 LogFlow(("DBGFR3BpSetReg: returns %Rrc\n", rc)); 716 return rc; 717 718 } 719 720 721 /** 722 * @callback_method_impl{FNVMMEMTRENDEZVOUS} 723 */ 724 static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpRegRecalcOnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser) 725 { 726 NOREF(pVM); NOREF(pvUser); 727 728 /* 729 * CPU 0 updates the enabled hardware breakpoint counts. 730 */ 731 if (pVCpu->idCpu == 0) 732 { 733 pVM->dbgf.s.cEnabledHwBreakpoints = 0; 734 pVM->dbgf.s.cEnabledHwIoBreakpoints = 0; 735 736 for (uint32_t iBp = 0; iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); iBp++) 737 if ( pVM->dbgf.s.aHwBreakpoints[iBp].fEnabled 738 && pVM->dbgf.s.aHwBreakpoints[iBp].enmType == DBGFBPTYPE_REG) 739 { 740 pVM->dbgf.s.cEnabledHwBreakpoints += 1; 741 pVM->dbgf.s.cEnabledHwIoBreakpoints += pVM->dbgf.s.aHwBreakpoints[iBp].u.Reg.fType == X86_DR7_RW_IO; 742 } 743 } 744 745 return CPUMRecalcHyperDRx(pVCpu, UINT8_MAX, false); 746 } 747 748 749 /** 750 * Arms a debug register breakpoint. 751 * 752 * This is used to implement both DBGFR3BpSetReg() and DBGFR3BpEnable(). 753 * 754 * @returns VBox status code. 755 * @param pVM The cross context VM structure. 756 * @param pBp The breakpoint. 757 * @thread EMT(0) 758 */ 759 static int dbgfR3BpRegArm(PVM pVM, PDBGFBP pBp) 760 { 761 RT_NOREF_PV(pBp); 762 Assert(pBp->fEnabled); 763 return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpRegRecalcOnCpu, NULL); 764 } 765 766 767 /** 768 * Disarms a debug register breakpoint. 769 * 770 * This is used to implement both DBGFR3BpClear() and DBGFR3BpDisable(). 771 * 772 * @returns VBox status code. 773 * @param pVM The cross context VM structure. 774 * @param pBp The breakpoint. 775 * @thread EMT(0) 776 */ 777 static int dbgfR3BpRegDisarm(PVM pVM, PDBGFBP pBp) 778 { 779 RT_NOREF_PV(pBp); 780 Assert(!pBp->fEnabled); 781 return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpRegRecalcOnCpu, NULL); 782 } 783 784 785 /** 786 * EMT worker for DBGFR3BpSetREM(). 787 * 788 * @returns VBox status code. 789 * @param pUVM The user mode VM handle. 790 * @param pAddress The address of the breakpoint. 791 * @param piHitTrigger The hit count at which the breakpoint start triggering. 792 * Use 0 (or 1) if it's gonna trigger at once. 793 * @param piHitDisable The hit count which disables the breakpoint. 794 * Use ~(uint64_t) if it's never gonna be disabled. 795 * @param piBp Where to store the breakpoint id. (optional) 796 * @thread EMT(0) 797 * @internal 798 */ 799 static DECLCALLBACK(int) dbgfR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, 800 uint64_t *piHitDisable, uint32_t *piBp) 801 { 802 /* 803 * Validate input. 804 */ 805 PVM pVM = pUVM->pVM; 806 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); 807 if (!DBGFR3AddrIsValid(pUVM, pAddress)) 808 return VERR_INVALID_PARAMETER; 809 if (*piHitTrigger > *piHitDisable) 810 return VERR_INVALID_PARAMETER; 811 AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER); 812 if (piBp) 813 *piBp = UINT32_MAX; 814 815 /* 816 * Check if the breakpoint already exists. 817 */ 818 PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REM, pAddress->FlatPtr); 819 if (pBp) 820 { 821 int rc = VINF_SUCCESS; 822 if (!pBp->fEnabled) 823 rc = IEMBreakpointSet(pVM, pBp->u.Rem.GCPtr); 824 if (RT_SUCCESS(rc)) 825 { 826 rc = VINF_DBGF_BP_ALREADY_EXIST; 827 if (piBp) 828 *piBp = pBp->iBp; 829 } 830 return rc; 831 } 832 833 /* 834 * Allocate and initialize the bp. 835 */ 836 pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REM); 837 if (!pBp) 838 return VERR_DBGF_NO_MORE_BP_SLOTS; 839 pBp->u.Rem.GCPtr = pAddress->FlatPtr; 840 pBp->iHitTrigger = *piHitTrigger; 841 pBp->iHitDisable = *piHitDisable; 842 ASMCompilerBarrier(); 843 pBp->fEnabled = true; 844 845 /* 846 * Now ask REM to set the breakpoint. 847 */ 848 int rc = IEMBreakpointSet(pVM, pAddress->FlatPtr); 849 if (RT_SUCCESS(rc)) 850 { 851 if (piBp) 852 *piBp = pBp->iBp; 853 } 854 else 855 dbgfR3BpFree(pVM, pBp); 856 857 return rc; 858 } 859 860 861 /** 862 * Sets a recompiler breakpoint. 863 * 864 * @returns VBox status code. 865 * @param pUVM The user mode VM handle. 866 * @param pAddress The address of the breakpoint. 867 * @param iHitTrigger The hit count at which the breakpoint start triggering. 868 * Use 0 (or 1) if it's gonna trigger at once. 869 * @param iHitDisable The hit count which disables the breakpoint. 870 * Use ~(uint64_t) if it's never gonna be disabled. 871 * @param piBp Where to store the breakpoint id. (optional) 872 * @thread Any thread. 873 */ 874 VMMR3DECL(int) DBGFR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp) 875 { 876 /* 877 * This must be done on EMT. 878 */ 879 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetREM, 5, 880 pUVM, pAddress, &iHitTrigger, &iHitDisable, piBp); 881 LogFlow(("DBGFR3BpSetREM: returns %Rrc\n", rc)); 882 return rc; 883 } 884 885 886 /** 887 * Updates IOM on whether we've got any armed I/O port or MMIO breakpoints. 888 * 889 * @returns VINF_SUCCESS 890 * @param pVM The cross context VM structure. 891 * @thread EMT(0) 892 */ 893 static int dbgfR3BpUpdateIom(PVM pVM) 894 { 895 dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_PORT_IO, &pVM->dbgf.s.PortIo); 896 if (pVM->dbgf.s.PortIo.cToSearch) 897 ASMAtomicBitSet(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_BREAKPOINT_IO); 898 else 899 ASMAtomicBitClear(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_BREAKPOINT_IO); 900 901 dbgfR3BpUpdateSearchOptimizations(pVM, DBGFBPTYPE_MMIO, &pVM->dbgf.s.Mmio); 902 if (pVM->dbgf.s.Mmio.cToSearch) 903 ASMAtomicBitSet(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_BREAKPOINT_MMIO); 904 else 905 ASMAtomicBitClear(&pVM->dbgf.s.bmSelectedEvents, DBGFEVENT_BREAKPOINT_MMIO); 906 907 IOMR3NotifyBreakpointCountChange(pVM, pVM->dbgf.s.PortIo.cToSearch != 0, pVM->dbgf.s.Mmio.cToSearch != 0); 908 return VINF_SUCCESS; 909 } 910 911 912 /** 913 * EMT worker for DBGFR3BpSetPortIo. 914 * 915 * @returns VBox status code. 916 * @param pUVM The user mode VM handle. 917 * @param uPort The first I/O port. 918 * @param cPorts The number of I/O ports. 919 * @param fAccess The access we want to break on. 920 * @param piHitTrigger The hit count at which the breakpoint start triggering. 921 * Use 0 (or 1) if it's gonna trigger at once. 922 * @param piHitDisable The hit count which disables the breakpoint. 923 * Use ~(uint64_t) if it's never gonna be disabled. 924 * @param piBp Where to store the breakpoint ID. 925 * @thread EMT(0) 926 */ 927 static DECLCALLBACK(int) dbgfR3BpSetPortIo(PUVM pUVM, RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess, 928 uint64_t const *piHitTrigger, uint64_t const *piHitDisable, uint32_t *piBp) 929 { 930 /* 931 * Validate input. 932 */ 933 PVM pVM = pUVM->pVM; 934 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); 935 *piBp = UINT32_MAX; 936 937 /* 938 * Check if the breakpoint already exists. 939 */ 940 for (uint32_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++) 941 if ( pVM->dbgf.s.aBreakpoints[i].enmType == DBGFBPTYPE_PORT_IO 942 && pVM->dbgf.s.aBreakpoints[i].u.PortIo.uPort == uPort 943 && pVM->dbgf.s.aBreakpoints[i].u.PortIo.cPorts == cPorts 944 && pVM->dbgf.s.aBreakpoints[i].u.PortIo.fAccess == fAccess) 945 { 946 if (!pVM->dbgf.s.aBreakpoints[i].fEnabled) 947 { 948 pVM->dbgf.s.aBreakpoints[i].fEnabled = true; 949 dbgfR3BpUpdateIom(pVM); 950 } 951 *piBp = pVM->dbgf.s.aBreakpoints[i].iBp; 952 return VINF_DBGF_BP_ALREADY_EXIST; 953 } 954 955 /* 956 * Allocate and initialize the breakpoint. 957 */ 958 PDBGFBP pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_PORT_IO); 959 if (!pBp) 960 return VERR_DBGF_NO_MORE_BP_SLOTS; 961 pBp->iHitTrigger = *piHitTrigger; 962 pBp->iHitDisable = *piHitDisable; 963 pBp->u.PortIo.uPort = uPort; 964 pBp->u.PortIo.cPorts = cPorts; 965 pBp->u.PortIo.fAccess = fAccess; 966 ASMCompilerBarrier(); 967 pBp->fEnabled = true; 968 969 /* 970 * Tell IOM. 971 */ 972 dbgfR3BpUpdateIom(pVM); 973 *piBp = pBp->iBp; 974 return VINF_SUCCESS; 365 366 return VERR_NOT_IMPLEMENTED; 367 } 368 369 370 /** 371 * This is only kept for now to not mess with the debugger implementation at this point, 372 * recompiler breakpoints are not supported anymore (IEM has some API but it isn't implemented 373 * and should probably be merged with the DBGF breakpoints). 374 */ 375 VMMR3DECL(int) DBGFR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, 376 uint64_t iHitDisable, PDBGFBP phBp) 377 { 378 RT_NOREF(pUVM, pAddress, iHitTrigger, iHitDisable, phBp); 379 return VERR_NOT_SUPPORTED; 975 380 } 976 381 … … 989 394 * @param iHitDisable The hit count which disables the breakpoint. 990 395 * Use ~(uint64_t) if it's never gonna be disabled. 991 * @param piBp Where to store the breakpoint ID. Optional. 992 * @thread Any thread. 993 */ 994 VMMR3DECL(int) DBGFR3BpSetPortIo(PUVM pUVM, RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess, 995 uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp) 996 { 396 * @param phBp Where to store the breakpoint handle. 397 * 398 * @thread Any thread. 399 */ 400 VMMR3DECL(int) DBGFR3BpSetPortIo(PUVM pUVM, RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess, 401 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp) 402 { 403 return DBGFR3BpSetPortIoEx(pUVM, NIL_DBGFBPOWNER, NULL /*pvUser*/, uPort, cPorts, 404 fAccess, iHitTrigger, iHitDisable, phBp); 405 } 406 407 408 /** 409 * Sets an I/O port breakpoint - extended version. 410 * 411 * @returns VBox status code. 412 * @param pUVM The user mode VM handle. 413 * @param hOwner The owner handle, use NIL_DBGFBPOWNER if no special owner attached. 414 * @param pvUser Opaque user data to pass in the owner callback. 415 * @param uPort The first I/O port. 416 * @param cPorts The number of I/O ports, see DBGFBPIOACCESS_XXX. 417 * @param fAccess The access we want to break on. 418 * @param iHitTrigger The hit count at which the breakpoint start 419 * triggering. Use 0 (or 1) if it's gonna trigger at 420 * once. 421 * @param iHitDisable The hit count which disables the breakpoint. 422 * Use ~(uint64_t) if it's never gonna be disabled. 423 * @param phBp Where to store the breakpoint handle. 424 * 425 * @thread Any thread. 426 */ 427 VMMR3DECL(int) DBGFR3BpSetPortIoEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, 428 RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess, 429 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp) 430 { 431 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); 432 AssertReturn(hOwner != NIL_DBGFBPOWNER || pvUser != NULL, VERR_INVALID_PARAMETER); 997 433 AssertReturn(!(fAccess & ~DBGFBPIOACCESS_VALID_MASK_PORT_IO), VERR_INVALID_FLAGS); 998 434 AssertReturn(fAccess, VERR_INVALID_FLAGS); 999 if (iHitTrigger > iHitDisable) 1000 return VERR_INVALID_PARAMETER; 1001 AssertPtrNullReturn(piBp, VERR_INVALID_POINTER); 435 AssertReturn(iHitTrigger <= iHitDisable, VERR_INVALID_PARAMETER); 436 AssertPtrReturn(phBp, VERR_INVALID_POINTER); 1002 437 AssertReturn(cPorts > 0, VERR_OUT_OF_RANGE); 1003 438 AssertReturn((RTIOPORT)(uPort + cPorts) < uPort, VERR_OUT_OF_RANGE); 1004 439 1005 /* 1006 * This must be done on EMT. 1007 */ 1008 uint32_t iBp = UINT32_MAX; 1009 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetPortIo, 7, 1010 pUVM, uPort, cPorts, fAccess, &iHitTrigger, &iHitDisable, piBp); 1011 if (piBp) 1012 *piBp = iBp; 1013 LogFlow(("DBGFR3BpSetPortIo: returns %Rrc iBp=%d\n", rc, iBp)); 1014 return rc; 1015 } 1016 1017 1018 /** 1019 * EMT worker for DBGFR3BpSetMmio. 1020 * 1021 * @returns VBox status code. 1022 * @param pUVM The user mode VM handle. 1023 * @param pGCPhys The start of the MMIO range to break on. 1024 * @param cb The size of the MMIO range. 1025 * @param fAccess The access we want to break on. 1026 * @param piHitTrigger The hit count at which the breakpoint start triggering. 1027 * Use 0 (or 1) if it's gonna trigger at once. 1028 * @param piHitDisable The hit count which disables the breakpoint. 1029 * Use ~(uint64_t) if it's never gonna be disabled. 1030 * @param piBp Where to store the breakpoint ID. 1031 * @thread EMT(0) 1032 */ 1033 static DECLCALLBACK(int) dbgfR3BpSetMmio(PUVM pUVM, PCRTGCPHYS pGCPhys, uint32_t cb, uint32_t fAccess, 1034 uint64_t const *piHitTrigger, uint64_t const *piHitDisable, uint32_t *piBp) 1035 { 1036 RTGCPHYS const GCPhys = *pGCPhys; 1037 1038 /* 1039 * Validate input. 1040 */ 1041 PVM pVM = pUVM->pVM; 1042 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); 1043 *piBp = UINT32_MAX; 1044 1045 /* 1046 * Check if the breakpoint already exists. 1047 */ 1048 for (uint32_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++) 1049 if ( pVM->dbgf.s.aBreakpoints[i].enmType == DBGFBPTYPE_MMIO 1050 && pVM->dbgf.s.aBreakpoints[i].u.Mmio.PhysAddr == GCPhys 1051 && pVM->dbgf.s.aBreakpoints[i].u.Mmio.cb == cb 1052 && pVM->dbgf.s.aBreakpoints[i].u.Mmio.fAccess == fAccess) 1053 { 1054 if (!pVM->dbgf.s.aBreakpoints[i].fEnabled) 1055 { 1056 pVM->dbgf.s.aBreakpoints[i].fEnabled = true; 1057 dbgfR3BpUpdateIom(pVM); 1058 } 1059 *piBp = pVM->dbgf.s.aBreakpoints[i].iBp; 1060 return VINF_DBGF_BP_ALREADY_EXIST; 1061 } 1062 1063 /* 1064 * Allocate and initialize the breakpoint. 1065 */ 1066 PDBGFBP pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_MMIO); 1067 if (!pBp) 1068 return VERR_DBGF_NO_MORE_BP_SLOTS; 1069 pBp->iHitTrigger = *piHitTrigger; 1070 pBp->iHitDisable = *piHitDisable; 1071 pBp->u.Mmio.PhysAddr = GCPhys; 1072 pBp->u.Mmio.cb = cb; 1073 pBp->u.Mmio.fAccess = fAccess; 1074 ASMCompilerBarrier(); 1075 pBp->fEnabled = true; 1076 1077 /* 1078 * Tell IOM. 1079 */ 1080 dbgfR3BpUpdateIom(pVM); 1081 *piBp = pBp->iBp; 1082 return VINF_SUCCESS; 440 return VERR_NOT_IMPLEMENTED; 1083 441 } 1084 442 … … 1097 455 * @param iHitDisable The hit count which disables the breakpoint. 1098 456 * Use ~(uint64_t) if it's never gonna be disabled. 1099 * @param piBp Where to store the breakpoint ID. Optional. 1100 * @thread Any thread. 1101 */ 1102 VMMR3DECL(int) DBGFR3BpSetMmio(PUVM pUVM, RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess, 1103 uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp) 1104 { 457 * @param phBp Where to store the breakpoint handle. 458 * 459 * @thread Any thread. 460 */ 461 VMMR3DECL(int) DBGFR3BpSetMmio(PUVM pUVM, RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess, 462 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp) 463 { 464 return DBGFR3BpSetMmioEx(pUVM, NIL_DBGFBPOWNER, NULL /*pvUser*/, GCPhys, cb, fAccess, 465 iHitTrigger, iHitDisable, phBp); 466 } 467 468 469 /** 470 * Sets a memory mapped I/O breakpoint - extended version. 471 * 472 * @returns VBox status code. 473 * @param pUVM The user mode VM handle. 474 * @param hOwner The owner handle, use NIL_DBGFBPOWNER if no special owner attached. 475 * @param pvUser Opaque user data to pass in the owner callback. 476 * @param GCPhys The first MMIO address. 477 * @param cb The size of the MMIO range to break on. 478 * @param fAccess The access we want to break on. 479 * @param iHitTrigger The hit count at which the breakpoint start 480 * triggering. Use 0 (or 1) if it's gonna trigger at 481 * once. 482 * @param iHitDisable The hit count which disables the breakpoint. 483 * Use ~(uint64_t) if it's never gonna be disabled. 484 * @param phBp Where to store the breakpoint handle. 485 * 486 * @thread Any thread. 487 */ 488 VMMR3DECL(int) DBGFR3BpSetMmioEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, 489 RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess, 490 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp) 491 { 492 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); 493 AssertReturn(hOwner != NIL_DBGFBPOWNER || pvUser != NULL, VERR_INVALID_PARAMETER); 1105 494 AssertReturn(!(fAccess & ~DBGFBPIOACCESS_VALID_MASK_MMIO), VERR_INVALID_FLAGS); 1106 495 AssertReturn(fAccess, VERR_INVALID_FLAGS); 1107 if (iHitTrigger > iHitDisable) 1108 return VERR_INVALID_PARAMETER; 1109 AssertPtrNullReturn(piBp, VERR_INVALID_POINTER); 496 AssertReturn(iHitTrigger <= iHitDisable, VERR_INVALID_PARAMETER); 497 AssertPtrReturn(phBp, VERR_INVALID_POINTER); 1110 498 AssertReturn(cb, VERR_OUT_OF_RANGE); 1111 499 AssertReturn(GCPhys + cb < GCPhys, VERR_OUT_OF_RANGE); 1112 500 501 return VERR_NOT_IMPLEMENTED; 502 } 503 504 505 /** 506 * Clears a breakpoint. 507 * 508 * @returns VBox status code. 509 * @param pUVM The user mode VM handle. 510 * @param hBp The handle of the breakpoint which should be removed (cleared). 511 * 512 * @thread Any thread. 513 */ 514 VMMR3DECL(int) DBGFR3BpClear(PUVM pUVM, DBGFBP hBp) 515 { 516 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); 517 AssertReturn(hBp != NIL_DBGFBPOWNER, VERR_INVALID_HANDLE); 518 519 return VERR_NOT_IMPLEMENTED; 520 } 521 522 523 /** 524 * Enables a breakpoint. 525 * 526 * @returns VBox status code. 527 * @param pUVM The user mode VM handle. 528 * @param hBp The handle of the breakpoint which should be enabled. 529 * 530 * @thread Any thread. 531 */ 532 VMMR3DECL(int) DBGFR3BpEnable(PUVM pUVM, DBGFBP hBp) 533 { 534 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); 535 AssertReturn(hBp != NIL_DBGFBPOWNER, VERR_INVALID_HANDLE); 536 537 return VERR_NOT_IMPLEMENTED; 538 } 539 540 541 /** 542 * Disables a breakpoint. 543 * 544 * @returns VBox status code. 545 * @param pUVM The user mode VM handle. 546 * @param hBp The handle of the breakpoint which should be disabled. 547 * 548 * @thread Any thread. 549 */ 550 VMMR3DECL(int) DBGFR3BpDisable(PUVM pUVM, DBGFBP hBp) 551 { 1113 552 /* 1114 * This must be done on EMT.553 * Validate the input. 1115 554 */ 1116 uint32_t iBp = UINT32_MAX; 1117 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpSetMmio, 7, 1118 pUVM, &GCPhys, cb, fAccess, &iHitTrigger, &iHitDisable, piBp); 1119 if (piBp) 1120 *piBp = iBp; 1121 LogFlow(("DBGFR3BpSetMmio: returns %Rrc iBp=%d\n", rc, iBp)); 1122 return rc; 1123 } 1124 1125 1126 /** 1127 * EMT worker for DBGFR3BpClear(). 1128 * 1129 * @returns VBox status code. 1130 * @param pUVM The user mode VM handle. 1131 * @param iBp The id of the breakpoint which should be removed (cleared). 1132 * @thread EMT(0) 1133 * @internal 1134 */ 1135 static DECLCALLBACK(int) dbgfR3BpClear(PUVM pUVM, uint32_t iBp) 1136 { 1137 /* 1138 * Validate input. 1139 */ 1140 PVM pVM = pUVM->pVM; 1141 VM_ASSERT_EMT(pVM); 1142 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); 1143 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp); 1144 if (!pBp) 1145 return VERR_DBGF_BP_NOT_FOUND; 1146 1147 /* 1148 * Disarm the breakpoint if it's enabled. 1149 */ 1150 if (pBp->fEnabled) 1151 { 1152 pBp->fEnabled = false; 1153 int rc; 1154 switch (pBp->enmType) 1155 { 1156 case DBGFBPTYPE_REG: 1157 rc = dbgfR3BpRegDisarm(pVM, pBp); 1158 break; 1159 1160 case DBGFBPTYPE_INT3: 1161 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpDisableInt3OnCpu, pBp); 1162 break; 1163 1164 case DBGFBPTYPE_REM: 1165 rc = IEMBreakpointClear(pVM, pBp->u.Rem.GCPtr); 1166 break; 1167 1168 case DBGFBPTYPE_PORT_IO: 1169 case DBGFBPTYPE_MMIO: 1170 rc = dbgfR3BpUpdateIom(pVM); 1171 break; 1172 1173 default: 1174 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE); 1175 } 1176 AssertRCReturn(rc, rc); 1177 } 1178 1179 /* 1180 * Free the breakpoint. 1181 */ 1182 dbgfR3BpFree(pVM, pBp); 1183 return VINF_SUCCESS; 1184 } 1185 1186 1187 /** 1188 * Clears a breakpoint. 1189 * 1190 * @returns VBox status code. 1191 * @param pUVM The user mode VM handle. 1192 * @param iBp The id of the breakpoint which should be removed (cleared). 1193 * @thread Any thread. 1194 */ 1195 VMMR3DECL(int) DBGFR3BpClear(PUVM pUVM, uint32_t iBp) 1196 { 1197 /* 1198 * This must be done on EMT. 1199 */ 1200 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpClear, 2, pUVM, iBp); 1201 LogFlow(("DBGFR3BpClear: returns %Rrc\n", rc)); 1202 return rc; 1203 } 1204 1205 1206 /** 1207 * EMT worker for DBGFR3BpEnable(). 1208 * 1209 * @returns VBox status code. 1210 * @param pUVM The user mode VM handle. 1211 * @param iBp The id of the breakpoint which should be enabled. 1212 * @thread EMT(0) 1213 * @internal 1214 */ 1215 static DECLCALLBACK(int) dbgfR3BpEnable(PUVM pUVM, uint32_t iBp) 1216 { 1217 /* 1218 * Validate input. 1219 */ 1220 PVM pVM = pUVM->pVM; 1221 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); 1222 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp); 1223 if (!pBp) 1224 return VERR_DBGF_BP_NOT_FOUND; 1225 1226 /* 1227 * Already enabled? 1228 */ 1229 if (pBp->fEnabled) 1230 return VINF_DBGF_BP_ALREADY_ENABLED; 1231 1232 /* 1233 * Arm the breakpoint. 1234 */ 1235 int rc; 1236 pBp->fEnabled = true; 1237 switch (pBp->enmType) 1238 { 1239 case DBGFBPTYPE_REG: 1240 rc = dbgfR3BpRegArm(pVM, pBp); 1241 break; 1242 1243 case DBGFBPTYPE_INT3: 1244 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpEnableInt3OnCpu, pBp); 1245 break; 1246 1247 case DBGFBPTYPE_REM: 1248 rc = IEMBreakpointSet(pVM, pBp->u.Rem.GCPtr); 1249 break; 1250 1251 case DBGFBPTYPE_PORT_IO: 1252 case DBGFBPTYPE_MMIO: 1253 rc = dbgfR3BpUpdateIom(pVM); 1254 break; 1255 1256 default: 1257 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE); 1258 } 1259 if (RT_FAILURE(rc)) 1260 pBp->fEnabled = false; 1261 1262 return rc; 1263 } 1264 1265 1266 /** 1267 * Enables a breakpoint. 1268 * 1269 * @returns VBox status code. 1270 * @param pUVM The user mode VM handle. 1271 * @param iBp The id of the breakpoint which should be enabled. 1272 * @thread Any thread. 1273 */ 1274 VMMR3DECL(int) DBGFR3BpEnable(PUVM pUVM, uint32_t iBp) 1275 { 1276 /* 1277 * This must be done on EMT. 1278 */ 1279 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpEnable, 2, pUVM, iBp); 1280 LogFlow(("DBGFR3BpEnable: returns %Rrc\n", rc)); 1281 return rc; 1282 } 1283 1284 1285 /** 1286 * EMT worker for DBGFR3BpDisable(). 1287 * 1288 * @returns VBox status code. 1289 * @param pUVM The user mode VM handle. 1290 * @param iBp The id of the breakpoint which should be disabled. 1291 * @thread EMT(0) 1292 * @internal 1293 */ 1294 static DECLCALLBACK(int) dbgfR3BpDisable(PUVM pUVM, uint32_t iBp) 1295 { 1296 /* 1297 * Validate input. 1298 */ 1299 PVM pVM = pUVM->pVM; 1300 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); 1301 PDBGFBP pBp = dbgfR3BpGet(pVM, iBp); 1302 if (!pBp) 1303 return VERR_DBGF_BP_NOT_FOUND; 1304 1305 /* 1306 * Already enabled? 1307 */ 1308 if (!pBp->fEnabled) 1309 return VINF_DBGF_BP_ALREADY_DISABLED; 1310 1311 /* 1312 * Remove the breakpoint. 1313 */ 1314 pBp->fEnabled = false; 1315 int rc; 1316 switch (pBp->enmType) 1317 { 1318 case DBGFBPTYPE_REG: 1319 rc = dbgfR3BpRegDisarm(pVM, pBp); 1320 break; 1321 1322 case DBGFBPTYPE_INT3: 1323 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, dbgfR3BpDisableInt3OnCpu, pBp); 1324 break; 1325 1326 case DBGFBPTYPE_REM: 1327 rc = IEMBreakpointClear(pVM, pBp->u.Rem.GCPtr); 1328 break; 1329 1330 case DBGFBPTYPE_PORT_IO: 1331 case DBGFBPTYPE_MMIO: 1332 rc = dbgfR3BpUpdateIom(pVM); 1333 break; 1334 1335 default: 1336 AssertMsgFailedReturn(("Invalid enmType=%d!\n", pBp->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE); 1337 } 1338 1339 return rc; 1340 } 1341 1342 1343 /** 1344 * Disables a breakpoint. 1345 * 1346 * @returns VBox status code. 1347 * @param pUVM The user mode VM handle. 1348 * @param iBp The id of the breakpoint which should be disabled. 1349 * @thread Any thread. 1350 */ 1351 VMMR3DECL(int) DBGFR3BpDisable(PUVM pUVM, uint32_t iBp) 1352 { 1353 /* 1354 * This must be done on EMT. 1355 */ 1356 int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3BpDisable, 2, pUVM, iBp); 1357 LogFlow(("DBGFR3BpDisable: returns %Rrc\n", rc)); 1358 return rc; 555 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); 556 AssertReturn(hBp != NIL_DBGFBPOWNER, VERR_INVALID_HANDLE); 557 558 return VERR_NOT_IMPLEMENTED; 1359 559 } 1360 560 … … 1367 567 * @param pfnCallback The callback function. 1368 568 * @param pvUser The user argument to pass to the callback. 569 * 1369 570 * @thread EMT 1370 571 * @internal … … 1379 580 AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER); 1380 581 1381 /* 1382 * Enumerate the hardware breakpoints. 1383 */ 1384 unsigned i; 1385 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++) 1386 if (pVM->dbgf.s.aHwBreakpoints[i].enmType != DBGFBPTYPE_FREE) 1387 { 1388 int rc = pfnCallback(pUVM, pvUser, &pVM->dbgf.s.aHwBreakpoints[i]); 1389 if (RT_FAILURE(rc) || rc == VINF_CALLBACK_RETURN) 1390 return rc; 1391 } 1392 1393 /* 1394 * Enumerate the other breakpoints. 1395 */ 1396 for (i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aBreakpoints); i++) 1397 if (pVM->dbgf.s.aBreakpoints[i].enmType != DBGFBPTYPE_FREE) 1398 { 1399 int rc = pfnCallback(pUVM, pvUser, &pVM->dbgf.s.aBreakpoints[i]); 1400 if (RT_FAILURE(rc) || rc == VINF_CALLBACK_RETURN) 1401 return rc; 1402 } 1403 1404 return VINF_SUCCESS; 582 RT_NOREF(pvUser); 583 584 return VERR_NOT_IMPLEMENTED; 1405 585 } 1406 586 … … 1413 593 * @param pfnCallback The callback function. 1414 594 * @param pvUser The user argument to pass to the callback. 595 * 1415 596 * @thread Any thread but the callback will be called from EMT. 1416 597 */ -
trunk/src/VBox/VMM/VMMRZ/DBGFRZ.cpp
r82968 r86666 69 69 for (unsigned iBp = 0; iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); iBp++) 70 70 { 71 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 71 72 if ( ((uint32_t)uDr6 & RT_BIT_32(iBp)) 72 73 && pVM->dbgf.s.aHwBreakpoints[iBp].enmType == DBGFBPTYPE_REG) … … 79 80 return fInHyper ? VINF_EM_DBG_HYPER_BREAKPOINT : VINF_EM_DBG_BREAKPOINT; 80 81 } 82 #else 83 if ( ((uint32_t)uDr6 & RT_BIT_32(iBp)) 84 && pVM->dbgf.s.aHwBreakpoints[iBp].hBp != NIL_DBGFBP) 85 { 86 pVCpu->dbgf.s.hBpActive = pVM->dbgf.s.aHwBreakpoints[iBp].hBp; 87 pVCpu->dbgf.s.fSingleSteppingRaw = false; 88 LogFlow(("DBGFRZTrap03Handler: hit hw breakpoint %x at %04x:%RGv\n", 89 pVM->dbgf.s.aHwBreakpoints[iBp].hBp, pRegFrame->cs.Sel, pRegFrame->rip)); 90 91 return fInHyper ? VINF_EM_DBG_HYPER_BREAKPOINT : VINF_EM_DBG_BREAKPOINT; 92 } 93 #endif 81 94 } 82 95 } … … 197 210 #endif 198 211 212 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 199 213 /* 200 214 * Get the trap address and look it up in the breakpoint table. … … 206 220 RTGCPTR pPc; 207 221 int rc = SELMValidateAndConvertCSAddr(pVCpu, pRegFrame->eflags, pRegFrame->ss.Sel, pRegFrame->cs.Sel, &pRegFrame->cs, 208 # ifdef IN_RC222 # ifdef IN_RC 209 223 pRegFrame->eip - 1, 210 # else224 # else 211 225 pRegFrame->rip /* no -1 in R0 */, 212 # endif226 # endif 213 227 &pPc); 214 228 AssertRCReturn(rc, rc); … … 233 247 } 234 248 } 249 #endif /* !VBOX_WITH_LOTS_OF_DBGF_BPS */ 235 250 236 251 return fInHyper -
trunk/src/VBox/VMM/include/DBGFInternal.h
r86098 r86666 747 747 748 748 749 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 749 750 /** 750 751 * Breakpoint search optimization. … … 761 762 /** Pointer to a breakpoint search optimziation structure. */ 762 763 typedef DBGFBPSEARCHOPT *PDBGFBPSEARCHOPT; 764 #else 765 /** 766 * Hardware breakpoint state. 767 */ 768 typedef struct DBGFBPHW 769 { 770 /** The flat GC address of the breakpoint. */ 771 RTGCUINTPTR GCPtr; 772 /** The breakpoint handle if active, NIL_DBGFBP if disabled. */ 773 DBGFBP hBp; 774 /** The access type (one of the X86_DR7_RW_* value). */ 775 uint8_t fType; 776 /** The access size. */ 777 uint8_t cb; 778 /** Flag whether the breakpoint is currently enabled. */ 779 bool fEnabled; 780 /** Padding. */ 781 uint8_t bPad; 782 } DBGFBPHW; 783 AssertCompileSize(DBGFBPHW, 16); 784 /** Pointer to a hardware breakpoint state. */ 785 typedef DBGFBPHW *PDBGFBPHW; 786 /** Pointer to a const hardware breakpoint state. */ 787 typedef const DBGFBPHW *PCDBGFBPHW; 788 #endif 763 789 764 790 … … 790 816 /** The number of enabled hardware I/O breakpoints. */ 791 817 uint8_t cEnabledHwIoBreakpoints; 818 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 792 819 /** The number of enabled INT3 breakpoints. */ 793 820 uint8_t cEnabledInt3Breakpoints; 794 821 uint8_t abPadding; /**< Unused padding space up for grabs. */ 822 #else 823 uint16_t u16Pad; 824 #endif 795 825 uint32_t uPadding; 796 826 … … 830 860 uint32_t u32Padding[2]; /**< Alignment padding. */ 831 861 862 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 832 863 /** Array of hardware breakpoints. (0..3) 833 864 * This is shared among all the CPUs because life is much simpler that way. */ … … 843 874 /** INT3 breakpoint search optimizations. */ 844 875 DBGFBPSEARCHOPT Int3; 876 #else 877 /** Array of hardware breakpoints (0..3). 878 * This is shared among all the CPUs because life is much simpler that way. */ 879 DBGFBPHW aHwBreakpoints[4]; 880 #endif 845 881 846 882 /** … … 907 943 uint32_t offVM; 908 944 945 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 909 946 /** Current active breakpoint (id). 910 947 * This is ~0U if not active. It is set when a execution engine … … 915 952 * @todo drop this in favor of aEvents! */ 916 953 uint32_t iActiveBp; 954 #else 955 /** Current active breakpoint handle. 956 * This is NIL_DBGFBP if not active. It is set when a execution engine 957 * encounters a breakpoint and returns VINF_EM_DBG_BREAKPOINT. 958 * 959 * @todo drop this in favor of aEvents! */ 960 DBGFBP hBpActive; 961 #endif 917 962 /** Set if we're singlestepping in raw mode. 918 963 * This is checked and cleared in the \#DB handler. */ … … 1092 1137 void dbgfR3AsTerm(PUVM pUVM); 1093 1138 void dbgfR3AsRelocate(PUVM pUVM, RTGCUINTPTR offDelta); 1139 #ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 1140 DECLHIDDEN(int) dbgfR3BpInit(PVM pVM); 1141 DECLHIDDEN(int) dbgfR3BpTerm(PVM pVM); 1142 #else 1094 1143 int dbgfR3BpInit(PVM pVM); 1144 #endif 1095 1145 int dbgfR3InfoInit(PUVM pUVM); 1096 1146 int dbgfR3InfoTerm(PUVM pUVM);
Note:
See TracChangeset
for help on using the changeset viewer.