aboutsummaryrefslogtreecommitdiff
path: root/code/tools/lcc/src/trace.c
diff options
context:
space:
mode:
Diffstat (limited to 'code/tools/lcc/src/trace.c')
-rw-r--r--code/tools/lcc/src/trace.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/code/tools/lcc/src/trace.c b/code/tools/lcc/src/trace.c
new file mode 100644
index 0000000..3b9ba78
--- /dev/null
+++ b/code/tools/lcc/src/trace.c
@@ -0,0 +1,181 @@
+#include "c.h"
+
+
+static char *fmt, *fp, *fmtend; /* format string, current & limit pointer */
+static Tree args; /* printf arguments */
+static Symbol frameno; /* local holding frame number */
+
+/* appendstr - append str to the evolving format string, expanding it if necessary */
+static void appendstr(char *str) {
+ do
+ if (fp == fmtend) {
+ if (fp) {
+ char *s = allocate(2*(fmtend - fmt), FUNC);
+ strncpy(s, fmt, fmtend - fmt);
+ fp = s + (fmtend - fmt);
+ fmtend = s + 2*(fmtend - fmt);
+ fmt = s;
+ } else {
+ fp = fmt = allocate(80, FUNC);
+ fmtend = fmt + 80;
+ }
+ }
+ while ((*fp++ = *str++) != 0);
+ fp--;
+}
+
+/* tracevalue - append format and argument to print the value of e */
+static void tracevalue(Tree e, int lev) {
+ Type ty = unqual(e->type);
+
+ switch (ty->op) {
+ case INT:
+ if (ty == chartype || ty == signedchar)
+ appendstr("'\\x%02x'");
+ else if (ty == longtype)
+ appendstr("0x%ld");
+ else
+ appendstr("0x%d");
+ break;
+ case UNSIGNED:
+ if (ty == chartype || ty == unsignedchar)
+ appendstr("'\\x%02x'");
+ else if (ty == unsignedlong)
+ appendstr("0x%lx");
+ else
+ appendstr("0x%x");
+ break;
+ case FLOAT:
+ if (ty == longdouble)
+ appendstr("%Lg");
+ else
+ appendstr("%g");
+ break;
+ case POINTER:
+ if (unqual(ty->type) == chartype
+ || unqual(ty->type) == signedchar
+ || unqual(ty->type) == unsignedchar) {
+ static Symbol null;
+ if (null == NULL)
+ null = mkstr("(null)");
+ tracevalue(cast(e, unsignedtype), lev + 1);
+ appendstr(" \"%.30s\"");
+ e = condtree(e, e, pointer(idtree(null->u.c.loc)));
+ } else {
+ appendstr("("); appendstr(typestring(ty, "")); appendstr(")0x%x");
+ }
+ break;
+ case STRUCT: {
+ Field q;
+ appendstr("("); appendstr(typestring(ty, "")); appendstr("){");
+ for (q = ty->u.sym->u.s.flist; q; q = q->link) {
+ appendstr(q->name); appendstr("=");
+ tracevalue(field(addrof(e), q->name), lev + 1);
+ if (q->link)
+ appendstr(",");
+ }
+ appendstr("}");
+ return;
+ }
+ case UNION:
+ appendstr("("); appendstr(typestring(ty, "")); appendstr("){...}");
+ return;
+ case ARRAY:
+ if (lev && ty->type->size > 0) {
+ int i;
+ e = pointer(e);
+ appendstr("{");
+ for (i = 0; i < ty->size/ty->type->size; i++) {
+ Tree p = (*optree['+'])(ADD, e, consttree(i, inttype));
+ if (isptr(p->type) && isarray(p->type->type))
+ p = retype(p, p->type->type);
+ else
+ p = rvalue(p);
+ if (i)
+ appendstr(",");
+ tracevalue(p, lev + 1);
+ }
+ appendstr("}");
+ } else
+ appendstr(typestring(ty, ""));
+ return;
+ default:
+ assert(0);
+ }
+ e = cast(e, promote(ty));
+ args = tree(mkop(ARG,e->type), e->type, e, args);
+}
+
+/* tracefinis - complete & generate the trace call to print */
+static void tracefinis(Symbol printer) {
+ Tree *ap;
+ Symbol p;
+
+ *fp = 0;
+ p = mkstr(string(fmt));
+ for (ap = &args; *ap; ap = &(*ap)->kids[1])
+ ;
+ *ap = tree(ARG+P, charptype, pointer(idtree(p->u.c.loc)), 0);
+ walk(calltree(pointer(idtree(printer)), freturn(printer->type), args, NULL), 0, 0);
+ args = 0;
+ fp = fmtend = 0;
+}
+
+/* tracecall - generate code to trace entry to f */
+static void tracecall(Symbol printer, Symbol f) {
+ int i;
+ Symbol counter = genident(STATIC, inttype, GLOBAL);
+
+ defglobal(counter, BSS);
+ (*IR->space)(counter->type->size);
+ frameno = genident(AUTO, inttype, level);
+ addlocal(frameno);
+ appendstr(f->name); appendstr("#");
+ tracevalue(asgn(frameno, incr(INCR, idtree(counter), consttree(1, inttype))), 0);
+ appendstr("(");
+ for (i = 0; f->u.f.callee[i]; i++) {
+ if (i)
+ appendstr(",");
+ appendstr(f->u.f.callee[i]->name); appendstr("=");
+ tracevalue(idtree(f->u.f.callee[i]), 0);
+ }
+ if (variadic(f->type))
+ appendstr(",...");
+ appendstr(") called\n");
+ tracefinis(printer);
+}
+
+/* tracereturn - generate code to trace return e */
+static void tracereturn(Symbol printer, Symbol f, Tree e) {
+ appendstr(f->name); appendstr("#");
+ tracevalue(idtree(frameno), 0);
+ appendstr(" returned");
+ if (freturn(f->type) != voidtype && e) {
+ appendstr(" ");
+ tracevalue(e, 0);
+ }
+ appendstr("\n");
+ tracefinis(printer);
+}
+
+/* trace_init - initialize for tracing */
+void trace_init(int argc, char *argv[]) {
+ int i;
+ static int inited;
+
+ if (inited)
+ return;
+ inited = 1;
+ type_init(argc, argv);
+ if (IR)
+ for (i = 1; i < argc; i++)
+ if (strncmp(argv[i], "-t", 2) == 0 && strchr(argv[i], '=') == NULL) {
+ Symbol printer = mksymbol(EXTERN,
+ argv[i][2] ? &argv[i][2] : "printf",
+ ftype(inttype, ptr(qual(CONST, chartype))));
+ printer->defined = 0;
+ attach((Apply)tracecall, printer, &events.entry);
+ attach((Apply)tracereturn, printer, &events.returns);
+ break;
+ }
+}