shell options are -ec, NOT -ce
[unix-history] / usr / src / old / dbx / events.c
CommitLineData
2a24676e 1/*
8a90f3aa
KB
2 * Copyright (c) 1983 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2a24676e 16 */
4298caf5 17
2a24676e 18#ifndef lint
8a90f3aa
KB
19static char sccsid[] = "@(#)events.c 5.4 (Berkeley) %G%";
20#endif /* not lint */
4298caf5
ML
21
22/*
23 * Event/breakpoint managment.
24 */
25
26#include "defs.h"
27#include "events.h"
28#include "main.h"
29#include "symbols.h"
30#include "tree.h"
31#include "eval.h"
32#include "source.h"
33#include "mappings.h"
2fd0f574 34#include "runtime.h"
4298caf5
ML
35#include "process.h"
36#include "machine.h"
37#include "lists.h"
38
39#ifndef public
34d5a416 40
4298caf5
ML
41typedef struct Event *Event;
42typedef struct Breakpoint *Breakpoint;
43
4298caf5
ML
44#include "symbols.h"
45
4298caf5
ML
46#define addevent(cond, cmdlist) event_alloc(false, cond, cmdlist)
47#define event_once(cond, cmdlist) event_alloc(true, cond, cmdlist)
48
34d5a416
DS
49/*
50 * When tracing variables we keep a copy of their most recent value
51 * and compare it to the current one each time a breakpoint occurs.
52 * MAXTRSIZE is the maximum size variable we allow.
53 */
54
55#define MAXTRSIZE 512
56
4298caf5
ML
57#endif
58
34d5a416
DS
59public boolean inst_tracing;
60public boolean single_stepping;
61public boolean isstopped;
62
63public Symbol linesym;
64public Symbol procsym;
65public Symbol pcsym;
66public Symbol retaddrsym;
67
4298caf5
ML
68struct Event {
69 unsigned int id;
0022c355 70 boolean temporary;
4298caf5
ML
71 Node condition;
72 Cmdlist actions;
73};
74
75struct Breakpoint {
76 Event event;
77 Address bpaddr;
78 Lineno bpline;
79 Cmdlist actions;
0022c355 80 boolean temporary;
4298caf5
ML
81};
82
83typedef List Eventlist;
84typedef List Bplist;
85
86#define eventlist_append(event, el) list_append(list_item(event), nil, el)
87#define bplist_append(bp, bl) list_append(list_item(bp), nil, bl)
88
89private Eventlist eventlist; /* list of active events */
90private Bplist bplist; /* list of active breakpoints */
0022c355
ML
91private Event curevent; /* most recently created event */
92private integer eventid; /* id number of current event */
93private integer trid; /* id number of current trace */
4298caf5
ML
94
95typedef struct Trcmd {
96 Integer trid;
97 Event event;
98 Cmdlist cmdlist;
99} *Trcmd;
100
101private List eachline; /* commands to execute after each line */
102private List eachinst; /* commands to execute after each instruction */
103
104private Breakpoint bp_alloc();
105
106/*
107 * Initialize breakpoint information.
108 */
109
110private Symbol builtinsym(str, class, type)
111String str;
112Symclass class;
113Symbol type;
114{
115 Symbol s;
116
117 s = insert(identname(str, true));
118 s->language = findlanguage(".s");
119 s->class = class;
120 s->type = type;
121 return s;
122}
123
124public bpinit()
125{
126 linesym = builtinsym("$line", VAR, t_int);
127 procsym = builtinsym("$proc", PROC, nil);
128 pcsym = lookup(identname("$pc", true));
129 if (pcsym == nil) {
130 panic("can't find $pc");
131 }
132 retaddrsym = builtinsym("$retaddr", VAR, t_int);
133 eventlist = list_alloc();
134 bplist = list_alloc();
135 eachline = list_alloc();
136 eachinst = list_alloc();
137}
138
139/*
140 * Trap an event and do the associated commands when it occurs.
141 */
142
143public Event event_alloc(istmp, econd, cmdlist)
0022c355 144boolean istmp;
4298caf5
ML
145Node econd;
146Cmdlist cmdlist;
147{
148 register Event e;
149
150 e = new(Event);
0022c355
ML
151 ++eventid;
152 e->id = eventid;
4298caf5
ML
153 e->temporary = istmp;
154 e->condition = econd;
155 e->actions = cmdlist;
156 eventlist_append(e, eventlist);
0022c355 157 curevent = e;
4298caf5
ML
158 translate(e);
159 return e;
160}
161
162/*
163 * Delete the event with the given id.
2fd0f574 164 * Returns whether it's successful or not.
4298caf5
ML
165 */
166
2fd0f574 167public boolean delevent (id)
4298caf5
ML
168unsigned int id;
169{
170 Event e;
171 Breakpoint bp;
172 Trcmd t;
2fd0f574 173 boolean found;
4298caf5 174
2fd0f574 175 found = false;
4298caf5
ML
176 foreach (Event, e, eventlist)
177 if (e->id == id) {
2fd0f574 178 found = true;
4298caf5
ML
179 foreach (Breakpoint, bp, bplist)
180 if (bp->event == e) {
0022c355
ML
181 if (tracebpts) {
182 printf("deleting breakpoint at 0x%x\n", bp->bpaddr);
183 fflush(stdout);
184 }
4298caf5
ML
185 list_delete(list_curitem(bplist), bplist);
186 }
187 endfor
2fd0f574 188 list_delete(list_curitem(eventlist), eventlist);
4298caf5
ML
189 break;
190 }
191 endfor
192 foreach (Trcmd, t, eachline)
193 if (t->event->id == id) {
2fd0f574 194 found = true;
4298caf5
ML
195 printrmtr(t);
196 list_delete(list_curitem(eachline), eachline);
197 }
198 endfor
199 foreach (Trcmd, t, eachinst)
200 if (t->event->id == id) {
2fd0f574 201 found = true;
4298caf5
ML
202 printrmtr(t);
203 list_delete(list_curitem(eachinst), eachinst);
204 }
205 endfor
206 if (list_size(eachinst) == 0) {
207 inst_tracing = false;
208 if (list_size(eachline) == 0) {
209 single_stepping = false;
210 }
211 }
2fd0f574 212 return found;
4298caf5
ML
213}
214
215/*
216 * Translate an event into the appropriate breakpoints and actions.
217 * While we're at it, turn on the breakpoints if the condition is true.
218 */
219
220private translate(e)
221Event e;
222{
223 Breakpoint bp;
224 Symbol s;
225 Node place;
226 Lineno line;
227 Address addr;
228
229 checkref(e->condition);
230 switch (e->condition->op) {
231 case O_EQ:
232 if (e->condition->value.arg[0]->op == O_SYM) {
233 s = e->condition->value.arg[0]->value.sym;
234 place = e->condition->value.arg[1];
235 if (s == linesym) {
236 if (place->op == O_QLINE) {
237 line = place->value.arg[1]->value.lcon;
2fd0f574 238 addr = objaddr(line, place->value.arg[0]->value.scon);
4298caf5
ML
239 } else {
240 eval(place);
241 line = pop(long);
242 addr = objaddr(line, cursource);
243 }
244 if (addr == NOADDR) {
2fd0f574
SL
245 if (not delevent(e->id)) {
246 printf("!! dbx.translate: can't undo event %d?\n",
247 e->id);
248 }
4298caf5
ML
249 beginerrmsg();
250 fprintf(stderr, "no executable code at line ");
251 prtree(stderr, place);
252 enderrmsg();
253 }
254 bp = bp_alloc(e, addr, line, e->actions);
255 } else if (s == procsym) {
256 eval(place);
257 s = pop(Symbol);
258 bp = bp_alloc(e, codeloc(s), 0, e->actions);
259 if (isactive(s) and pc != codeloc(program)) {
260 evalcmdlist(e->actions);
261 }
262 } else if (s == pcsym) {
263 eval(place);
264 bp = bp_alloc(e, pop(Address), 0, e->actions);
265 } else {
266 condbp(e);
267 }
268 } else {
269 condbp(e);
270 }
271 break;
272
273 /*
274 * These should be handled specially.
275 * But for now I'm ignoring the problem.
276 */
277 case O_AND:
278 case O_OR:
279 default:
280 condbp(e);
281 break;
282 }
283}
284
285/*
286 * Create a breakpoint for a condition that cannot be pinpointed
287 * to happening at a particular address, but one for which we
288 * must single step and check the condition after each statement.
289 */
290
291private condbp(e)
292Event e;
293{
294 Symbol p;
295 Breakpoint bp;
296 Cmdlist actions;
297
298 p = tcontainer(e->condition);
299 if (p == nil) {
300 p = program;
301 }
302 actions = buildcmdlist(build(O_IF, e->condition, e->actions));
303 actions = buildcmdlist(build(O_TRACEON, false, actions));
304 bp = bp_alloc(e, codeloc(p), 0, actions);
305}
306
307/*
308 * Determine the deepest nested subprogram that still contains
309 * all elements in the given expression.
310 */
311
312public Symbol tcontainer(exp)
313Node exp;
314{
315 Integer i;
316 Symbol s, t, u, v;
317
318 checkref(exp);
319 s = nil;
320 if (exp->op == O_SYM) {
321 s = container(exp->value.sym);
322 } else if (not isleaf(exp->op)) {
323 for (i = 0; i < nargs(exp->op); i++) {
324 t = tcontainer(exp->value.arg[i]);
325 if (t != nil) {
326 if (s == nil) {
327 s = t;
328 } else {
329 u = s;
330 v = t;
331 while (u != v and u != nil) {
332 u = container(u);
333 v = container(v);
334 }
335 if (u == nil) {
336 panic("bad ancestry for \"%s\"", symname(s));
337 } else {
338 s = u;
339 }
340 }
341 }
342 }
343 }
344 return s;
345}
346
e1bc702e
ML
347/*
348 * Determine if the given function can be executed at full speed.
349 * This can only be done if there are no breakpoints within the function.
350 */
351
0022c355 352public boolean canskip(f)
e1bc702e
ML
353Symbol f;
354{
355 Breakpoint p;
0022c355 356 boolean ok;
e1bc702e
ML
357
358 ok = true;
359 foreach (Breakpoint, p, bplist)
360 if (whatblock(p->bpaddr) == f) {
361 ok = false;
362 break;
363 }
364 endfor
365 return ok;
366}
367
4298caf5
ML
368/*
369 * Print out what's currently being traced by looking at
370 * the currently active events.
371 *
372 * Some convolution here to translate internal representation
373 * of events back into something more palatable.
374 */
375
376public status()
377{
378 Event e;
4298caf5
ML
379
380 foreach (Event, e, eventlist)
381 if (not e->temporary) {
e1bc702e 382 printevent(e);
4298caf5
ML
383 }
384 endfor
385}
386
e1bc702e
ML
387public printevent(e)
388Event e;
389{
390 Command cmd;
391
392 if (not isredirected()) {
2fd0f574 393 printeventid(e->id);
e1bc702e
ML
394 }
395 cmd = list_element(Command, list_head(e->actions));
396 if (cmd->op == O_PRINTCALL) {
397 printf("trace ");
398 printname(stdout, cmd->value.sym);
399 } else {
400 if (list_size(e->actions) > 1) {
401 printf("{ ");
402 }
403 foreach (Command, cmd, e->actions)
404 printcmd(stdout, cmd);
405 if (not list_islast()) {
406 printf("; ");
407 }
408 endfor
409 if (list_size(e->actions) > 1) {
410 printf(" }");
411 }
412 printcond(e->condition);
413 }
414 printf("\n");
415}
416
2fd0f574
SL
417private printeventid (id)
418integer id;
419{
420 printf("[%d] ", id);
421}
422
4298caf5
ML
423/*
424 * Print out a condition.
425 */
426
427private printcond(cond)
428Node cond;
429{
430 Symbol s;
431 Node place;
432
433 if (cond->op == O_EQ and cond->value.arg[0]->op == O_SYM) {
434 s = cond->value.arg[0]->value.sym;
435 place = cond->value.arg[1];
436 if (s == procsym) {
437 if (place->value.sym != program) {
438 printf(" in ");
439 printname(stdout, place->value.sym);
440 }
441 } else if (s == linesym) {
442 printf(" at ");
443 prtree(stdout, place);
444 } else if (s == pcsym or s == retaddrsym) {
445 printf("i at ");
446 prtree(stdout, place);
447 } else {
448 printf(" when ");
449 prtree(stdout, cond);
450 }
451 } else {
452 printf(" when ");
453 prtree(stdout, cond);
454 }
455}
456
457/*
458 * Add a breakpoint to the list and return it.
459 */
460
461private Breakpoint bp_alloc(e, addr, line, actions)
462Event e;
463Address addr;
464Lineno line;
465Cmdlist actions;
466{
467 register Breakpoint p;
468
469 p = new(Breakpoint);
470 p->event = e;
471 p->bpaddr = addr;
472 p->bpline = line;
473 p->actions = actions;
0022c355
ML
474 p->temporary = false;
475 if (tracebpts) {
476 if (e == nil) {
b9ae3d87 477 printf("new bp at 0x%x for event ??\n", addr);
0022c355
ML
478 } else {
479 printf("new bp at 0x%x for event %d\n", addr, e->id);
480 }
481 fflush(stdout);
482 }
4298caf5
ML
483 bplist_append(p, bplist);
484 return p;
485}
486
487/*
488 * Free all storage in the event and breakpoint tables.
489 */
490
491public bpfree()
492{
493 register Event e;
494
495 fixbps();
496 foreach (Event, e, eventlist)
2fd0f574
SL
497 if (not delevent(e->id)) {
498 printf("!! dbx.bpfree: can't delete event %d\n", e->id);
499 }
4298caf5
ML
500 list_delete(list_curitem(eventlist), eventlist);
501 endfor
502}
503
504/*
505 * Determine if the program stopped at a known breakpoint
506 * and if so do the associated commands.
507 */
508
0022c355 509public boolean bpact()
4298caf5
ML
510{
511 register Breakpoint p;
0022c355 512 boolean found;
2fd0f574 513 integer eventId;
4298caf5
ML
514
515 found = false;
516 foreach (Breakpoint, p, bplist)
517 if (p->bpaddr == pc) {
0022c355
ML
518 if (tracebpts) {
519 printf("breakpoint for event %d found at location 0x%x\n",
520 p->event->id, pc);
521 }
4298caf5 522 found = true;
0022c355
ML
523 if (p->event->temporary) {
524 if (not delevent(p->event->id)) {
525 printf("!! dbx.bpact: can't find event %d\n",
526 p->event->id);
527 }
528 }
4298caf5 529 evalcmdlist(p->actions);
0022c355
ML
530 if (isstopped) {
531 eventId = p->event->id;
532 }
533 if (p->temporary) {
534 list_delete(list_curitem(bplist), bplist);
535 }
4298caf5
ML
536 }
537 endfor
538 if (isstopped) {
2fd0f574
SL
539 if (found) {
540 printeventid(eventId);
541 }
4298caf5
ML
542 printstatus();
543 }
544 fflush(stdout);
545 return found;
546}
547
548/*
549 * Begin single stepping and executing the given commands after each step.
550 * If the first argument is true step by instructions, otherwise
551 * step by source lines.
552 *
553 * We automatically set a breakpoint at the end of the current procedure
554 * to turn off the given tracing.
555 */
556
557public traceon(inst, event, cmdlist)
0022c355 558boolean inst;
4298caf5
ML
559Event event;
560Cmdlist cmdlist;
561{
562 register Trcmd trcmd;
0022c355 563 Breakpoint bp;
4298caf5 564 Cmdlist actions;
e1bc702e 565 Address ret;
0022c355 566 Event e;
4298caf5 567
0022c355
ML
568 if (event == nil) {
569 e = curevent;
570 } else {
571 e = event;
572 }
4298caf5 573 trcmd = new(Trcmd);
0022c355
ML
574 ++trid;
575 trcmd->trid = trid;
576 trcmd->event = e;
4298caf5
ML
577 trcmd->cmdlist = cmdlist;
578 single_stepping = true;
579 if (inst) {
580 inst_tracing = true;
581 list_append(list_item(trcmd), nil, eachinst);
582 } else {
583 list_append(list_item(trcmd), nil, eachline);
584 }
e1bc702e
ML
585 ret = return_addr();
586 if (ret != 0) {
0022c355
ML
587 actions = buildcmdlist(build(O_TRACEOFF, trcmd->trid));
588 bp = bp_alloc(e, (Address) ret, 0, actions);
589 bp->temporary = true;
590 }
591 if (tracebpts) {
592 printf("adding trace %d for event %d\n", trcmd->trid, e->id);
4298caf5
ML
593 }
594}
595
596/*
597 * Turn off some kind of tracing.
598 * Strictly an internal command, this cannot be invoked by the user.
599 */
600
601public traceoff(id)
602Integer id;
603{
604 register Trcmd t;
0022c355 605 register boolean found;
4298caf5
ML
606
607 found = false;
608 foreach (Trcmd, t, eachline)
609 if (t->trid == id) {
610 printrmtr(t);
611 list_delete(list_curitem(eachline), eachline);
612 found = true;
613 break;
614 }
615 endfor
616 if (not found) {
617 foreach (Trcmd, t, eachinst)
618 if (t->event->id == id) {
619 printrmtr(t);
620 list_delete(list_curitem(eachinst), eachinst);
621 found = true;
622 break;
623 }
624 endfor
625 if (not found) {
0022c355
ML
626 beginerrmsg();
627 fprintf(stderr, "[internal error: trace id %d not found]\n", id);
4298caf5
ML
628 }
629 }
630 if (list_size(eachinst) == 0) {
631 inst_tracing = false;
632 if (list_size(eachline) == 0) {
633 single_stepping = false;
634 }
635 }
636}
637
638/*
639 * If breakpoints are being traced, note that a Trcmd is being deleted.
640 */
641
642private printrmtr(t)
643Trcmd t;
644{
0022c355
ML
645 if (tracebpts) {
646 printf("removing trace %d", t->trid);
647 if (t->event != nil) {
648 printf(" for event %d", t->event->id);
649 }
650 printf("\n");
252b7653 651 }
4298caf5
ML
652}
653
654/*
655 * Print out news during single step tracing.
656 */
657
658public printnews()
659{
660 register Trcmd t;
661
662 foreach (Trcmd, t, eachline)
663 evalcmdlist(t->cmdlist);
664 endfor
665 foreach (Trcmd, t, eachinst)
666 evalcmdlist(t->cmdlist);
667 endfor
668 bpact();
669}
670
671/*
672 * A procedure call/return has occurred while single-stepping,
673 * note it if we're tracing lines.
674 */
675
0022c355 676private boolean chklist();
4298caf5
ML
677
678public callnews(iscall)
0022c355 679boolean iscall;
4298caf5
ML
680{
681 if (not chklist(eachline, iscall)) {
682 chklist(eachinst, iscall);
683 }
684}
685
0022c355 686private boolean chklist(list, iscall)
4298caf5 687List list;
0022c355 688boolean iscall;
4298caf5
ML
689{
690 register Trcmd t;
691 register Command cmd;
692
2fd0f574 693 setcurfunc(whatblock(pc));
4298caf5
ML
694 foreach (Trcmd, t, list)
695 foreach (Command, cmd, t->cmdlist)
696 if (cmd->op == O_PRINTSRCPOS and
697 (cmd->value.arg[0] == nil or cmd->value.arg[0]->op == O_QLINE)) {
4298caf5
ML
698 if (iscall) {
699 printentry(curfunc);
700 } else {
701 printexit(curfunc);
702 }
703 return true;
704 }
705 endfor
706 endfor
707 return false;
708}
709
4298caf5
ML
710/*
711 * List of variables being watched.
712 */
713
714typedef struct Trinfo *Trinfo;
715
716struct Trinfo {
717 Node variable;
718 Address traddr;
719 Symbol trblock;
720 char *trvalue;
721};
722
723private List trinfolist;
724
725/*
726 * Find the trace information record associated with the given record.
727 * If there isn't one then create it and add it to the list.
728 */
729
730private Trinfo findtrinfo(p)
731Node p;
732{
733 register Trinfo tp;
0022c355 734 boolean isnew;
4298caf5
ML
735
736 isnew = true;
737 if (trinfolist == nil) {
738 trinfolist = list_alloc();
739 } else {
740 foreach (Trinfo, tp, trinfolist)
741 if (tp->variable == p) {
742 isnew = false;
743 break;
744 }
745 endfor
746 }
747 if (isnew) {
748 if (tracebpts) {
749 printf("adding trinfo for \"");
750 prtree(stdout, p);
751 printf("\"\n");
752 }
753 tp = new(Trinfo);
754 tp->variable = p;
755 tp->traddr = lval(p);
756 tp->trvalue = nil;
757 list_append(list_item(tp), nil, trinfolist);
758 }
759 return tp;
760}
761
762/*
763 * Print out the value of a variable if it has changed since the
764 * last time we checked.
765 */
766
767public printifchanged(p)
768Node p;
769{
770 register Trinfo tp;
771 register int n;
772 char buff[MAXTRSIZE];
0022c355 773 Filename curfile;
4298caf5 774 static Lineno prevline;
0022c355 775 static Filename prevfile;
4298caf5
ML
776
777 tp = findtrinfo(p);
778 n = size(p->nodetype);
0022c355
ML
779 dread(buff, tp->traddr, n);
780 curfile = srcfilename(pc);
4298caf5
ML
781 if (tp->trvalue == nil) {
782 tp->trvalue = newarr(char, n);
783 mov(buff, tp->trvalue, n);
784 mov(buff, sp, n);
785 sp += n;
0022c355 786 printf("initially (at line %d in \"%s\"):\t", curline, curfile);
4298caf5
ML
787 prtree(stdout, p);
788 printf(" = ");
789 printval(p->nodetype);
790 putchar('\n');
791 } else if (cmp(tp->trvalue, buff, n) != 0) {
792 mov(buff, tp->trvalue, n);
793 mov(buff, sp, n);
794 sp += n;
0022c355 795 printf("after line %d in \"%s\":\t", prevline, prevfile);
4298caf5
ML
796 prtree(stdout, p);
797 printf(" = ");
798 printval(p->nodetype);
799 putchar('\n');
800 }
801 prevline = curline;
0022c355 802 prevfile = curfile;
4298caf5
ML
803}
804
805/*
806 * Stop if the value of the given expression has changed.
807 */
808
809public stopifchanged(p)
810Node p;
811{
812 register Trinfo tp;
813 register int n;
814 char buff[MAXTRSIZE];
815 static Lineno prevline;
816
817 tp = findtrinfo(p);
818 n = size(p->nodetype);
819 dread(buff, tp->traddr, n);
820 if (tp->trvalue == nil) {
821 tp->trvalue = newarr(char, n);
822 mov(buff, tp->trvalue, n);
823 isstopped = true;
824 } else if (cmp(tp->trvalue, buff, n) != 0) {
825 mov(buff, tp->trvalue, n);
2fd0f574
SL
826 mov(buff, sp, n);
827 sp += n;
828 printf("after line %d:\t", prevline);
829 prtree(stdout, p);
830 printf(" = ");
831 printval(p->nodetype);
832 putchar('\n');
4298caf5
ML
833 isstopped = true;
834 }
835 prevline = curline;
836}
837
838/*
839 * Free the tracing table.
840 */
841
842public trfree()
843{
844 register Trinfo tp;
845
846 foreach (Trinfo, tp, trinfolist)
847 dispose(tp->trvalue);
848 dispose(tp);
849 list_delete(list_curitem(trinfolist), trinfolist);
850 endfor
851}
852
853/*
854 * Fix up breakpoint information before continuing execution.
855 *
856 * It's necessary to destroy events and breakpoints that were created
857 * temporarily and still exist because the program terminated abnormally.
858 */
859
860public fixbps()
861{
862 register Event e;
863 register Trcmd t;
864
865 single_stepping = false;
866 inst_tracing = false;
867 trfree();
868 foreach (Event, e, eventlist)
869 if (e->temporary) {
2fd0f574
SL
870 if (not delevent(e->id)) {
871 printf("!! dbx.fixbps: can't find event %d\n", e->id);
872 }
4298caf5
ML
873 }
874 endfor
875 foreach (Trcmd, t, eachline)
876 printrmtr(t);
877 list_delete(list_curitem(eachline), eachline);
878 endfor
879 foreach (Trcmd, t, eachinst)
880 printrmtr(t);
881 list_delete(list_curitem(eachinst), eachinst);
882 endfor
883}
884
885/*
886 * Set all breakpoints in object code.
887 */
888
889public setallbps()
890{
891 register Breakpoint p;
892
893 foreach (Breakpoint, p, bplist)
894 setbp(p->bpaddr);
895 endfor
896}
897
898/*
899 * Undo damage done by "setallbps".
900 */
901
902public unsetallbps()
903{
904 register Breakpoint p;
905
906 foreach (Breakpoint, p, bplist)
907 unsetbp(p->bpaddr);
908 endfor
909}