|
|
1.1 root 1: (setq rcs-trace-
2: "$Header: /usr/lib/lisp/RCS/trace.l,v 1.2 83/08/15 22:30:36 jkf Exp $")
3:
4: ;---- The Joseph Lister Trace Package, v1
5: ; John Foderaro, Sept 1979
6: ;------------------------------------------------------------------;
7: ; Copyright (c) 1979 The Regents of the University of California ;
8: ; All rights reserved. ;
9: ;------------------------------------------------------------------;
10: (eval-when (eval)
11: (setq old-read-table-trace readtable)
12: (setq readtable (makereadtable t))
13: (setq old-uctolc-value (status uctolc))
14: (sstatus uctolc nil) ; turn off case conversion
15: (load 'charmac)
16: (setsyntax '\; 'macro 'zapline)
17: )
18:
19:
20:
21: ;----
22: ; trace uses these properties on the property list:
23: ; trace-orig-fcn: original occupant of the function cell
24: ; trace-trace-fcn: the value trace puts in the function cell
25: ; (used to check if the trace function has be overwritten).
26: ; trace-trace-args: the arguments when function was traced.
27: ; trace-printargs: function to print argument to function
28: ; trace-printres: function to print result of function
29:
30: (declare (nlambda T-status T-sstatus)
31: (special piport
32: if ifnot evalin evalout
33: printargs printres evfcn
34: traceenter traceexit
35: prinlevel prinlength
36: $$traced-functions$$ ; all functions being traced
37: $$functions-in-trace$$ ; active functions
38: $$funcargs-in-trace$$ ; arguments to active functions.
39: $tracemute ; if t, then enters and exits
40: ; are quiet, but info is still
41: ; kept so (tracedump) will work
42: trace-prinlevel ; default values
43: trace-prinlength
44: trace-printer ; function trace uses to print
45: ))
46:
47:
48:
49: (cond ((null (boundp '$$traced-functions$$)) (setq $$traced-functions$$ nil)))
50: (cond ((null (boundp '$$functions-in-trace$$)) (setq $$functions-in-trace$$ nil)))
51: (cond ((null (boundp '$$funcargs-in-trace$$)) (setq $$funcargs-in-trace$$ nil)))
52: (cond ((null (boundp '$tracemute)) (setq $tracemute nil)))
53: (cond ((null (boundp 'trace-prinlevel)) (setq trace-prinlevel 4)))
54: (cond ((null (boundp 'trace-prinlength)) (setq trace-prinlength 5)))
55: (cond ((null (boundp 'trace-printer)) (setq trace-printer 'Trace-print)))
56:
57: ;----> It is important that the trace package not use traced functions
58: ; thus we give the functions the trace package uses different
59: ; names and make them equivalent at this time to their
60: ; traceable counterparts.
61: (defun trace-startup-func nil
62: (do ((i '( (add1 T-add1)(append T-append)
63: (and T-and) (apply T-apply)
64: (cond T-cond) (cons T-cons) (delq T-delq)
65: (def T-def) (do T-do) (drain T-drain)
66: (dtpr T-dtpr) (eval T-eval)(funcall T-funcall)
67: (get T-get) (getd T-getd)(getdisc T-getdisc)
68: (greaterp T-greaterp)(lessp T-lessp)
69: (mapc T-mapc) (not T-not)(nreverse T-nreverse)
70: (patom T-patom) (print T-print) (prog T-prog)
71: (patom T-patom)(putd T-putd)
72: (putprop T-putprop)
73: (read T-read)(remprop T-remprop) (reverse T-reverse)
74: (return T-return)
75: (set T-set) (setq T-setq)
76: (status T-status) (sstatus T-sstatus)
77: (sub1 T-sub1) (terpr T-terpr)
78: (zerop T-zerop))
79: (cdr i)))
80: ((null i))
81: (putd (cadar i) (getd (caar i)))
82: (putprop (cadar i) t 'Untraceable)))
83:
84: (trace-startup-func)
85:
86:
87: (putprop 'quote t 'Untraceable) ; this prevents the common error
88: ; of (trace 'foo) from causing big
89: ; problems.
90:
91: ;--- trace - arg1,arg2, ... names of functions to trace
92: ; This is the main user callable trace routine.
93: ; work in progress, documentation incomplete since im not sure exactly
94: ; where this is going.
95: ;
96: (def trace
97: (nlambda (argl)
98: (prog (if ifnot evalin evalout funnm typ
99: funcd did break printargs printres evfcn traceenter traceexit
100: traceargs)
101:
102: ; turn off transfer table linkages if they are on
103: (cond ((T-status translink) (T-sstatus translink nil)))
104:
105: ; process each argument
106:
107: (do ((ll argl (cdr ll))
108: (funnm)
109: (funcd))
110: ((null ll))
111: (setq funnm (car ll)
112: if t
113: break nil
114: ifnot nil
115: evalin nil
116: evalout nil
117: printargs nil
118: printres nil
119: evfcn nil
120: traceenter 'T-traceenter
121: traceexit 'T-traceexit
122: traceargs nil)
123:
124: ; a list as an argument means that the user is specifying
125: ; conditions on the trace
126: (cond ((not (atom funnm))
127: (cond ((not (atom (setq funnm (car funnm))))
128: (T-print (car funnm))
129: (T-patom '" is non an function name")
130: (go botloop)))
131: ; remember the arguments in case a retrace is requested
132: (setq traceargs (cdar ll))
133: ; scan the arguments
134: (do ((rr (cdar ll) (cdr rr)))
135: ((null rr))
136: (cond ((memq (car rr) '(if ifnot evalin evalout
137: printargs printres evfcn
138: traceenter traceexit))
139: (T-set (car rr) (cadr rr))
140: (setq rr (cdr rr)))
141: ((eq (car rr) 'evalinout)
142: (setq evalin (setq evalout (cadr rr))
143: rr (cdr rr)))
144: ((eq (car rr) 'break)
145: (setq break t))
146: ((eq (car rr) 'lprint)
147: (setq printargs 'T-levprint
148: printres 'T-levprint))
149: (t (T-patom '"bad request: ")
150: (T-print (car rr))
151: (T-terpr)))))
152: (t (setq traceargs nil) ;no args given
153: ))
154:
155: ; if function is untraceable, print error message and skip
156: (cond ((get funnm 'Untraceable)
157: (setq did (cons `(,funnm untraceable) did))
158: (go botloop)))
159:
160:
161: ; Untrace before tracing
162: (let ((res (funcall 'untrace (list funnm))))
163: (cond (res (setq did (cons `(,funnm untraced) did)))))
164:
165: ; store the names of the arg printing routines if they are
166: ; different than print
167:
168: (cond (printargs (T-putprop funnm printargs 'trace-printargs)))
169: (cond (printres (T-putprop funnm printres 'trace-printres)))
170: (T-putprop funnm traceargs 'trace-trace-args)
171:
172: ; we must determine the type of function being traced
173: ; in order to create the correct replacement function
174:
175: (cond ((setq funcd (T-getd funnm))
176: (cond ((bcdp funcd) ; machine code
177: (cond ((or (eq 'lambda (T-getdisc funcd))
178: (eq 'nlambda (T-getdisc funcd))
179: (eq 'macro (T-getdisc funcd)))
180: (setq typ (T-getdisc funcd)))
181: ((stringp (T-getdisc funcd)) ; foreign func
182: (setq typ 'lambda)) ; close enough
183: (t (T-patom '"Unknown type of compiled function")
184: (T-print funnm)
185: (setq typ nil))))
186:
187: ((dtpr funcd) ; lisp coded
188: (cond ((or (eq 'lambda (car funcd))
189: (eq 'lexpr (car funcd)))
190: (setq typ 'lambda))
191: ((or (eq 'nlambda (car funcd))
192: (eq 'macro (car funcd)))
193: (setq typ (car funcd)))
194: (t (T-patom '"Bad function definition: ")
195: (T-print funnm)
196: (setq typ nil))))
197: ((arrayp funcd) ; array
198: (setq typ 'lambda))
199: (t (T-patom '"Bad function defintion: ")
200: (T-print funnm)))
201:
202: ; now that the arguments have been examined for this
203: ; function, do the tracing stuff.
204: ; First save the old function on the property list
205:
206: (T-putprop funnm funcd 'trace-orig-fcn)
207:
208: ; now build a replacement
209:
210: (cond
211: ((eq typ 'lambda)
212: (T-eval
213: `(T-def
214: ,funnm
215: (lexpr (T-nargs)
216: ((lambda (T-arglst T-res T-rslt
217: $$functions-in-trace$$
218: $$funcargs-in-trace$$)
219: (T-do ((i T-nargs (T-sub1 i)))
220: ((T-zerop i))
221: (T-setq T-arglst
222: (T-cons (arg i) T-arglst)))
223: (T-setq $$funcargs-in-trace$$
224: (T-cons T-arglst
225: $$funcargs-in-trace$$))
226: (T-cond ((T-setq T-res
227: (T-and ,if
228: (T-not ,ifnot)))
229: (,traceenter ',funnm T-arglst)
230: ,@(cond (evalin
231: `((T-patom ,'":in: ")
232: ,evalin
233: (T-terpr))))
234: (T-cond (,break
235: (trace-break)))))
236: (T-setq T-rslt
237: ,(cond
238: (evfcn)
239: (t `(T-apply
240: ',funcd
241: T-arglst))))
242: (T-cond (T-res
243: ,@(cond (evalout
244: `((T-patom ,'":out: ")
245: ,evalout
246: (T-terpr))))
247: (,traceexit ',funnm T-rslt)))
248: T-rslt)
249: nil nil nil
250: (T-cons ',funnm $$functions-in-trace$$)
251: $$funcargs-in-trace$$))))
252: (T-putprop funnm (T-getd funnm) 'trace-trace-fcn)
253: (setq did (cons funnm did)
254: $$traced-functions$$ (cons funnm
255: $$traced-functions$$)))
256:
257: ((or (eq typ 'nlambda)
258: (eq typ 'macro))
259: (T-eval
260: `(T-def ,funnm
261: (,typ (T-arglst)
262: ((lambda (T-res T-rslt
263: $$functions-in-trace$$
264: $$funcargs-in-trace$$)
265: (T-setq $$funcargs-in-trace$$
266: (T-cons
267: T-arglst
268: $$funcargs-in-trace$$))
269: (T-cond ((T-setq
270: T-res
271: (T-and ,if
272: (not ,ifnot)))
273: (,traceenter
274: ',funnm
275: T-arglst)
276: ,evalin
277: (T-cond (,break
278: (trace-break)))))
279: (T-setq T-rslt
280: ,(cond
281: (evfcn `(,evfcn
282: ',funcd
283: T-arglst))
284: (t `(T-apply ',funcd
285: T-arglst))))
286: (T-cond (T-res
287: ,evalout
288: (,traceexit ',funnm T-rslt)))
289: T-rslt)
290: nil nil
291: (cons ',funnm $$functions-in-trace$$)
292: $$funcargs-in-trace$$))))
293: (T-putprop funnm (T-getd funnm) 'trace-trace-fcn)
294: (setq did (cons funnm did)
295: $$traced-functions$$ (cons funnm
296: $$traced-functions$$)))
297:
298: (t (T-patom '"No such function as: ")
299: (T-print funnm)
300: (T-terpr)))))
301: botloop )
302: ; if given no args, just return the function currently being traced
303: (return (cond ((null argl) $$traced-functions$$)
304: (t (T-nreverse did)))))))
305:
306: ;--- untrace
307: ; (untrace foo bar baz)
308: ; untraces foo, bar and baz.
309: ; (untrace)
310: ; untraces all functions being traced.
311: ;
312:
313: (def untrace
314: (nlambda (argl)
315: (cond ((null argl) (setq argl $$traced-functions$$)))
316:
317: (do ((i argl (cdr i))
318: (tmp)
319: (curf)
320: (res))
321: ((null i)
322: (cond ((null $$traced-functions$$)
323: (setq $$functions-in-trace$$ nil)
324: (setq $$funcargs-in-trace$$ nil)))
325: res)
326: (cond ((and (T-getd (setq curf (car i)))
327: (eq (T-getd (car i))
328: (get (car i) 'trace-trace-fcn)))
329: ; we only want to restore the original definition
330: ; if this function has not been redefined!
331: ; we test this by checking to be sure that the
332: ; trace-trace-property is the same as the function
333: ; definition.
334: (T-putd curf (get curf 'trace-orig-fcn))
335: (T-remprop curf 'trace-orig-fcn)
336: (T-remprop curf 'trace-trace-fcn)
337: (T-remprop curf 'trace-trace-args)
338: (T-remprop curf 'entercount)
339: (setq $$traced-functions$$
340: (T-delq curf $$traced-functions$$))
341: (setq res (cons curf res)))))))
342:
343:
344: ;--- retrace :: trace again all function thought to be traced.
345: ;
346: (def retrace
347: (nlambda (args)
348: (cond ((null args) (setq args $$traced-functions$$)))
349: (mapcan '(lambda (fcn)
350: (cond ((and (symbolp fcn)
351: (not (eq (T-getd fcn)
352: (get fcn 'trace-trace-fcn))))
353:
354: (funcall 'trace
355: `((,fcn ,@(get fcn 'trace-trace-args)))))))
356: args)))
357:
358: ;--- tracedump :: dump the currently active trace frames
359: ;
360: (def tracedump
361: (lambda nil
362: (let (($tracemute nil))
363: (T-tracedump-recursive $$functions-in-trace$$
364: $$funcargs-in-trace$$))))
365:
366:
367: ;--- traceargs :: return list of args to currently entered traced functions
368: ; call is:
369: ; (traceargs foo) returns first call to foo starting at most current
370: ; (traceargs foo 3) returns args to third call to foo, starting at
371: ; most current
372: ;
373: (def traceargs
374: (nlambda (args)
375: (cond ((and args $$functions-in-trace$$)
376: (let ((name (car args))
377: (amt (cond ((numberp (cadr args)) (cadr args))
378: (t 1))))
379: (do ((fit $$functions-in-trace$$ (cdr fit))
380: (fat $$funcargs-in-trace$$ (cdr fat)))
381: ((null fit))
382: (cond ((eq name (car fit))
383: (cond ((zerop (setq amt (1- amt)))
384: (return (car fat))))))))))))
385:
386: ;--- T-tracedump-recursive
387: ; since the lists of functions being traced and arguments are in the reverse
388: ; of the order we want to print them, we recurse down the lists and on the
389: ; way back we print the information.
390: ;
391: (def T-tracedump-recursive
392: (lambda ($$functions-in-trace$$ $$funcargs-in-trace$$)
393: (cond ((null $$functions-in-trace$$))
394: (t (T-tracedump-recursive (cdr $$functions-in-trace$$)
395: (cdr $$funcargs-in-trace$$))
396: (T-traceenter (car $$functions-in-trace$$)
397: (car $$funcargs-in-trace$$))))))
398:
399:
400:
401: ;--- T-traceenter - funnm : name of function just entered
402: ; - count : count to print out
403: ; This routine is called to print the entry banner for a
404: ; traced function.
405: ;
406: (def T-traceenter
407: (lambda (name args)
408: (prog (count indent)
409: (cond ((not $tracemute)
410: (setq count 0 indent 0)
411: (do ((ll $$functions-in-trace$$ (cdr ll)))
412: ((null ll))
413: (cond ((eq (car ll) name) (setq count (1+ count))))
414: (setq indent (1+ indent)))
415:
416: (T-traceindent indent)
417: (T-print count)
418: (T-patom '" <Enter> ")
419: (T-print name)
420: (T-patom '" ")
421: (cond ((setq count (T-get name 'trace-printargs))
422: (funcall count args))
423: (t (funcall trace-printer args)))
424: (T-terpr))))))
425:
426: (def T-traceexit
427: (lambda (name res)
428: (prog (count indent)
429: (cond ((not $tracemute)
430: (setq count 0 indent 0)
431: (do ((ll $$functions-in-trace$$ (cdr ll)))
432: ((null ll))
433: (cond ((eq (car ll) name) (setq count (1+ count))))
434: (setq indent (1+ indent)))
435:
436:
437: (T-traceindent indent)
438: (T-print count)
439: (T-patom " <EXIT> ")
440: (T-print name)
441: (T-patom " ")
442:
443: (cond ((setq count (T-get name 'trace-printres))
444: (funcall count res))
445: (t (funcall trace-printer res)))
446:
447: (T-terpr))))))
448:
449:
450: ;--- Trace-printer
451: ; this is the default value of trace-printer. It prints a form after
452: ; binding prinlevel and prinlength.
453: ;
454: (def Trace-print
455: (lambda (form)
456: (let ((prinlevel trace-prinlevel)
457: (prinlength trace-prinlength))
458: (T-print form))))
459:
460: ; T-traceindent
461: ; - n : indent to column n
462:
463: (def T-traceindent
464: (lambda (col)
465: (do ((i col (1- i))
466: (char '| |))
467: ((< i 2))
468: (T-patom (cond ((eq char '| |) (setq char '\|))
469: (t (setq char '| |)))))))
470: ; from toplevel.l:
471: ;
472: ;--- read and print functions are user-selectable by just
473: ; assigning another value to top-level-print and top-level-read
474: ;
475: (declare (special top-level-read top-level-print))
476:
477: (defmacro top-print (&rest args)
478: `(cond (top-level-print (funcall top-level-print ,@args))
479: (t (T-print ,@args))))
480:
481: (defmacro top-read (&rest args)
482: `(cond ((and top-level-read
483: (T-getd top-level-read))
484: (funcall top-level-read ,@args))
485: (t (T-read ,@args))))
486:
487:
488: ; trace-break - this is the trace break loop
489: (def trace-break
490: (lambda nil
491: (prog (tracevalread piport)
492: (T-terpr) (T-patom '"[tracebreak]")
493: loop (T-terpr)
494: (T-patom '"T>")
495: (T-drain)
496: (cond ((or (eq nil (setq tracevalread
497: (car
498: (errset (top-read nil nil)))))
499: (and (dtpr tracevalread)
500: (eq 'tracereturn (car tracevalread))))
501: (T-terpr)
502: (return nil)))
503: (top-print (car (errset (T-eval tracevalread))))
504: (go loop))))
505:
506:
507: (def T-levprint
508: (lambda (x)
509: ((lambda (prinlevel prinlength)
510: (T-print x))
511: 3 10)))
512:
513:
514: (eval-when (eval)
515: (apply 'sstatus `(uctolc ,old-uctolc-value))
516: (setq readtable old-read-table-trace)
517: )
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.