Bug #831
closedvkernel can not access debug registers
0%
Description
I mistakenly pressed 'h' to get help in the vkernel ddb and got a bus error.
ddb interprets 'h' as 'hwatch' (set hardware watchpoint).  This calls
db_md_set_watchpoint() which in turn calls fill_dbregs().  The latter
tries to access debug registers which triggers a GPF as the vkernel
runs in user mode.
Using 'show registers' also results in a GPF for the same reason.
This patch removes debug register code from the vkernel.
Index: dfly/src/sys/platform/vkernel/i386/db_trace.c
===================================================================
--- dfly.orig/src/sys/platform/vkernel/i386/db_trace.c    2007-10-27
09:50:50.108742000 0200
++ dfly/src/sys/platform/vkernel/i386/db_trace.c    2007-10-27
09:51:38.000000000 +0200@ -50,14 +50,7 @
 #include <ddb/db_sym.h>
 #include <ddb/db_variables.h>
-db_varfcn_t db_dr0;
-db_varfcn_t db_dr1;
-db_varfcn_t db_dr2;
-db_varfcn_t db_dr3;
-db_varfcn_t db_dr4;
-db_varfcn_t db_dr5;
-db_varfcn_t db_dr6;
-db_varfcn_t db_dr7;
+static int db_dr(struct db_variable *vp, db_expr_t *valuep, int op);
/*
 * Machine register set.
@ -79,14 +72,14 @
    { "edi",    &ddb_regs.tf_edi,    FCN_NULL },
    { "eip",    &ddb_regs.tf_eip,    FCN_NULL },
    { "efl",    &ddb_regs.tf_eflags, FCN_NULL },
-    { "dr0",    NULL,             db_dr0 },
-    { "dr1",    NULL,             db_dr1 },
-    { "dr2",    NULL,             db_dr2 },
-    { "dr3",    NULL,             db_dr3 },
-    { "dr4",    NULL,             db_dr4 },
-    { "dr5",    NULL,             db_dr5 },
-    { "dr6",    NULL,             db_dr6 },
-    { "dr7",    NULL,             db_dr7 },
+    { "dr0",    NULL,             db_dr },
+    { "dr1",    NULL,             db_dr },
+    { "dr2",    NULL,             db_dr },
+    { "dr3",    NULL,             db_dr },
+    { "dr4",    NULL,             db_dr },
+    { "dr5",    NULL,             db_dr },
+    { "dr6",    NULL,             db_dr },
+    { "dr7",    NULL,             db_dr },
 };
 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);@ -112,10 +105,6 @
 static void    dl_symbol_values(int callpc, const char **name);
static char    *watchtype_str(int type);                               int size, int access, struct dbreg * d);
-static int    ki386_set_watch(int watchnum, unsigned int watchaddr,
-static int    ki386_clr_watch(int watchnum, struct dbreg * d);
 int        db_md_set_watchpoint(db_expr_t addr, db_expr_t size);
 int        db_md_clr_watchpoint(db_expr_t addr, db_expr_t size);
 void        db_md_list_watchpoints(void);@ -405,201 +394,30 @
     db_stack_trace_cmd(ebp, 1, -1, NULL);
 }
#define DB_DRX_FUNC(reg)                        \{                                    \
-int                                    \
-db_ ## reg (struct db_variable *vp, db_expr_t *valuep, int op)        \
-    if (op == DB_VAR_GET)                        \
-        *valuep = r ## reg ();                    \
-    else                                \
-        load_ ## reg (*valuep);                 \
-                                    \
-    return(0);                            \}DB_DRX_FUNC(dr0)
-DB_DRX_FUNC(dr1)
-DB_DRX_FUNC(dr2)
-DB_DRX_FUNC(dr3)
-DB_DRX_FUNC(dr4)
-DB_DRX_FUNC(dr5)
-DB_DRX_FUNC(dr6)
-DB_DRX_FUNC(dr7)
 static intki386_set_watch(int watchnum, unsigned int watchaddr, int size, int access,           struct dbreg *d)
+db_dr(struct db_variable *vp, db_expr_t *valuep, int op)
 {
-    int i;
-    unsigned int mask;
-    
-    if (watchnum == 1) {        for (i = 0, mask = 0x3; i < 4; i++, mask <<= 2)
-            if ((d->dr7 & mask) == 0)
-                break;
-        if (i < 4)
-            watchnum = i;
-        else
-            return(1);    }
-    
-    switch (access) {
-    case DBREG_DR7_EXEC:
-        size = 1; /* size must be 1 for an execution breakpoint /
-        / fall through /
-    case DBREG_DR7_WRONLY:
-    case DBREG_DR7_RDWR:
-        break;
-    default:
-        return(1);    }
-     * we can watch a 1, 2, or 4 byte sized location
-     /
-    switch (size) {
-    case 1:
-        mask = 0x00;
-        break;
-    case 2:
-        mask = 0x01 << 2;
-        break;
-    case 4:
-        mask = 0x03 << 2;
-        break;
-    default:
-        return(1);    }
-    d->dr7 &= ~((0x3 << (watchnum * 2)) | (0x0f << (watchnum * 4 + 16)));
-    DBREG_DRX(d, watchnum) = watchaddr;
-    d->dr7 |= (0x2 << (watchnum * 2)) | (mask << (watchnum * 4 + 16));
+    if (op == DB_VAR_GET)
+        *valuep = 0;
+    return(-1);
 }
-int
-ki386_clr_watch(int watchnum, struct dbreg *d)
-    if (watchnum < 0 || watchnum >= 4)
-        return(1);    
-    d->dr7 &= ~((0x3 << (watchnum * 2)) | (0x0f << (watchnum * 4 + 16)));
-    DBREG_DRX(d, watchnum) = 0;
-    
-    return(0);}
-
 int
 db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
 {
-    int avail, wsize;
-    int i;
-    struct dbreg d;
-    
-    fill_dbregs(NULL, &d);
-    
-    avail = 0;
-    for(i=0; i < 4; i++) {
-        if ((d.dr7 & (3 << (i * 2))) == 0)
-            avail++;
-    }
-    
-    if (avail * 4 < size)
-        return(1);    
-    for (i=0; i < 4 && (size != 0); i++) {
-        if ((d.dr7 & (3 << (i * 2))) == 0) {
-            if (size > 4)
-                wsize = 4;
-            else
-                wsize = size;
-            if (wsize == 3)
-                wsize++;
-            ki386_set_watch(i, addr, wsize, DBREG_DR7_WRONLY, &d);
-            addr = wsize;
-            size = wsize;        }
-    }
    return(-1);
 }
===================================================================
--- dfly.orig/src/sys/platform/vkernel/i386/cpu_regs.c    2007-10-27
09:50:50.109229000 0200
++ dfly/src/sys/platform/vkernel/i386/cpu_regs.c    2007-10-27
09:51:38.000000000 +0200@ -1056,115 +1056,13 @
 int
 fill_dbregs(struct lwp *lp, struct dbreg *dbregs)
 {
-        if (lp == NULL) {
-                dbregs->dr0 = rdr0();
-                dbregs->dr1 = rdr1();
-                dbregs->dr2 = rdr2();
-                dbregs->dr3 = rdr3();
-                dbregs->dr4 = rdr4();
-                dbregs->dr5 = rdr5();
-                dbregs->dr6 = rdr6();
-                dbregs->dr7 = rdr7();
-        } else {
-        struct pcb *pcb;
-                dbregs->dr0 = pcb->pcb_dr0;
-                dbregs->dr1 = pcb->pcb_dr1;
-                dbregs->dr2 = pcb->pcb_dr2;
-                dbregs->dr3 = pcb->pcb_dr3;
-                dbregs->dr4 = 0;
-                dbregs->dr5 = 0;
-                dbregs->dr6 = pcb->pcb_dr6;
-                dbregs->dr7 = pcb->pcb_dr7;
-        }
-    return (0);
+    return (ENOSYS);
 }
int
 set_dbregs(struct lwp *lp, struct dbreg *dbregs)
{
-    if (lp == NULL) {
-        load_dr0(dbregs->dr0);
-        load_dr1(dbregs->dr1);
-        load_dr2(dbregs->dr2);
-        load_dr3(dbregs->dr3);
-        load_dr4(dbregs->dr4);
-        load_dr5(dbregs->dr5);
-        load_dr6(dbregs->dr6);
-        load_dr7(dbregs->dr7);
-    } else {
-        struct pcb pcb;
-        struct ucred *ucred;
-        int i;
-        uint32_t mask1, mask2;
-         * Don't let an illegal value for dr7 get set.    Specifically,
-         * check for undefined settings.  Setting these bit patterns
-         * result in undefined behaviour and can lead to an unexpected
-         * TRCTRAP.
-         /
-        for (i = 0, mask1 = 0x3<<16, mask2 = 0x2<<16; i < 8;
-             i++, mask1 <<= 2, mask2 <<= 2)
-            if ((dbregs->dr7 & mask1) == mask2)
-                return (EINVAL);
-        
-        pcb = lp->lwp_thread->td_pcb;
-        ucred = lp->lwp_proc->p_ucred;
-         * Don't let a process set a breakpoint that is not within the
-         * process's address space.  If a process could do this, it
-         * could halt the system by setting a breakpoint in the kernel
-         * (if ddb was enabled).  Thus, we need to check to make sure
-         * that no breakpoints are being enabled for addresses outside
-         * process's address space, unless, perhaps, we were called by
-         * uid 0.
-         
-         * XXX - what about when the watched area of the user's
-         * address space is written into from within the kernel
-         * ... wouldn't that still cause a breakpoint to be generated
-         * from within kernel mode?
-         */
-            if (dbregs->dr7 & 0x3) {
-                / dr0 is enabled /
-                if (dbregs->dr0 >= VM_MAX_USER_ADDRESS)
-                    return (EINVAL);
-            }
-                / dr1 is enabled /
-                if (dbregs->dr1 >= VM_MAX_USER_ADDRESS)
-                    return (EINVAL);
-            }
-                / dr2 is enabled /
-                if (dbregs->dr2 >= VM_MAX_USER_ADDRESS)
-                    return (EINVAL);
-            }
-                / dr3 is enabled */
-                if (dbregs->dr3 >= VM_MAX_USER_ADDRESS)
-                    return (EINVAL);
-            }
-        }
-        pcb->pcb_dr1 = dbregs->dr1;
-        pcb->pcb_dr2 = dbregs->dr2;
-        pcb->pcb_dr3 = dbregs->dr3;
-        pcb->pcb_dr6 = dbregs->dr6;
-        pcb->pcb_dr7 = dbregs->dr7;
-    }
+    return (ENOSYS);
 }#if 0
       Updated by nthery almost 18 years ago
      Updated by nthery almost 18 years ago
      
    
    I'll commit this patch in a couple of days unless sbd complains.