/********************************************************************** * Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. * * All Rights Reserved. * * Reference "/usr/src/COPYRIGHT" for applicable restrictions. * **********************************************************************/ /* * SCCSID: @(#)trace.c 3.0 4/21/86 * (System V) trace.c 1.2 */ /* ctrace - C program debugging tool * * trace code generation routines */ #include "global.h" #include <ctype.h> #define max(X, Y) (((int) X > (int) Y) ? X : Y) /* boolean fields in the marked array */ #define VAR_START 1 #define VAR_END 2 #define EXP_START 4 #define EXP_END 8 static enum bool too_many_vars = no; /* too many variables to trace */ static int marked[STMTMAX]; static int vtrace_count = 0; struct text { int start, end; }; static struct { struct text var; struct text exp; enum trace_type ttype; /* old C compiler does not allow structure member names to be the same */ } vtrace[TRACEMAX]; /* output the preprocessor statement */ putpp() { puttext(yyleng); /* add a #line statement surrounded by newlines so the next trace code is put on a new line */ printf("\n#line %d \"%s\"\n", yylineno, filename); } /* output the statement text as is */ puttext(end) register int end; { register int i; char *strcpy(); if (end >= yyleng) { /* a #if in dcl init list can make end > yyleng */ fputs(yytext, stdout); /* cannot use puts because it adds a newline */ yyleng = token_start = 0; } else { for (i = 0; i < end; ++i) putchar(yytext[i]); strcpy(yytext, yytext + end); yyleng = token_start = yyleng - end; } vtrace_count = 0; /* declarations can contain expressions */ } /* cleanup after tracing a statement */ reset() { vtrace_count = yyleng = token_start = 0; /* warn of too many variables to trace in this statement */ if (too_many_vars) { warning("some variables are not traced in this statement"); too_many_vars = no; } /* warn of a statement that was too long to fit in the buffer */ if (too_long) { warning("statement too long to trace"); puttext(yyleng); too_long = no; } } /* functions to maintain the variable trace list */ add_fcn(sym, exp_start, exp_end, type) struct symbol_struct sym; int exp_start, exp_end; enum trace_type type; { register int i; /* see if this function is being traced */ if (!trace) return; /* prevent unnecessary "too many vars" messages */ /* see if the variable is already being traced */ for (i = vtrace_count - 1; i >= 0; --i) if (vtrace[i].exp.start == sym.start && vtrace[i].exp.end == sym.end) { break; } /* if not, use the next trace element */ if (i < 0) if (vtrace_count < tracemax) i = vtrace_count++; else { too_many_vars = yes; return; } /* save the trace information */ vtrace[i].var.start = sym.start; vtrace[i].var.end = sym.end; vtrace[i].exp.start = exp_start; vtrace[i].exp.end = exp_end; vtrace[i].ttype = type; } expand_fcn(sym, new_start, new_end) struct symbol_struct sym; int new_start, new_end; { register int i; for (i = vtrace_count - 1; i >= 0; --i) if (vtrace[i].exp.start == sym.start && vtrace[i].exp.end == sym.end) { /* don't expand ++i to *++i */ if (sym.type != side_effect) { vtrace[i].exp.start = vtrace[i].var.start = new_start; vtrace[i].exp.end = vtrace[i].var.end = new_end; } break; } } rm_trace(sym) struct symbol_struct sym; { register int i; for (i = vtrace_count - 1; i >= 0; --i) if (vtrace[i].exp.start == sym.start && vtrace[i].exp.end == sym.end) { --vtrace_count; /* eliminate the hole */ for ( ; i < vtrace_count; ++i) vtrace[i] = vtrace[i + 1]; break; } } rm_all_trace(sym) struct symbol_struct sym; { register int i, j; for (i = vtrace_count - 1; i >= 0; --i) { if (vtrace[i].exp.start >= sym.start && vtrace[i].exp.start <= sym.end) { --vtrace_count; /* eliminate the hole */ for (j = i; j < vtrace_count; ++j) vtrace[j] = vtrace[j + 1]; } } } /* functions to trace the variables in a statement */ tr_vars(start, end) int start; register int end; /* register variables are in order of use */ { register int i, j; enum bool simple_trace(); /* don't trace a statement that was too long to fit in the buffer */ if (too_long) { return; } /* mark the significant characters */ for (i = start; i < end; ++i) marked[i] = 0; for (i = 0; i < vtrace_count; ++i) { marked[vtrace[i].exp.start] |= EXP_START; marked[vtrace[i].exp.end] |= EXP_END; marked[vtrace[i].var.end] |= VAR_END; } /* for each character in the statement */ for (i = start; i < end; ++i) { if (marked[i] & EXP_END) /* check for the end of a traced expression */ for (j = 0; j < vtrace_count; ++j) if (vtrace[j].exp.end == i) { if (!simple_trace(j)) { printf(", "); dump_code(j); transvar(vtrace[j].var); } printf("), "); if (vtrace[j].ttype == strres) printf("_ct"); else transvar(vtrace[j].var); /* check for a postfix ++/-- operator */ if (vtrace[j].ttype == postfix) { if (yytext[vtrace[j].exp.end - 1] == '+') putchar('-'); else putchar('+'); putchar('1'); } putchar(')'); } if (marked[i] & EXP_START) /* check for the start of a traced expression */ for (j = 0; j < vtrace_count; ++j) if (vtrace[j].exp.start == i) { putchar('('); if (simple_trace(j)) dump_code(j); else if (vtrace[j].ttype == strres) printf("_ct = "); } /* output this character */ putchar(yytext[i]); } } /* check for a simple variable trace */ static enum bool simple_trace(j) register int j; { register int k; if (vtrace[j].exp.start == vtrace[j].var.start && vtrace[j].exp.end == vtrace[j].var.end) { for (k = 0; k < vtrace_count; ++k) if (k != j) { /* if var is not this var */ if (vtrace[k].exp.start >= vtrace[j].var.start && vtrace[k].exp.end <= vtrace[j].var.end) break; /* this var has an embedded var */ if (vtrace[k].exp.start == vtrace[j].var.start || vtrace[k].exp.end == vtrace[j].var.end) break; /* this var is part of a larger var */ } if (k == vtrace_count) return(yes); } return(no); } /* dump routine call */ static dump_code(j) register int j; { register int k; register char c; if (vtrace[j].ttype == string || vtrace[j].ttype == strres) printf("s_ct_(\""); else /* unknown type */ printf("u_ct_(\""); for (k = 0; (c = indentation[k]) != '\0'; ++k) transchar(c); printf("/* "); putvar(vtrace[j].var); printf("\","); /* size of variable code */ if (vtrace[j].ttype != string && vtrace[j].ttype != strres) { printf("sizeof("); transvar(vtrace[j].var); printf("),"); } } /* output the variable's name */ static putvar(var) struct text var; { register int i; for (i = var.start; i < var.end; ++i) transchar(yytext[i]); } /* translate sub-exps containing '=', '++', and '--' ops into repeatable exps */ static transvar(var) struct text var; { register int i, j; /* don't check the first character for start of an expression */ putchar(yytext[var.start]); for (i = var.start + 1; i < var.end; ++i) { if (marked[i] & VAR_END) /* check for the end of a traced variable */ for (j = 0; j < vtrace_count; ++j) if (vtrace[j].var.end == i) { /* transform a postfix ++/-- operator into -/+ 1 */ if (vtrace[j].ttype == postfix) { if (yytext[vtrace[j].exp.end - 1] == '+') putchar('-'); else putchar('+'); printf("1)"); /* skip the postfix operator */ i = max(i, vtrace[j].exp.end - 1); goto skip; } /* skip the rest of a assignment expression */ if (vtrace[j].ttype == assign) { i = max(i, vtrace[j].exp.end - 1); goto skip; } } if (marked[i] & EXP_START) /* check for the start of a traced expression */ for (j = 0; j < vtrace_count; ++j) if (vtrace[j].exp.start == i) { /* insert a '(' in front of a postfix ++/-- expression */ if (vtrace[j].ttype == postfix) putchar('('); /* skip a prefix ++/-- operator */ if (vtrace[j].ttype == prefix) { i = max(i, vtrace[j].var.start - 1); goto skip; } } /* output this character */ putchar(yytext[i]); skip: ; } } /* trace the statement text */ tr_stmt(lineno, stmt, putsemicolon) int lineno; char *stmt; enum bool putsemicolon; { register int c, i; /* see if this function is being traced and */ /* don't trace a statement that was too long to fit in the buffer */ if (!trace || too_long) { return; } /* output the trace function call */ printf("t_ct_(\""); /* if the line number field should be blank */ if (lineno == NO_LINENO) { /* print a blank line number */ printf("\\n "); /* copy the leading blanks and tabs in the loop statement */ if (stmt[0] == '\n') /* skip a leading newline */ i = 1; else i = 0; for ( ; isspace(c = stmt[i]); ++i) transchar(c); i = 0; /* there isn't a newline in the statement text */ } /* if the statement starts on a new line */ else if (stmt[0] == '\n') { /* adjust the line number for any embedded new lines */ for (i = 1; (c = stmt[i]) != '\0'; ++i) if (c == '\n') --lineno; /* print the line number */ printf("\\n%3d ", lineno); i = 1; /* skip the newline in the statement text */ } else i = 0; /* convert special characters in the statement text */ for ( ; (c = stmt[i]) != '\0'; ++i) transchar(c); /* terminate the trace function call */ printf("\")"); /* see if this is to be a statement */ if (putsemicolon) printf("; "); } /* translate a character for a string constant */ static transchar(c) register int c; { switch (c) { case '"': printf("\\\""); break; case '\\': printf("\\\\"); break; case '\t': printf("\\t"); break; case '\n': printf("\\n"); break; default: putchar(c); } }