Hi all, The following are patches to allow dynamic (ie runtime) selection of the printf() debugging used in Kaffe. (Very useful for generating traces, etc.) Basically, each block of debug code (inside the DBG() macro) is tagged. At runtime a selection of debugs tags can be set, and all matching statements are executed. (It currently uses an int as a bitmask to tag sections of code.) See the example below. This specifically adds the files debug.[ch] to kaffe/kaffevm/, adds DEBUG$(OBJEXT) as a target in the Makefile, and adds the '-vmdebug ' flag to kaffe/kaffe/main.c. I don't have any patches against any of the kaffevm sources to actually use any of this. (I figured they would be out of date by now.) So, you'll actually have to change the DBG() statements that you do use over to this system. The diffs are against v0.8.4, but should fit into any recent release. The debugging cruft is implemented as macros, these macros completely disappear when not compiled with -DDEBUG or with -DNDEBUG. The basic macro is DBG(tag, statements) where tag is one of the tags defined in debug.h (or a bitwise OR of two or more) and statements are any set of statements that you only want executed when debugging under that tag. For example, I've got the following code in classLoader.c:loadClass() ... if (loader != NULL) { Hjava_lang_String* str; DBG(DBG_CLASS_LOAD, printf("classLoader: loading %s\n", name->data); ) str = makeReplaceJavaStringFromUtf8(name->data, name->length, '/', '.'); class = (Hjava_lang_Class*) do_execute_java_method(NULL, (Hjava_lang_Object*)loader, loadClassName, loadClassSig, 0, false, str, true); DBG(DBG_CLASS_LOAD, printf("classLoader: done\n"); ) } else { ... Given this, if I start kaffe with 'kaffe -vmdebug CLASS_LOAD Main', then it will execute the printfs() above (because the tags match). Since the tags are represented as bits, you can OR them together (as in 'kaffe -vmdebug CLASS_LOAD|CLASS_PREPARE Main' or whatever.) This doesn't substitute for a good debugger, but what it can provide (which a debugger might not) is a trace of execution. I find it very handy for localizing errors right when they occur--just re-run kaffe with debugging flags on and you're set--no recompilation necessary. Hopefully some of you might find this useful. Suggestions, bugs, and feature creep encouraged, to tullmann@cs.utah.edu. Also, let me know if there are any problems with the diff, I'm new to this patch stuff. -Pat Index: kaffe/kaffevm/Makefile.in =================================================================== RCS file: /n/fast/usr/lsrc/mach/CVS/kaffe/kaffe/kaffevm/Makefile.in,v retrieving revision 1.1.1.2.2.1 diff -u -b -r1.1.1.2.2.1 Makefile.in --- kaffe/kaffevm/Makefile.in 1997-04-24 16:44:46-06 1.1.1.2.2.1 +++ kaffe/kaffevm/Makefile.in 1997-04-25 14:38:59-06 @@ -60,6 +60,7 @@ verify$(OBJEXT) \ code-analyse$(OBJEXT) \ exception$(OBJEXT) \ + debug$(OBJEXT) \ md$(OBJEXT) all: mkkaffevm Index: kaffe/kaffevm/debug.c =================================================================== RCS file: /n/fast/usr/lsrc/mach/CVS/kaffe/kaffe/kaffevm/Attic/debug.c,v retrieving revision 1.1 retrieving revision 1.1.2.1 diff -u -b -r1.1 -r1.1.2.1 --- kaffe/kaffevm/debug.c 1997-04-24 17:43:15-06 1.1 +++ kaffe/kaffevm/debug.c 1997-04-24 17:43:15-06 1.1.2.1 @@ -0,0 +1,100 @@ +/* + * debug.c + * + * A dynamic debugging framework for kaffe. Through the magic + * of hiedous macros, we can control the debugging output of + * kaffe in a couple of ways. First, it can be completely + * disabled in which case all of the code "just goes away", + * or, if its enabled, the area of code to debug is dynamically, + * chosen at run time. + * + * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * Written by Patrick Tullmann , 1997 + */ + +#include "config.h" +#include "config-std.h" +#include "config-mem.h" +#include "debug.h" + +/* Default debugging mask to use (if debug is enabled) */ +#define DEFAULT_DEBUG_MASK DBG_SETUP + +#if defined(NDEBUG) || !defined(DEBUG) +/* Don't waste space with the debugging functions */ + +void dbgSetMask(int m) { } +void dbgSetMaskStr(char *s) { } + +#else /* Actually define the functions */ + +int kaffevmDebugMask = DBG_SETUP; + +void dbgSetMask(int mask) +{ + kaffevmDebugMask = mask; +} + +/* + * Associate strings with an option or set of + * options. Each name, x, below (in the D() macro) + * is associated with the DBG_x tag. + */ +static struct debug_opts { + char *name; + int mask; +} debug_opts[] = { +#define D(name) { #name, DBG_ ## name } + D(GC), + D(SETUP), + D(CLASS_LOAD), + D(CLASS_LINK), + D(CLASS_PREPARE), + D(CLASS), + D(ZIP), + D(NATIVE_METH), + D(LOOKUP_METH), + D(LOOKUP_FIELD), + D(LOOKUP_EXC), + D(LOOKUP), + D(ALL), + D(CLASS_STATE), + { "init", DBG_SETUP|DBG_CLASS|DBG_ZIPFILE } +}; + + +void dbgSetMaskStr(char *mask_str) +{ + int i; + char *separators = "|,"; + char *opt; + + if (!opt) { + kaffevmDebugMask = DEFAULT_DEBUG_MASK; + return; + } + + opt = strtok(mask_str, separators); + + while (opt) { + for (i = 0; i < (sizeof debug_opts)/(sizeof(debug_opts[0])); i++) + /* probably should strcasecmp() or stricmp() */ + if (!strcmp(opt, debug_opts[i].name)) { + kaffevmDebugMask |= debug_opts[i].mask; + break; + } + + /* Be polite. */ + if (i == (sizeof debug_opts)/(sizeof(debug_opts[0]))) + fprintf(stderr, "Unknown flag (%s) passed to -vmdebug\n", + opt); + + /* Get next opt */ + opt = strtok(NULL, separators); + } +} +#endif + Index: kaffe/kaffevm/debug.h =================================================================== RCS file: /n/fast/usr/lsrc/mach/CVS/kaffe/kaffe/kaffevm/Attic/debug.h,v retrieving revision 1.1 retrieving revision 1.1.2.1 diff -u -b -r1.1 -r1.1.2.1 --- kaffe/kaffevm/debug.h 1997-04-24 17:43:16-06 1.1 +++ kaffe/kaffevm/debug.h 1997-04-24 17:43:16-06 1.1.2.1 @@ -0,0 +1,88 @@ +/* + * debug.c + * + * A dynamic debugging framework for kaffe. Through the magic + * of hiedous macros, we can control the debugging output of + * kaffe in a couple of ways. First, it can be completely + * disabled in which case all of the code "just goes away", + * or, if its enabled, the area of code to debug is dynamically, + * chosen at run time. + * + * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * Written by Patrick Tullmann , 1997 + */ +#ifndef __kaffevm_debug_h +#define __kaffevm_debug_h + +/* Defines what debugging output is seen. Needs to be 32-bit. */ +extern int kaffevmDebugMask; + +#if defined(NDEBUG) || !defined(DEBUG) +/* --- Debugging is NOT enabled --- */ + +/* Replace the mask set functions with empty macros */ +# define DBG(mask, statement) { ((void)0); } + +# define DBGEXPR(mask, expr, default) (default) + +# define DBGPRINT(mask, printfargs) { ((void)0); } + +#else +/* --- Debugging is enabled --- */ + +/* Set the debugging mask to use. (give the mask) */ +void dbgSetMask(int mask); + +/* Set the debugging mask to use. (give a string, useful for + * parsing a command line option. */ +void dbgSetMaskStr(char *mask_str); + +/* Debug Masks: (1 bit per) */ +/* NOTE: Many of these names are silly, and there is probably a + * better organization. Feel free to throw away names and fixup + * the groupings. */ +# define DBG_GC (0) +# define DBG_SETUP (1<<1) +# define DBG_CLASS_LOAD (1<<2) +# define DBG_CLASS_LINK (1<<3) +# define DBG_CLASS_PREPARE (1<<4) +# define DBG_CLASS (DBG_CLASS_LOAD|DBG_CLASS_LINK|DBG_CLASS_PREPARE|DBG_CLASS_STATE) +# define DBG_ZIPFILE (1<<5) +# define DBG_NATIVE_METH (1<<6) + /* lookup.c: */ +# define DBG_LOOKUP_METH (1<<7) +# define DBG_LOOKUP_FIELD (1<<8) +# define DBG_LOOKUP_EXC (1<<9) +# define DBG_LOOKUP (DBG_LOOKUP_METH|DBG_LOOKUP_FIELD|DBG_LOOKUP_EXC) +# define DBG_METHOD (1<<10) +# define DBG_FIELD (1<<11) +# define DBG_CLASS_STATE (1<<12) + +# define DBG_ALL (0xFFFFFFFF) + +/* Debug macros that are selected with the above flags. */ + +# define DBG(mask, statement) { \ + if ((mask)&kaffevmDebugMask) { \ + statement; \ + }} + + +/* XXX probably doesn't do right thing with default... */ +# define DBGEXPR(mask, expr, default) \ + (((mask)&kaffevmDebugMask)&(expr)) + +/* If only all the world used GNU CPP, which lets macros take a variable + * number of arguments... */ +# define DBGPRINT(mask, printfargs) { \ + if ((mask)&kaffevmDebugMask) { \ + printf printfargs; \ + }} + + +#endif /* defined(NDEBUG) || !defined(DEBUG) */ + +#endif /* __kaffevm_debug_h */ Index: kaffe/kaffe/main.c =================================================================== RCS file: /n/fast/usr/lsrc/mach/CVS/kaffe/kaffe/kaffe/main.c,v retrieving revision 1.1.1.2 retrieving revision 1.1.1.2.2.2 diff -u -b -r1.1.1.2 -r1.1.1.2.2.2 --- main.c 1997-04-18 12:24:55-06 1.1.1.2 +++ main.c 1997-04-25 14:31:56-06 1.1.1.2.2.2 @@ -31,6 +31,9 @@ Hjava_lang_Object* AllocObjectArray(int, char*); Hjava_lang_String* makeJavaString(char*, int); extern jword do_execute_java_class_method(char*, char*, char*, ...); +#ifdef DEBUG +void dbgSetMaskStr(char *mask_str); +#endif extern char* engine_name; extern char* engine_version; @@ -167,6 +170,16 @@ else if (strcmp(argv[i], "-verbose") == 0 || strcmp(argv[i], "-v") == 0) { flag_classload = 1; } +#ifdef DEBUG + else if (strcmp(argv[i], "-vmdebug") == 0) { + i++; + if (argv[i] == 0) { /* forgot second arg */ + fprintf(stderr, "Error: -vmdebug option requires a debug flag.\n"); + exit(1); + } + dbgSetMaskStr(argv[i]); + } +#endif else if (strcmp(argv[i], "-debug") == 0) { flag_trace = 1; } @@ -229,6 +242,11 @@ fprintf(stderr, " -v, -verbose Be verbose\n"); fprintf(stderr, " -verbosejit Print message during JIT code generation\n"); fprintf(stderr, " -debug Trace method calls\n"); +#ifdef DEBUG + fprintf(stderr, " -vmdebug Internal VM debugging. See kaffe/kaffevm/debug.h\n"); +#else + fprintf(stderr, " -vmdebug Not available, must compile with -DDEBUG."); +#endif fprintf(stderr, " -noasyncgc * Do not garbage collect asynchronously\n"); fprintf(stderr, " -cs, -checksource * Check source against class files\n"); fprintf(stderr, " -ms * Initial heap size\n");