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