1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "portfns.h" 6 #include "ureg.h" 7 #include "../port/error.h" 8 9 // 10 // These bits used to be in port/devdbg but were removed in 11 // order to allow for using hardware debug features on certain 12 // architectures 13 // 14 15 extern void breakset(Bkpt *b); 16 extern void breakrestore(Bkpt *b); 17 extern Bkpt* breakclear(int id); 18 extern void breaknotify(Bkpt *b, Proc *p); 19 extern int breakmatch(BkptCond *cond, Ureg *ur, Proc *p); 20 21 void skipfree(Bkpt *b); 22 Bkpt*newskip(ulong addr, Bkpt *skipb, Proc *skipp); 23 Bkpt *skipalloc; 24 extern Bkpt *breakpoints; 25 typedef struct SkipArg SkipArg; 26 struct SkipArg 27 { 28 Bkpt *b; 29 Proc *p; 30 }; 31 32 void 33 skiphandler(Bkpt *b) 34 { 35 SkipArg *a = b->aux; 36 Bkpt *l; 37 38 if(breakclear(b->id) == nil) 39 panic("skiphandler: breakclear() failed"); 40 breakrestore(a->b); 41 l = a->b->link; 42 while(l != nil) { 43 breakrestore(l); 44 l = l->link; 45 } 46 skipfree(b); 47 a->p->dbgstop = 0; // Whoo! 48 if(a->p->state == Stopped) 49 ready(a->p); 50 } 51 52 Bkpt* 53 newskip(ulong addr, Bkpt *skipb, Proc *skipp) 54 { 55 Bkpt *b; 56 SkipArg *a; 57 58 b = skipalloc; 59 if(b == nil) 60 panic("newskip(): no free skips\n"); 61 skipalloc = b->next; 62 63 b->addr = addr; 64 b->conditions->val = addr; 65 b->link = nil; 66 a = b->aux; 67 a->b = skipb; 68 a->p = skipp; 69 70 return b; 71 } 72 73 void 74 skipfree(Bkpt *b) 75 { 76 b->next = skipalloc; 77 skipalloc = b; 78 } 79 80 // 81 // Called from the exception handler when a breakpoint instruction has been 82 // hit. This cannot not be called unless at least one breakpoint with this 83 // address is in the list of breakpoints. (All breakpoint notifications must 84 // previously have been set via setbreak()) 85 // 86 // foreach breakpoint in list 87 // if breakpoint matches conditions 88 // notify the break handler 89 // if no breakpoints matched the conditions 90 // pick a random breakpoint set to this address 91 // 92 // set a breakpoint at the next instruction to be executed, 93 // and pass the current breakpoint to the "skiphandler" 94 // 95 // clear the current breakpoint 96 // 97 // Tell the scheduler to stop scheduling, so the caller is 98 // guaranteed to execute the instruction, followed by the 99 // added breakpoint. 100 // 101 // 102 int 103 breakhit(Ureg *ur, Proc *p) 104 { 105 Bkpt *b; 106 int nmatched; 107 Bkpt *skip; 108 109 nmatched = 0; 110 for(b = breakpoints; b != nil; b = b->next) { 111 if(breakmatch(b->conditions, ur, p)) { 112 breaknotify(b, p); 113 ++nmatched; 114 } 115 } 116 117 if(nmatched) 118 return BrkSched; 119 120 skip = nil; 121 for(b = breakpoints; b != nil; b = b->next) { 122 if(b->addr == ur->pc) { 123 if(breakclear(b->id) == nil) 124 panic("breakhit: breakclear() failed"); 125 126 if(skip == nil) 127 skip = newskip(machnextaddr(ur), b, p); 128 else { 129 b->link = skip->link; 130 skip->link = b; 131 } 132 } 133 } 134 if(skip == nil) 135 return BrkSched; 136 breakset(skip); 137 return BrkNoSched; 138 } 139 140 void 141 portbreakinit(void) 142 { 143 Bkpt *b; 144 int i; 145 146 skipalloc = mallocz(conf.nproc*(sizeof(Bkpt)+sizeof(BkptCond)+sizeof(SkipArg)), 1); 147 if(skipalloc == nil) 148 error(Enomem); 149 150 b = skipalloc; 151 for(i=0; i < conf.nproc-1; i++) { 152 b->id = -(i+1); 153 b->conditions = (BkptCond*)((uchar*)b + sizeof(Bkpt)); 154 b->conditions->op = 'b'; 155 b->handler = skiphandler; 156 b->aux = (SkipArg*)((uchar*)b+sizeof(Bkpt)+sizeof(BkptCond)); 157 b->next = (Bkpt*)((uchar*)b+sizeof(Bkpt)+sizeof(BkptCond)+sizeof(SkipArg)); 158 b = b->next; 159 } 160 b->next = nil; 161 } 162