VirtualBox

Changeset 97693 in vbox for trunk/src/VBox/VMM/VMMAll


Ignore:
Timestamp:
Nov 28, 2022 10:03:17 PM (2 years ago)
Author:
vboxsync
Message:

VMM/DBGF: Added a DBGFBpCheckInstruction function for checking for instruction breakpoint. bugref:9898

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/DBGFAll.cpp

    r96407 r97693  
    3131*********************************************************************************************************************************/
    3232#define LOG_GROUP LOG_GROUP_DBGF
     33#define VMCPU_INCL_CPUM_GST_CTX
    3334#include <VBox/vmm/dbgf.h>
    3435#include "DBGFInternal.h"
     36#include <VBox/vmm/cpum.h>
    3537#include <VBox/vmm/vmcc.h>
    3638#include <VBox/err.h>
     
    169171
    170172/**
    171  * Checks I/O access for guest or hypervisor breakpoints.
     173 * Checks instruction boundrary for guest or hypervisor hardware breakpoints.
     174 *
     175 * @returns Strict VBox status code.  May return DRx register import errors in
     176 *          addition to the ones detailed.
     177 * @retval  VINF_SUCCESS no breakpoint.
     178 * @retval  VINF_EM_DBG_BREAKPOINT hypervisor breakpoint triggered.
     179 * @retval  VINF_EM_RAW_GUEST_TRAP caller must trigger \#DB trap, DR6 and DR7
     180 *          have been updated appropriately.
     181 *
     182 * @param   pVM         The cross context VM structure.
     183 * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
     184 * @param   GCPtrPC     The unsegmented PC address.
     185 */
     186VMM_INT_DECL(VBOXSTRICTRC)  DBGFBpCheckInstruction(PVMCC pVM, PVMCPUCC pVCpu, RTGCPTR GCPtrPC)
     187{
     188    CPUM_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_DR7);
     189
     190    /*
     191     * Check hyper breakpoints first as the VMM debugger has priority over
     192     * the guest.
     193     */
     194    if (pVM->dbgf.s.cEnabledHwIoBreakpoints > 0)
     195        for (unsigned iBp = 0; iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); iBp++)
     196        {
     197            if (   pVM->dbgf.s.aHwBreakpoints[iBp].GCPtr != GCPtrPC
     198                || pVM->dbgf.s.aHwBreakpoints[iBp].fType != X86_DR7_RW_EO
     199                || pVM->dbgf.s.aHwBreakpoints[iBp].cb    != 1
     200                || !pVM->dbgf.s.aHwBreakpoints[iBp].fEnabled
     201                || pVM->dbgf.s.aHwBreakpoints[iBp].hBp   == NIL_DBGFBP)
     202            { /*likely*/ }
     203            else
     204            {
     205                /* (See also DBGFRZTrap01Handler.) */
     206                pVCpu->dbgf.s.hBpActive = pVM->dbgf.s.aHwBreakpoints[iBp].hBp;
     207                pVCpu->dbgf.s.fSingleSteppingRaw = false;
     208
     209                LogFlow(("DBGFBpCheckInstruction: hit hw breakpoint %u at %04x:%RGv (%RGv)\n",
     210                         iBp, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, GCPtrPC));
     211                return VINF_EM_DBG_BREAKPOINT;
     212            }
     213        }
     214
     215    /*
     216     * Check the guest.
     217     */
     218    uint32_t const fDr7 = (uint32_t)pVCpu->cpum.GstCtx.dr[7];
     219    if (X86_DR7_ANY_EO_ENABLED(fDr7))
     220    {
     221        /*
     222         * The CPU (10980XE & 6700K at least) will set the DR6.BPx bits for any
     223         * DRx that matches the current PC and is configured as an execution
     224         * breakpoint (RWx=EO, LENx=1byte).  They don't have to be enabled,
     225         * however one that is enabled must match for the #DB to be raised and
     226         * DR6 to be modified, of course.
     227         */
     228        CPUM_IMPORT_EXTRN_RET(pVCpu, CPUMCTX_EXTRN_DR0_DR3);
     229        uint32_t fMatched = 0;
     230        uint32_t fEnabled = 0;
     231        for (unsigned iBp = 0, iBpMask = 1; iBp < 4; iBp++, iBpMask <<= 1)
     232            if (X86_DR7_IS_EO_CFG(fDr7, iBp))
     233            {
     234                if (fDr7 & X86_DR7_L_G(iBp))
     235                    fEnabled |= iBpMask;
     236                if (pVCpu->cpum.GstCtx.dr[iBp] == GCPtrPC)
     237                    fMatched |= iBpMask;
     238            }
     239        if (!(fEnabled & fMatched))
     240        { /*likely*/ }
     241        else if (fEnabled & fMatched)
     242        {
     243            /*
     244             * Update DR6 and DR7.
     245             *
     246             * See "AMD64 Architecture Programmer's Manual Volume 2", chapter
     247             * 13.1.1.3 for details on DR6 bits.  The basics is that the B0..B3
     248             * bits are always cleared while the others must be cleared by software.
     249             *
     250             * The following sub chapters says the GD bit is always cleared when
     251             * generating a #DB so the handler can safely access the debug registers.
     252             */
     253            CPUM_IMPORT_EXTRN_RET(pVCpu, CPUMCTX_EXTRN_DR6);
     254            pVCpu->cpum.GstCtx.dr[6] &= ~X86_DR6_B_MASK;
     255            pVCpu->cpum.GstCtx.dr[6] |= fMatched;    /* All matched  */
     256            pVCpu->cpum.GstCtx.dr[7] &= ~X86_DR7_GD;
     257            LogFlow(("DBGFBpCheckInstruction: hit hw breakpoints %#x at %04x:%RGv (%RGv)\n",
     258                     fMatched, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, GCPtrPC));
     259            return VINF_EM_RAW_GUEST_TRAP;
     260        }
     261    }
     262    return VINF_SUCCESS;
     263}
     264
     265
     266/**
     267 * Checks I/O access for guest or hypervisor hardware breakpoints.
    172268 *
    173269 * @returns Strict VBox status code
Note: See TracChangeset for help on using the changeset viewer.

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