2005-08-26 17:39:27 +00:00
|
|
|
#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
|
2005-10-04 01:21:34 +00:00
|
|
|
if (fp == fmtend) {
|
2005-08-26 17:39:27 +00:00
|
|
|
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;
|
|
|
|
}
|
2005-10-04 01:21:34 +00:00
|
|
|
}
|
2005-08-26 17:39:27 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|