summaryrefslogtreecommitdiff
path: root/bcc/debug.c
diff options
context:
space:
mode:
Diffstat (limited to 'bcc/debug.c')
-rw-r--r--bcc/debug.c386
1 files changed, 201 insertions, 185 deletions
diff --git a/bcc/debug.c b/bcc/debug.c
index 2b1e12e..2ccda5d 100644
--- a/bcc/debug.c
+++ b/bcc/debug.c
@@ -1,200 +1,216 @@
-/* debug.c - print debug messages for operators for bcc */
-
-/* Copyright (C) 1992 Bruce Evans */
-
-#include "bcc.h"
-
-#ifdef DEBUG
-#include "gencode.h"
-#include "reg.h"
-#include "sc.h"
-#include "scan.h"
-#include "type.h"
-
-PRIVATE char *opname[LASTOP - FIRSTOP + 1] = /* operator names */
-{ /* order must agree with op.h */
- "cond?",
- "or",
- "eor",
- "and",
- "gt", "lt",
- "add",
- "div", "mod",
- "lognot", "not",
- "strucelt", "strucptr",
- "eq",
- "addab", "andab", "divab", "eorab", "modab", "mulab", "orab",
- "slab", "srab", "subab",
- "comma",
- "cond:",
- "logor",
- "logand",
- "logeq",
- "ne",
- "ge", "le",
- "sl", "sr",
- "sub",
- "mul",
- "address", "cast", "indirect", "neg",
- "predec", "preinc", "postdec", "postinc",
- "func", "list", "rootlist",
- "leaf",
- "ptraddab", "ptradd", "ptrsub",
-};
-
-FORWARD void outindchars P((int byte, indn_pt count));
-
-PUBLIC void dbitem(item)
-struct symstruct *item;
+/*
+ * debug.c: a generic debugging facility for unix programs.
+ *
+ * The calling program is required to call debug_setlevel(lvl) to set
+ * which messages will be displayed. The level is a two part value
+ * where the least significant (decimal) digit is a level as described
+ * below. The most significant digits are a class code. For a message
+ * to be displayed the class code must either be zero or match the
+ * class code of the debug(...) message.
+ *
+ * The 'debug(lvl, fmt, ...)' function displays debugging messages
+ * complete with source and line number. The function can be used
+ * as a normal one in if() smt else smt constructs. It returns the
+ * actual number of bytes printed so it's return value can be used
+ * inside an if(debug(...)) to enable more debugging code. This code
+ * will be removed by the compiler (as dead code) if debugging is
+ * not enabled.
+ *
+ * The level on the debug() statment also consists of a level and class
+ * code where the class code must be zero or match the setlevel's class
+ * code for the message to be displayed.
+ *
+ * Level 0
+ * Always displayed if the debugging is enabled.
+ * You probably shouldn't use this.
+ *
+ * Level 1
+ * Important state changes and errors that cause a significant change
+ * in program flow.
+ *
+ * Level 2
+ * Rare things that cause a minor program flow adjustment.
+ *
+ * Level 3
+ * Errors and useful messages that are slightly too verbose or common
+ * for 0-2 or don't quite fit in the classifications.
+ *
+ * Level 4
+ * All remote responses or major results. (Trace results)
+ *
+ * Level 5
+ * All remote commands or major tasks. (Trace jobs)
+ *
+ * Level 6
+ * General information that will not be too verbose but is normally a
+ * little less important. (Trace state)
+ *
+ * Level 7
+ * Similar to level 3 but verbose or not as useful.
+ *
+ * Level 8
+ * Very verbose information that'll probably be useful sometime.
+ *
+ * Level 9
+ * Anything and everything else, debugs that probably won't be useful
+ * ever again. (unclassified)
+ *
+ * Notes:
+ * If the programmer doesn't set the debug level this is not an important
+ * debug message or is only important right now.
+ * => default debug level == 9
+ *
+ * If something fits in one of the lower levels but is very verbose
+ * it should nevertheless be moved upto level 3 or levels 7-9.
+ * (Possibly leaving a single line 'oops' at the lower level)
+ *
+ * The general idea is that debug levels 0-3 should not scroll too fast
+ * to read and nothing below level 7 should be much more verbose than
+ * levels 4 or 5.
+ *
+ *****************************************************************************
+ *
+ * 2004-06-20: Added __STDC__ to debug.h so it can be called from non-ansi
+ * compiler. This file still needs ansi or unproto.
+ *
+ * 2004-06-20: Added check of DEBUG environment variable if setlevel isn't
+ * called before a debug().
+ *
+ * 2004-06-20: Added #define VARARG_MACROS so the preprocessor can remove
+ * all the debugging 'stuff'.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "debug.h"
+
+#define USE_DBPRINTF
+
+#ifndef DEBUG
+static char ident[] =
+ "$Id: debug.c: (c) 1995-2004 Robert de Bath. Debugging disabled. $";
+#else
+static char ident[] =
+ "$Id: debug.c: (c) 1995-2004 Robert de Bath. Debugging enabled. $";
+
+static char * db_file = 0;
+static int db_lineno = 0;
+static int disp_state = 0;
+static int disp_pos(void);
+
+static void debug_envvar(void);
+
+int debug_level = -1;
+
+void debug_do_setlevel(char * fname, int lineno, int level)
{
- dbtype(item->type);
- if (item->storage == NOSTORAGE)
- {
- outbyte(' ');
- outstr(item->name.namep + 2);
- outstr(" (offset ");
- outshex(item->offset.offi);
- outbyte(')');
- return;
- }
- if (item->storage == LOCAL)
- {
- outbyte(' ');
- if (item->flags == TEMP)
- outstr("(temp)");
- else
- outstr(item->name.namep);
- }
- outstr(" = ");
- outindchars('[', item->indcount);
- switch (item->storage)
- {
- case CONSTANT:
- outstr("const ");
- if (item->type->scalar & RSCALAR)
- outstr("(whatever)");
- else if (item->type->scalar & UNSIGNED)
- outuvalue((uvalue_t) item->offset.offv);
- else
- outvalue(item->offset.offv);
- break;
- case BREG:
- case DREG:
- case INDREG0:
- case INDREG1:
- case INDREG2:
-#ifdef DATREG1
- case DATREG1:
-#endif
-#ifdef DATREG2
- case DATREG2:
-#endif
- outregname(item->storage);
- if (item->level == OFFKLUDGELEVEL)
- {
- outplus();
- if (item->flags & LABELLED)
- outlabel(item->name.label);
- else
- outccname(item->name.namep);
- }
- break;
- case LOCAL:
- outbyte('S');
- if (sp <= 0)
- outplus();
- outshex(-sp);
- break;
- case GLOBAL:
- if (item->flags & LABELLED)
- outlabel(item->name.label);
- else
- outstr(item->name.namep);
- break;
- default:
- outstr("bad storage (");
- outhex((uoffset_T) item->storage);
- outbyte(')');
- outstr(" offset ");
- }
- if (item->storage != CONSTANT)
- {
- if (item->offset.offi >= 0)
- outplus();
- outshex(item->offset.offi);
- }
- outindchars(']', item->indcount);
+ if(level || !debug_level)
+ debug_level = level;
+ debug_pos(fname, lineno);
+ debug_msg(1, "Debug level now %d", level);
+ debug_level = level;
}
-PUBLIC void dbtype(type)
-struct typestruct *type;
+int debug_pos(char * file, int lineno)
{
- for ( ; type != NULL; type = type->nexttype)
- {
- outbyte(' ');
- switch (type->constructor)
- {
- case ARRAY:
- outbyte('[');
- outhex(type->typesize / type->nexttype->typesize);
- outbyte(']');
- break;
- case FUNCTION:
- outstr("()");
- break;
- case POINTER:
- outbyte('*');
- break;
- case STRUCTU:
- outstr("struct ");
- default:
- if (type->scalar & UNSIGNED)
- outstr("unsigned ");
- outstr(type->tname);
- break;
- }
- }
+ db_file = file;
+ db_lineno = lineno;
+ disp_state |= 1;
+ return disp_pos();
+}
+
+int debug_msg(int level, char * fmt, ...)
+{
+ va_list ap;
+ int rv = 0;
+ int disp = 0;
+
+ if (debug_level == -1) debug_envvar();
+
+ if (level == -1) {
+ level = 0;
+ disp_state |= 1;
+ db_lineno = -1;
+ }
+
+ disp_state |= 2;
+
+ if (level>9 || debug_level>9) {
+ disp = (level%10 <= debug_level%10);
+ if (disp && level>9 && debug_level>9 && level/10 != debug_level/10)
+ disp = 0;
+ } else disp = (level <= debug_level);
+
+ if (disp)
+ {
+ disp_state |= 4;
+
+ va_start(ap, fmt);
+#ifdef USE_DBPRINTF
+ rv = vdbprintf(fmt, ap);
+#else
+ rv = vfprintf(stderr, fmt, ap);
+#endif
+ va_end(ap);
+ }
+ return rv + disp_pos();
}
-PUBLIC void debug(exp) /* sub-nodes must be leaves */
-struct nodestruct *exp;
+int
+disp_pos()
{
- if (!debugon)
- return;
- outstr("! Debug: ");
- if (exp->tag < FIRSTOP && exp->tag > LASTOP)
- outstr("unknown op");
- else
- outstr(opname[exp->tag - FIRSTOP]);
- if (exp->right != NULL && exp->tag != FUNCOP &&
- exp->tag != LISTOP && exp->tag != ROOTLISTOP)
- {
- dbitem(exp->right->left.symptr);
- outstr(" to");
- }
- dbitem(exp->left.nodeptr->left.symptr);
- outstr(" (used reg = ");
- if (reguse & INDREG0)
- outregname(INDREG0);
- if (reguse & INDREG1)
- outregname(INDREG1);
- if (reguse & INDREG2)
- outregname(INDREG2);
- outnstr(")");
+ int rv = 0;
+ if (disp_state == 7 && db_lineno != -1)
+#ifdef USE_DBPRINTF
+ rv = dbprintf(" at %s:%d\n", db_file, db_lineno);
+#else
+ rv = fprintf(stderr, " at %s:%d\n", db_file, db_lineno);
+#endif
+
+ if ((disp_state&3) == 3) {
+ db_file = 0;
+ db_lineno = disp_state = 0;
+ }
+ return rv;
}
-PUBLIC void debugswap()
+/* If setlevel isn't called check the environment */
+
+static void debug_envvar(void)
{
- if (debugon)
- outnstr("! Debug: expression subtree swapping");
+ char * p = getenv("DEBUG");
+ if (!p || !*p)
+ debug_level = 0;
+ else
+ debug_level = atoi(p);
+ if (debug_level)
+#ifdef USE_DBPRINTF
+ dbprintf("Debug level now %d from environment.\n", debug_level);
+#else
+ fprintf(stderr, "Debug level now %d from environment.\n", debug_level);
+#endif
}
-PRIVATE void outindchars(byte, count)
-int byte;
-indn_pt count;
+#endif
+
+#ifndef VARARG_MACROS
+/*
+ * This function should never be called.
+ *
+ * If ident sees the message in a binary then your compiler is wasting
+ * space by allocating it for unused strings.
+ *
+ * We know GNU-C is ok, but it complains.
+ */
+int debug_never(int level, char * name, ...)
{
- while (count--)
- outbyte(byte);
+#ifndef __GNUC__
+ 1?0:debug_never(0, "$Warning: Debugging strings exist in non-debug binary $");
+#endif
+ return 0;
}
+#endif
-#endif /* DEBUG */