diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
| commit | 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch) | |
| tree | c6e220ba61db3a6ea4052e6841296d829654e664 /os/pc/x86break.c | |
| parent | 46439007cf417cbd9ac8049bb4122c890097a0fa (diff) | |
20060303
Diffstat (limited to 'os/pc/x86break.c')
| -rw-r--r-- | os/pc/x86break.c | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/os/pc/x86break.c b/os/pc/x86break.c new file mode 100644 index 00000000..db31fe4f --- /dev/null +++ b/os/pc/x86break.c @@ -0,0 +1,138 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "ureg.h" +#include "../port/error.h" + +// +// from trap.c +// + +uchar BREAK = 0xcc; +static ulong skipflags; +extern int (*breakhandler)(Ureg *ur, Proc*); +static Bkpt *skip; +int breakmatch(BkptCond *cond, Ureg *ur, Proc *p); +void breaknotify(Bkpt *b, Proc *p); +void breakrestore(Bkpt *b); +Bkpt* breakclear(int id); + +void +skiphandler(Ureg *ur, void*) +{ + if (skip == 0) + panic("single step outside of skip"); + + breakrestore( skip ); + skip = 0; + ur->flags = skipflags; + if (up != 0) + up->state = Running; +} + +void +machbreakinit(void) +{ + breakhandler = breakhit; + trapenable(VectorDBG, skiphandler, nil, "bkpt.skip"); +} + +Instr +machinstr(ulong addr) +{ + if (addr < KTZERO) + error(Ebadarg); + return *(uchar*)addr; +} + +void +machbreakset(ulong addr) +{ + if (addr < KTZERO) + error(Ebadarg); + *(uchar*)addr = BREAK; +} + +void +machbreakclear(ulong addr, Instr i) +{ + if (addr < KTZERO) + error(Ebadarg); + *(uchar*)addr = i; +} + +// +// Called from the exception handler when a breakpoint instruction has been +// hit. This cannot not be called unless at least one breakpoint with this +// address is in the list of breakpoints. (All breakpoint notifications must +// previously have been set via setbreak()) +// +// foreach breakpoint in list +// if breakpoint matches conditions +// notify the break handler +// if no breakpoints matched the conditions +// pick a random breakpoint set to this address +// +// set a breakpoint at the next instruction to be executed, +// and pass the current breakpoint to the "skiphandler" +// +// clear the current breakpoint +// +// Tell the scheduler to stop scheduling, so the caller is +// guaranteed to execute the instruction, followed by the +// added breakpoint. +// +// + +extern Bkpt *breakpoints; + + +int +breakhit(Ureg *ur, Proc *p) +{ + Bkpt *b; + int nmatched; + + ur->pc--; + + nmatched = 0; + for(b = breakpoints; b != nil; b = b->next) { + if(breakmatch(b->conditions, ur, p)) { + breaknotify(b, p); + ++nmatched; + } + } + + if (nmatched) + return 1; + + if (skip != nil) + panic("x86break: non-nil skip in breakhit\n"); + + for(b = breakpoints; b != (Bkpt*) nil; b = b->next) { + if(b->addr == ur->pc) { + if(breakclear(b->id) == 0) + panic("breakhit: breakclear() failed"); + + skip = b; + skipflags = ur->flags; + if (p != 0) + p->state = Stopped; /* this should disable scheduling */ + + if (ur->flags & (1 << 9)) { /* mask all interrupts */ + ur->flags &= ~(1<<9); + } + ur->flags |= (1 << 8); + } + } + return 1; +} + +int +isvalid_va(void*) +{ + return 1; +} |
