diff options
author | aiju <devnull@localhost> | 2017-06-12 19:03:07 +0000 |
---|---|---|
committer | aiju <devnull@localhost> | 2017-06-12 19:03:07 +0000 |
commit | 773be02aa18095e857c6659416d84951ceb60d41 (patch) | |
tree | 26daede4230e14d46d42efbcd6eab8e68adc7687 | |
parent | 1cfa405d0a272cbd7df22d4b9767eb57e21cc21f (diff) |
kernel: add support for hardware watchpoints
-rw-r--r-- | sys/src/9/bcm/main.c | 7 | ||||
-rw-r--r-- | sys/src/9/kw/main.c | 7 | ||||
-rw-r--r-- | sys/src/9/mtx/main.c | 7 | ||||
-rw-r--r-- | sys/src/9/omap/main.c | 7 | ||||
-rw-r--r-- | sys/src/9/pc/dat.h | 3 | ||||
-rw-r--r-- | sys/src/9/pc/devarch.c | 78 | ||||
-rw-r--r-- | sys/src/9/pc/fns.h | 4 | ||||
-rw-r--r-- | sys/src/9/pc/io.h | 1 | ||||
-rw-r--r-- | sys/src/9/pc/l.s | 32 | ||||
-rw-r--r-- | sys/src/9/pc/main.c | 11 | ||||
-rw-r--r-- | sys/src/9/pc/trap.c | 31 | ||||
-rw-r--r-- | sys/src/9/pc64/dat.h | 3 | ||||
-rw-r--r-- | sys/src/9/pc64/fns.h | 4 | ||||
-rw-r--r-- | sys/src/9/pc64/l.s | 29 | ||||
-rw-r--r-- | sys/src/9/pc64/main.c | 6 | ||||
-rw-r--r-- | sys/src/9/pc64/trap.c | 31 | ||||
-rw-r--r-- | sys/src/9/port/devproc.c | 162 | ||||
-rw-r--r-- | sys/src/9/port/portdat.h | 14 | ||||
-rw-r--r-- | sys/src/9/port/portfns.h | 1 | ||||
-rw-r--r-- | sys/src/9/port/proc.c | 4 | ||||
-rw-r--r-- | sys/src/9/ppc/main.c | 7 | ||||
-rw-r--r-- | sys/src/9/sgi/main.c | 7 | ||||
-rw-r--r-- | sys/src/9/teg2/main.c | 7 | ||||
-rw-r--r-- | sys/src/9/zynq/main.c | 7 |
24 files changed, 465 insertions, 5 deletions
diff --git a/sys/src/9/bcm/main.c b/sys/src/9/bcm/main.c index 36ca703b7..69fb61bb1 100644 --- a/sys/src/9/bcm/main.c +++ b/sys/src/9/bcm/main.c @@ -584,3 +584,10 @@ cmpswap(long *addr, long old, long new) { return cas32(addr, old, new); } + +void +setupwatchpts(Proc *, Watchpt *, int n) +{ + if(n > 0) + error("no watchpoints"); +} diff --git a/sys/src/9/kw/main.c b/sys/src/9/kw/main.c index 8d16c0b43..f2bc302db 100644 --- a/sys/src/9/kw/main.c +++ b/sys/src/9/kw/main.c @@ -638,3 +638,10 @@ cmpswap(long *addr, long old, long new) { return cas32(addr, old, new); } + +void +setupwatchpts(Proc *, Watchpt *, int n) +{ + if(n > 0) + error("no watchpoints"); +} diff --git a/sys/src/9/mtx/main.c b/sys/src/9/mtx/main.c index 1ce07155b..564a197d7 100644 --- a/sys/src/9/mtx/main.c +++ b/sys/src/9/mtx/main.c @@ -436,3 +436,10 @@ cistrncmp(char *a, char *b, int n) return 0; } + +void +setupwatchpts(Proc *, Watchpt *, int n) +{ + if(n > 0) + error("no watchpoints"); +} diff --git a/sys/src/9/omap/main.c b/sys/src/9/omap/main.c index f16ca5d6d..6ff256f34 100644 --- a/sys/src/9/omap/main.c +++ b/sys/src/9/omap/main.c @@ -654,3 +654,10 @@ cmpswap(long *addr, long old, long new) { return cas32(addr, old, new); } + +void +setupwatchpts(Proc *, Watchpt *, int n) +{ + if(n > 0) + error("no watchpoints"); +} diff --git a/sys/src/9/pc/dat.h b/sys/src/9/pc/dat.h index 35bf8b4d6..14f406389 100644 --- a/sys/src/9/pc/dat.h +++ b/sys/src/9/pc/dat.h @@ -159,6 +159,8 @@ struct PMMU Segdesc gdt[NPROCSEG]; /* per process descriptors */ Segdesc *ldt; /* local descriptor table */ int nldt; /* number of ldt descriptors allocated */ + + u32int dr[8]; /* debug registers */ }; /* @@ -252,6 +254,7 @@ struct Mach char* cpuidtype; int havetsc; int havepge; + int havewatchpt8; uvlong tscticks; int pdballoc; int pdbfree; diff --git a/sys/src/9/pc/devarch.c b/sys/src/9/pc/devarch.c index 7870ad6d4..0523ce84e 100644 --- a/sys/src/9/pc/devarch.c +++ b/sys/src/9/pc/devarch.c @@ -49,6 +49,9 @@ enum { /* cpuid standard function codes */ Procsig, Proctlbcache, Procserial, + + Highextfunc = 0x80000000, + Procextfeat, }; typedef long Rdwrfn(Chan*, void*, long, vlong); @@ -874,6 +877,23 @@ cpuidentify(void) hwrandbuf = rdrandbuf; else hwrandbuf = nil; + + /* 8-byte watchpoints are supported in Long Mode */ + if(sizeof(uintptr) == 8) + m->havewatchpt8 = 1; + else if(strcmp(m->cpuidid, "GenuineIntel") == 0){ + /* some random CPUs that support 8-byte watchpoints */ + if(family == 15 && (model == 3 || model == 4 || model == 6) + || family == 6 && (model == 15 || model == 23 || model == 28)) + m->havewatchpt8 = 1; + /* Intel SDM claims amd64 support implies 8-byte watchpoint support */ + cpuid(Highextfunc, regs); + if(regs[0] >= Procextfeat){ + cpuid(Procextfeat, regs); + if((regs[3] & 1<<29) != 0) + m->havewatchpt8 = 1; + } + } cputype = t; return t->family; @@ -1229,3 +1249,61 @@ dumpmcregs(void) iprint("\n"); } } + +void +setupwatchpts(Proc *pr, Watchpt *wp, int nwp) +{ + int i; + u8int cfg; + Watchpt *p; + + if(nwp > 4) + error("there are four watchpoints."); + if(nwp == 0){ + memset(pr->dr, 0, sizeof(pr->dr)); + return; + } + for(p = wp; p < wp + nwp; p++){ + switch(p->type){ + case WATCHRD|WATCHWR: case WATCHWR: + break; + case WATCHEX: + if(p->len != 1) + error("length must be 1 on breakpoints"); + break; + default: + error("type must be rw-, -w- or --x"); + } + switch(p->len){ + case 1: case 2: case 4: + break; + case 8: + if(m->havewatchpt8) break; + default: + error(m->havewatchpt8 ? "length must be 1,2,4,8" : "length must be 1,2,4"); + } + if((p->addr & p->len - 1) != 0) + error("address must be aligned according to length"); + } + + memset(pr->dr, 0, sizeof(pr->dr)); + pr->dr[6] = 0xffff8ff0; + for(i = 0; i < nwp; i++){ + pr->dr[i] = wp[i].addr; + switch(wp[i].type){ + case WATCHRD|WATCHWR: cfg = 3; break; + case WATCHWR: cfg = 1; break; + case WATCHEX: cfg = 0; break; + default: continue; + } + switch(wp[i].len){ + case 1: break; + case 2: cfg |= 4; break; + case 4: cfg |= 12; break; + case 8: cfg |= 8; break; + default: continue; + } + pr->dr[7] |= cfg << 16 + 4 * i; + pr->dr[7] |= 1 << 2 * i + 1; + } +} diff --git a/sys/src/9/pc/fns.h b/sys/src/9/pc/fns.h index 13c390bd4..7b91ed4df 100644 --- a/sys/src/9/pc/fns.h +++ b/sys/src/9/pc/fns.h @@ -51,6 +51,7 @@ ulong getcr0(void); ulong getcr2(void); ulong getcr3(void); ulong getcr4(void); +u32int getdr6(void); char* getconf(char*); void guesscpuhz(int); void halt(void); @@ -165,6 +166,9 @@ void procfork(Proc*); void putcr0(ulong); void putcr3(ulong); void putcr4(ulong); +void putdr(u32int*); +void putdr6(u32int); +void putdr7(u32int); void* rampage(void); int rdmsr(int, vlong*); void realmode(Ureg*); diff --git a/sys/src/9/pc/io.h b/sys/src/9/pc/io.h index a17826671..2bcba0c36 100644 --- a/sys/src/9/pc/io.h +++ b/sys/src/9/pc/io.h @@ -4,6 +4,7 @@ #define X86FAMILY(x) ((((x)>>8) & 0x0F) | (((x)>>20) & 0xFF)<<4) enum { + VectorDE = 1, /* debug exception */ VectorNMI = 2, /* non-maskable interrupt */ VectorBPT = 3, /* breakpoint */ VectorUD = 6, /* invalid opcode exception */ diff --git a/sys/src/9/pc/l.s b/sys/src/9/pc/l.s index 40b05519f..600188b62 100644 --- a/sys/src/9/pc/l.s +++ b/sys/src/9/pc/l.s @@ -845,6 +845,38 @@ _rndbytes: _rnddone: RET +/* debug register access */ + +TEXT putdr(SB), $0 + MOVL p+0(FP), SI + MOVL 28(SI), AX + MOVL AX, DR7 + MOVL 0(SI), AX + MOVL AX, DR0 + MOVL 4(SI), AX + MOVL AX, DR1 + MOVL 8(SI), AX + MOVL AX, DR2 + MOVL 12(SI), AX + MOVL AX, DR3 + MOVL 24(SI), AX + MOVL AX, DR6 + RET + +TEXT getdr6(SB), $0 + MOVL DR6, AX + RET + +TEXT putdr6(SB), $0 + MOVL p+0(FP), AX + MOVL AX, DR6 + RET + +TEXT putdr7(SB), $0 + MOVL p+0(FP), AX + MOVL AX, DR7 + RET + /* * Used to get to the first process: * set up an interrupt return frame and IRET to user level. diff --git a/sys/src/9/pc/main.c b/sys/src/9/pc/main.c index 18586cacc..bb4422325 100644 --- a/sys/src/9/pc/main.c +++ b/sys/src/9/pc/main.c @@ -801,6 +801,8 @@ procsetup(Proc *p) memset(p->gdt, 0, sizeof(p->gdt)); p->ldt = nil; p->nldt = 0; + + memset(p->dr, 0, sizeof(p->dr)); } void @@ -831,6 +833,9 @@ procfork(Proc *p) p->fpsave = up->fpsave; p->fpstate = FPinactive; } + + /* clear debug registers */ + memset(p->dr, 0, sizeof(p->dr)); splx(s); } @@ -838,6 +843,9 @@ void procrestore(Proc *p) { uvlong t; + + if(p->dr[7] != 0) + putdr(p->dr); if(p->kp) return; @@ -854,6 +862,9 @@ void procsave(Proc *p) { uvlong t; + + if(p->dr[7] != 0) + putdr7(0); cycles(&t); p->kentry -= t; diff --git a/sys/src/9/pc/trap.c b/sys/src/9/pc/trap.c index 3fa728975..b7877563d 100644 --- a/sys/src/9/pc/trap.c +++ b/sys/src/9/pc/trap.c @@ -13,6 +13,7 @@ static int trapinited; void noted(Ureg*, ulong); +static void debugexc(Ureg*, void*); static void debugbpt(Ureg*, void*); static void fault386(Ureg*, void*); static void doublefault(Ureg*, void*); @@ -222,6 +223,7 @@ trapinit(void) * Special traps. * Syscall() is called directly without going through trap(). */ + trapenable(VectorDE, debugexc, 0, "debugexc"); trapenable(VectorBPT, debugbpt, 0, "debugpt"); trapenable(VectorPF, fault386, 0, "fault386"); trapenable(Vector2F, doublefault, 0, "doublefault"); @@ -627,6 +629,35 @@ dumpstack(void) } static void +debugexc(Ureg *, void *) +{ + u32int dr6, m; + char buf[ERRMAX]; + char *p, *e; + int i; + + dr6 = getdr6(); + if(up == nil) + panic("kernel debug exception dr6=%#.8ux", dr6); + putdr6(up->dr[6]); + m = up->dr[7]; + m = (m >> 4 | m >> 3) & 8 | (m >> 3 | m >> 2) & 4 | (m >> 2 | m >> 1) & 2 | (m >> 1 | m) & 1; + m &= dr6; + if(m == 0){ + sprint(buf, "sys: debug exception dr6=%#.8ux", dr6); + postnote(up, 1, buf, NDebug); + }else{ + p = buf; + e = buf + sizeof(buf); + p = seprint(p, e, "sys: watchpoint "); + for(i = 0; i < 4; i++) + if((m & 1<<i) != 0) + p = seprint(p, e, "%d%s", i, (m >> i + 1 != 0) ? "," : ""); + postnote(up, 1, buf, NDebug); + } +} + +static void debugbpt(Ureg* ureg, void*) { char buf[ERRMAX]; diff --git a/sys/src/9/pc64/dat.h b/sys/src/9/pc64/dat.h index 2a5029ca8..1f7a4717c 100644 --- a/sys/src/9/pc64/dat.h +++ b/sys/src/9/pc64/dat.h @@ -144,6 +144,8 @@ struct PMMU ulong kmapcount; ulong kmapindex; ulong mmucount; + + u64int dr[8]; }; /* @@ -219,6 +221,7 @@ struct Mach char* cpuidtype; int havetsc; int havepge; + int havewatchpt8; uvlong tscticks; uintptr stack[1]; diff --git a/sys/src/9/pc64/fns.h b/sys/src/9/pc64/fns.h index 41e3380ec..6db652674 100644 --- a/sys/src/9/pc64/fns.h +++ b/sys/src/9/pc64/fns.h @@ -44,6 +44,7 @@ u64int getcr0(void); u64int getcr2(void); u64int getcr3(void); u64int getcr4(void); +u64int getdr6(void); char* getconf(char*); void guesscpuhz(int); void halt(void); @@ -158,6 +159,9 @@ void procfork(Proc*); void putcr0(u64int); void putcr3(u64int); void putcr4(u64int); +void putdr(u64int*); +void putdr6(u64int); +void putdr7(u64int); void* rampage(void); int rdmsr(int, vlong*); void realmode(Ureg*); diff --git a/sys/src/9/pc64/l.s b/sys/src/9/pc64/l.s index cb3cb343e..c5b95dd3e 100644 --- a/sys/src/9/pc64/l.s +++ b/sys/src/9/pc64/l.s @@ -692,6 +692,35 @@ ones: f3: RET +/* debug register access */ + +TEXT putdr(SB), $0 + MOVQ 56(BP), AX + MOVQ AX, DR7 + MOVQ 0(BP), AX + MOVQ AX, DR0 + MOVQ 8(BP), AX + MOVQ AX, DR1 + MOVQ 16(BP), AX + MOVQ AX, DR2 + MOVQ 24(BP), AX + MOVQ AX, DR3 + MOVQ 48(BP), AX + MOVQ AX, DR6 + RET + +TEXT getdr6(SB), $0 + MOVQ DR6, AX + RET + +TEXT putdr6(SB), $0 + MOVQ BP, DR6 + RET + +TEXT putdr7(SB), $0 + MOVQ BP, DR7 + RET + /* */ TEXT touser(SB), 1, $-4 diff --git a/sys/src/9/pc64/main.c b/sys/src/9/pc64/main.c index e1534e9b7..ea920fe56 100644 --- a/sys/src/9/pc64/main.c +++ b/sys/src/9/pc64/main.c @@ -797,6 +797,9 @@ void procrestore(Proc *p) { uvlong t; + + if(p->dr[7] != 0) + putdr(p->dr); if(p->kp) return; @@ -810,6 +813,9 @@ void procsave(Proc *p) { uvlong t; + + if(p->dr[7] != 0) + putdr7(0); cycles(&t); p->kentry -= t; diff --git a/sys/src/9/pc64/trap.c b/sys/src/9/pc64/trap.c index 4c64d201e..5ac1b0d6b 100644 --- a/sys/src/9/pc64/trap.c +++ b/sys/src/9/pc64/trap.c @@ -13,6 +13,7 @@ static int trapinited; void noted(Ureg*, ulong); +static void debugexc(Ureg*, void*); static void debugbpt(Ureg*, void*); static void faultamd64(Ureg*, void*); static void doublefault(Ureg*, void*); @@ -224,6 +225,7 @@ trapinit(void) * Special traps. * Syscall() is called directly without going through trap(). */ + trapenable(VectorDE, debugexc, 0, "debugexc"); trapenable(VectorBPT, debugbpt, 0, "debugpt"); trapenable(VectorPF, faultamd64, 0, "faultamd64"); trapenable(Vector2F, doublefault, 0, "doublefault"); @@ -588,6 +590,35 @@ dumpstack(void) } static void +debugexc(Ureg *, void *) +{ + u64int dr6, m; + char buf[ERRMAX]; + char *p, *e; + int i; + + dr6 = getdr6(); + if(up == nil) + panic("kernel debug exception dr6=%#.8ullx", dr6); + putdr6(up->dr[6]); + m = up->dr[7]; + m = (m >> 4 | m >> 3) & 8 | (m >> 3 | m >> 2) & 4 | (m >> 2 | m >> 1) & 2 | (m >> 1 | m) & 1; + m &= dr6; + if(m == 0){ + sprint(buf, "sys: debug exception dr6=%#.8ullx", dr6); + postnote(up, 1, buf, NDebug); + }else{ + p = buf; + e = buf + sizeof(buf); + p = seprint(p, e, "sys: watchpoint "); + for(i = 0; i < 4; i++) + if((m & 1<<i) != 0) + p = seprint(p, e, "%d%s", i, (m >> i + 1 != 0) ? "," : ""); + postnote(up, 1, buf, NDebug); + } +} + +static void debugbpt(Ureg* ureg, void*) { char buf[ERRMAX]; diff --git a/sys/src/9/port/devproc.c b/sys/src/9/port/devproc.c index b6b51959c..d960d0eec 100644 --- a/sys/src/9/port/devproc.c +++ b/sys/src/9/port/devproc.c @@ -34,6 +34,7 @@ enum Qwait, Qprofile, Qsyscall, + Qwatchpt, }; enum @@ -101,6 +102,7 @@ Dirtab procdir[] = "wait", {Qwait}, 0, 0400, "profile", {Qprofile}, 0, 0400, "syscall", {Qsyscall}, 0, 0400, + "watchpt", {Qwatchpt}, 0, 0600, }; static @@ -181,6 +183,8 @@ profclock(Ureg *ur, Timer *) } } +static int lenwatchpt(Proc *); + static int procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp) { @@ -265,6 +269,11 @@ procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp) } break; } + switch(QID(tab->qid)){ + case Qwatchpt: + len = lenwatchpt(p); + break; + } mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE); devdir(c, qid, tab->name, len, p->user, perm, dp); @@ -334,19 +343,22 @@ nonone(Proc *p) error(Eperm); } +static void clearwatchpt(Proc *p); + static Chan* -procopen(Chan *c, int omode) +procopen(Chan *c, int omode0) { Proc *p; Pgrp *pg; Chan *tc; int pid; + int omode; if(c->qid.type & QTDIR) - return devopen(c, omode, 0, 0, procgen); + return devopen(c, omode0, 0, 0, procgen); if(QID(c->qid) == Qtrace){ - if (omode != OREAD) + if (omode0 != OREAD) error(Eperm); lock(&tlock); if (waserror()){ @@ -366,7 +378,7 @@ procopen(Chan *c, int omode) unlock(&tlock); poperror(); - c->mode = openmode(omode); + c->mode = openmode(omode0); c->flag |= COPEN; c->offset = 0; return c; @@ -382,7 +394,7 @@ procopen(Chan *c, int omode) if(p->pid != pid) error(Eprocdied); - omode = openmode(omode); + omode = openmode(omode0); switch(QID(c->qid)){ case Qtext: @@ -425,6 +437,7 @@ procopen(Chan *c, int omode) case Qfpregs: case Qsyscall: case Qppid: + case Qwatchpt: nonone(p); break; @@ -454,6 +467,19 @@ procopen(Chan *c, int omode) error(Eprocdied); tc = devopen(c, omode, 0, 0, procgen); + if(waserror()){ + cclose(tc); + nexterror(); + } + + switch(QID(c->qid)){ + case Qwatchpt: + if((omode0 & OTRUNC) != 0) + clearwatchpt(p); + break; + } + + poperror(); qunlock(&p->debug); poperror(); @@ -701,6 +727,119 @@ readfd1(Chan *c, Proc *p, char *buf, int nbuf) } /* + * setupwatchpts(Proc *p, Watchpt *wp, int nwp) is defined for all arches separately. + * It tests whether wp is a valid set of watchpoints and errors out otherwise. + * If and only if they are valid, it sets up all watchpoints (clearing any preexisting ones). + * This is to make sure that failed writes to watchpt don't touch the existing watchpoints. + */ + +static void +clearwatchpt(Proc *p) +{ + setupwatchpts(p, nil, 0); + free(p->watchpt); + p->watchpt = nil; + p->nwatchpt = 0; +} + +static int +lenwatchpt(Proc *pr) +{ + /* careful, not holding debug lock */ + return pr->nwatchpt * (10 + 4 * sizeof(uintptr)); +} + +static int +readwatchpt(Proc *pr, char *buf, int nbuf) +{ + char *p, *e; + Watchpt *w; + + p = buf; + e = buf + nbuf; + /* careful, length has to match lenwatchpt() */ + for(w = pr->watchpt; w < pr->watchpt + pr->nwatchpt; w++) + p = seprint(p, e, sizeof(uintptr) == 8 ? "%c%c%c %#.16p %#.16p\n" : "%c%c%c %#.8p %#.8p\n", + (w->type & WATCHRD) != 0 ? 'r' : '-', + (w->type & WATCHWR) != 0 ? 'w' : '-', + (w->type & WATCHEX) != 0 ? 'x' : '-', + (void *) w->addr, (void *) w->len); + return p - buf; +} + +static int +writewatchpt(Proc *pr, char *buf, int nbuf, uvlong offset) +{ + char *p, *q, *e; + char line[256], *f[4]; + Watchpt *wp, *wq; + int rc, nwp, nwp0; + uvlong x; + + p = buf; + e = buf + nbuf; + if(offset != 0) + nwp0 = pr->nwatchpt; + else + nwp0 = 0; + nwp = 0; + for(q = p; q < e; q++) + nwp += *q == '\n'; + if(nwp > 65536) error(Egreg); + wp = malloc((nwp0+nwp) * sizeof(Watchpt)); + if(wp == nil) error(Enomem); + if(waserror()){ + free(wp); + nexterror(); + } + if(nwp0 > 0) + memmove(wp, pr->watchpt, sizeof(Watchpt) * nwp0); + for(wq = wp + nwp0;;){ + q = memchr(p, '\n', e - p); + if(q == nil) + break; + if(q - p > sizeof(line) - 1) + error("line too long"); + memmove(line, p, q - p); + line[q - p] = 0; + p = q + 1; + + rc = tokenize(line, f, nelem(f)); + if(rc == 0) continue; + if(rc != 3) + error("wrong number of fields"); + for(q = f[0]; *q != 0; q++) + switch(*q){ + case 'r': if((wq->type & WATCHRD) != 0) goto tinval; wq->type |= WATCHRD; break; + case 'w': if((wq->type & WATCHWR) != 0) goto tinval; wq->type |= WATCHWR; break; + case 'x': if((wq->type & WATCHEX) != 0) goto tinval; wq->type |= WATCHEX; break; + case '-': break; + default: tinval: error("invalid type"); + } + x = strtoull(f[1], &q, 0); + if(f[1] == q || *q != 0 || x != (uintptr) x) error("invalid address"); + wq->addr = x; + x = strtoull(f[2], &q, 0); + if(f[2] == q || *q != 0 || x != (uintptr) x) error("invalid length"); + wq->len = x; + if(!okaddr(wq->addr, wq->len, 0)) error("bad address"); + wq++; + } + nwp = wq - (wp + nwp0); + if(nwp == 0 && nwp0 == pr->nwatchpt){ + poperror(); + free(wp); + return p - buf; + } + setupwatchpts(pr, wp, nwp0 + nwp); + poperror(); + free(pr->watchpt); + pr->watchpt = wp; + pr->nwatchpt = nwp0 + nwp; + return p - buf; +} + +/* * userspace can't pass negative file offset for a * 64 bit kernel address, so we use 63 bit and sign * extend to 64 bit. @@ -1006,6 +1145,16 @@ procread(Chan *c, void *va, long n, vlong off) case Qppid: return readnum(offset, va, n, p->parentpid, NUMSIZE); + + case Qwatchpt: + eqlock(&p->debug); + j = readwatchpt(p, statbuf, sizeof(statbuf)); + qunlock(&p->debug); + if(offset >= j) + return 0; + if(offset+n > j) + n = j - offset; + goto statbufread; } error(Egreg); @@ -1125,6 +1274,9 @@ procwrite(Chan *c, void *va, long n, vlong off) if(p->noteid != id) error(Ebadarg); break; + case Qwatchpt: + writewatchpt(p, va, n, off); + break; default: print("unknown qid in procwrite\n"); error(Egreg); diff --git a/sys/src/9/port/portdat.h b/sys/src/9/port/portdat.h index c91e7a29c..17901b31d 100644 --- a/sys/src/9/port/portdat.h +++ b/sys/src/9/port/portdat.h @@ -49,6 +49,7 @@ typedef struct Timers Timers; typedef struct Uart Uart; typedef struct Waitq Waitq; typedef struct Walkqid Walkqid; +typedef struct Watchpt Watchpt; typedef struct Watchdog Watchdog; typedef int Devgen(Chan*, char*, Dirtab*, int, int, Dir*); @@ -772,6 +773,9 @@ struct Proc PMMU; char *syscalltrace; /* syscall trace */ + + Watchpt *watchpt; /* watchpoints */ + int nwatchpt; }; enum @@ -962,6 +966,16 @@ struct Watchdog void (*stat)(char*, char*); /* watchdog statistics */ }; +struct Watchpt +{ + enum { + WATCHRD = 1, + WATCHWR = 2, + WATCHEX = 4, + } type; + uintptr addr, len; +}; + /* queue state bits, Qmsg, Qcoalesce, and Qkick can be set in qopen */ enum diff --git a/sys/src/9/port/portfns.h b/sys/src/9/port/portfns.h index 14ff9ddaa..803622fd8 100644 --- a/sys/src/9/port/portfns.h +++ b/sys/src/9/port/portfns.h @@ -319,6 +319,7 @@ void setmalloctag(void*, uintptr); void setrealloctag(void*, uintptr); void setregisters(Ureg*, char*, char*, int); void setswapchan(Chan*); +void setupwatchpts(Proc*, Watchpt*, int); char* skipslash(char*); void sleep(Rendez*, int(*)(void*), void*); void* smalloc(ulong); diff --git a/sys/src/9/port/proc.c b/sys/src/9/port/proc.c index 0c701fb8a..2425f32a2 100644 --- a/sys/src/9/port/proc.c +++ b/sys/src/9/port/proc.c @@ -1209,6 +1209,10 @@ pexit(char *exitstr, int freemem) free(up->syscalltrace); up->syscalltrace = nil; } + if(up->watchpt != nil){ + free(up->watchpt); + up->watchpt = nil; + } qunlock(&up->debug); /* Sched must not loop for these locks */ diff --git a/sys/src/9/ppc/main.c b/sys/src/9/ppc/main.c index 5d2a1765b..93b81fd48 100644 --- a/sys/src/9/ppc/main.c +++ b/sys/src/9/ppc/main.c @@ -497,3 +497,10 @@ cistrncmp(char *a, char *b, int n) return 0; } + +void +setupwatchpts(Proc *, Watchpt *, int n) +{ + if(n > 0) + error("no watchpoints"); +} diff --git a/sys/src/9/sgi/main.c b/sys/src/9/sgi/main.c index 6e5a8ae42..2ed77a5b6 100644 --- a/sys/src/9/sgi/main.c +++ b/sys/src/9/sgi/main.c @@ -497,3 +497,10 @@ confinit(void) imagmem->maxsize = kpages; // mainmem->flags |= POOL_PARANOIA; } + +void +setupwatchpts(Proc *, Watchpt *, int n) +{ + if(n > 0) + error("no watchpoints"); +} diff --git a/sys/src/9/teg2/main.c b/sys/src/9/teg2/main.c index e26d8bd87..30c46647d 100644 --- a/sys/src/9/teg2/main.c +++ b/sys/src/9/teg2/main.c @@ -907,3 +907,10 @@ wakewfi(void) intrcpu(cpu); #endif } + +void +setupwatchpts(Proc *, Watchpt *, int n) +{ + if(n > 0) + error("no watchpoints"); +} diff --git a/sys/src/9/zynq/main.c b/sys/src/9/zynq/main.c index ec23af843..d8100441c 100644 --- a/sys/src/9/zynq/main.c +++ b/sys/src/9/zynq/main.c @@ -427,3 +427,10 @@ main(void) userinit(); schedinit(); } + +void +setupwatchpts(Proc *, Watchpt *, int n) +{ + if(n > 0) + error("no watchpoints"); +} |