1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)bpact.c 1.1 01/18/82";
4 
5 /*
6  * Routines for doing the right thing when a breakpoint is reached.
7  */
8 
9 #include "defs.h"
10 #include "breakpoint.h"
11 #include "sym.h"
12 #include "tree.h"
13 #include "source.h"
14 #include "mappings.h"
15 #include "runtime.h"
16 #include "process.h"
17 #include "machine.h"
18 #include "main.h"
19 #include "bp.rep"
20 #include "tree/tree.rep"
21 
22 typedef enum { SAVE, NOSAVE } SAVEBP;
23 
24 LOCAL SAVEBP handlebp();
25 
26 /*
27  * A "delayed" breakpoint is one that has an action involving execution
28  * of code, e.g. at a CALL we want to step from the beginning of the
29  * procedure to the first line before printing parameters.
30  */
31 
32 LOCAL short delayed;
33 
34 #define NONE 0
35 #define DELAY_CALL 1
36 #define DELAY_STOP 2
37 
38 /*
39  * Take action at a breakpoint; if it's not a breakpoint return FALSE.
40  *
41  * As we go through the list of breakpoints, we have to remember
42  * the previous one so that "handlebp" can delete breakpoints on
43  * the fly if necessary.
44  *
45  * If the breakpoint is a STOP_BP, handlebp will set "isstopped".  After
46  * going through the loop, bpact checks if "isstopped" is set and calls
47  * printstatus if it is.  This is so multiple breakpoints at the same
48  * address, one of which is a STOP_BP, still work.
49  */
50 
51 #define isswitch(bptype) ( \
52 	bptype == ALL_ON || bptype == ALL_OFF || \
53 	bptype == TERM_ON || bptype == TERM_OFF || \
54 	bptype == BLOCK_ON || bptype == BLOCK_OFF || \
55 	bptype == STOP_ON || bptype == STOP_OFF \
56 )
57 
58 BOOLEAN bpact()
59 {
60 	register BPINFO *p;
61 	BPINFO *prev, *next;
62 	BOOLEAN found;
63 	ADDRESS oldpc;
64 
65 	delayed = NONE;
66 	found = FALSE;
67 	prev = NIL;
68 	for (p = bphead; p != NIL; p = next) {
69 		next = p->bpnext;
70 		if (p->bpaddr == pc) {
71 			prbpfound(p);
72 			found = TRUE;
73 			if (p->bpcond == NIL || isswitch(p->bptype) || cond(p->bpcond)) {
74 				prbphandled();
75 				if (handlebp(p) == NOSAVE) {
76 					prbpnosave();
77 					if (prev == NIL) {
78 						bphead = next;
79 					} else {
80 						prev->bpnext = next;
81 					}
82 					dispose(p);
83 				} else {
84 					prbpsave();
85 					prev = p;
86 				}
87 			} else {
88 				prev = p;
89 			}
90 		} else {
91 			prev = p;
92 		}
93 	}
94 	if (delayed != NONE) {
95 		oldpc = pc;
96 		runtofirst();
97 		if ((delayed&DELAY_CALL) == DELAY_CALL) {
98 			SYM *s, *t;
99 
100 			s = curfunc;
101 			t = whatblock(return_addr());
102 			if (t == NIL) {
103 				panic("can't find block for caller addr %d", caller_addr());
104 			}
105 			printcall(s, t);
106 			addbp(return_addr(), RETURN, s, NIL, NIL, 0);
107 		}
108 		if (pc != oldpc) {
109 			bpact();
110 		}
111 		if (isstopped) {
112 			printstatus();
113 		}
114 	} else {
115 		if (isstopped) {
116 			printstatus();
117 		}
118 	}
119 	fflush(stdout);
120 	return(found);
121 }
122 
123 /*
124  * Handle an expected breakpoint appropriately, return whether
125  * or not to save the breakpoint.
126  */
127 
128 LOCAL SAVEBP handlebp(p)
129 BPINFO *p;
130 {
131 	register SYM *s, *t;
132 	SAVEBP r;
133 
134 	r = SAVE;
135 	switch(p->bptype) {
136 		case ALL_ON:
137 			curfunc = p->bpblock;
138 			addcond(TRPRINT, p->bpcond);
139 			if (p->bpline >= 0) {
140 				tracing++;
141 			} else {
142 				inst_tracing++;
143 			}
144 			addbp(return_addr(), ALL_OFF, curfunc, p->bpcond, NIL, 0);
145 			break;
146 
147 		case ALL_OFF:
148 			r = NOSAVE;
149 			if (p->bpline >= 0) {
150 				tracing--;
151 			} else {
152 				inst_tracing--;
153 			}
154 			delcond(TRPRINT, p->bpcond);
155 			curfunc = p->bpblock;
156 			break;
157 
158 		case STOP_ON:
159 			var_tracing++;
160 			curfunc = p->bpblock;
161 			if (p->bpnode != NIL) {
162 				addvar(TRSTOP, p->bpnode, p->bpcond);
163 			} else if (p->bpcond != NIL) {
164 				addcond(TRSTOP, p->bpcond);
165 			}
166 			addbp(return_addr(), STOP_OFF, curfunc, p->bpcond, p->bpnode, 0);
167 			break;
168 
169 		case STOP_OFF:
170 			r = NOSAVE;
171 			delcond(TRSTOP, p->bpcond);
172 			var_tracing--;
173 			curfunc = p->bpblock;
174 			break;
175 
176 		case INST:
177 			curline = p->bpline;
178 			if (curline > 0) {
179 				printf("trace:  ");
180 				printlines(curline, curline);
181 			} else {
182 				printf("inst trace:	");
183 				printinst(pc, pc);
184 			}
185 			break;
186 
187 		case STOP_BP:
188 			if (p->bpblock != NIL) {
189 				delayed |= DELAY_STOP;
190 				curfunc = p->bpblock;
191 			}
192 			curline = p->bpline;
193 			isstopped = TRUE;
194 			break;
195 
196 		case BLOCK_ON: {
197 			BPINFO *nbp;
198 
199 			s = p->bpblock;
200 			t = p->bpnode->nameval;
201 			nbp = newbp(codeloc(t), CALL, t, p->bpcond, NIL, 0);
202 			addbp(return_addr(), BLOCK_OFF, (SYM *) nbp, NIL, NIL, 0);
203 			break;
204 		}
205 
206 		case BLOCK_OFF: {
207 			BPINFO *oldbp;
208 
209 			r = NOSAVE;
210 			oldbp = (BPINFO *) p->bpblock;
211 			delbp(oldbp->bpid);
212 			break;
213 		}
214 
215 		case CALL:
216 			delayed |= DELAY_CALL;
217 			curfunc = p->bpblock;
218 			break;
219 
220 		case RETURN:
221 			r = NOSAVE;
222 			s = p->bpblock;
223 			printrtn(s);
224 			break;
225 
226 		case TERM_ON: {
227 			ADDRESS addr;
228 
229 			curfunc = p->bpblock;
230 			addvar(TRPRINT, p->bpnode, p->bpcond);
231 			addr = return_addr();
232 			addbp(addr, TERM_OFF, curfunc, p->bpcond, p->bpnode, 0);
233 			var_tracing++;
234 			break;
235 		}
236 
237 		case TERM_OFF:
238 			r = NOSAVE;
239 			var_tracing--;
240 			delvar(TRPRINT, p->bpnode, p->bpcond);
241 			curfunc = p->bpblock;
242 			break;
243 
244 		case AT_BP:
245 			printf("at line %d: ", p->bpline);
246 			eval(p->bpnode);
247 			prtree(p->bpnode);
248 			printf(" = ");
249 			printval(p->bpnode->nodetype);
250 			putchar('\n');
251 			break;
252 
253 		/*
254 		 * Returning from a called procedure.
255 		 * Further breakpoint processing is not done, since if
256 		 * there were any it wouldn't be associated with the call.
257 		 */
258 		case CALLPROC:
259 			procreturn(p->bpblock);
260 			delbp(p->bpid);
261 			erecover();
262 			/* NOTREACHED */
263 
264 		case END_BP:
265 			r = NOSAVE;
266 			endprogram();
267 
268 		default:
269 			panic("unknown bptype %d in cont", p->bptype);
270 			/* NOTREACHED */
271 	}
272 	return(r);
273 }
274 
275 /*
276  * Internal trace routines.
277  */
278 
279 LOCAL char *prbptype[] ={
280 	"ALL_ON", "ALL_OFF", "INST", "CALL", "RETURN", "BLOCK_ON", "BLOCK_OFF",
281 	"TERM_ON", "TERM_OFF", "AT_BP", "STOP_BP", "CALLPROC", "END_BP",
282 	"STOP_ON", "STOP_OFF",
283 };
284 
285 LOCAL prbpfound(p)
286 BPINFO *p;
287 {
288 	if (option('b')) {
289 		printf("%s breakpoint found at pc %d, line %d -- ",
290 			prbptype[(int) p->bptype], p->bpaddr, p->bpline);
291 	}
292 }
293 
294 LOCAL prbphandled()
295 {
296 	if (option('b')) {
297 		printf("handled, ");
298 	}
299 }
300 
301 LOCAL prbpnosave()
302 {
303 	if (option('b')) {
304 		printf("not saved\n");
305 		fflush(stdout);
306 	}
307 }
308 
309 LOCAL prbpsave()
310 {
311 	if (option('b')) {
312 		printf("saved\n");
313 		fflush(stdout);
314 	}
315 }
316