cvsuser 03/02/23 22:58:39
Modified: . MANIFEST jit_debug.c
docs running.pod
Added: docs debug.pod
Log:
Improve debugging support and documentation:
- added new document describing various debugging tricks
- added the PMC registers to the stabs type info
Revision Changes Path
1.318 +1 -0 parrot/MANIFEST
Index: MANIFEST
===================================================================
RCS file: /cvs/public/parrot/MANIFEST,v
retrieving revision 1.317
retrieving revision 1.318
diff -u -w -r1.317 -r1.318
--- MANIFEST 18 Feb 2003 20:36:59 -0000 1.317
+++ MANIFEST 24 Feb 2003 06:58:37 -0000 1.318
@@ -123,6 +123,7 @@
debug.ops
disassemble.c
disassemble.pl
+docs/debug.pod
docs/debugger.pod
docs/dev/byteorder.dev
docs/dev/dod.dev
1.9 +120 -25 parrot/jit_debug.c
Index: jit_debug.c
===================================================================
RCS file: /cvs/public/parrot/jit_debug.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -w -r1.8 -r1.9
--- jit_debug.c 16 Feb 2003 22:41:30 -0000 1.8
+++ jit_debug.c 24 Feb 2003 06:58:37 -0000 1.9
@@ -1,7 +1,7 @@
/*
* jit_debug.c
*
- * $Id: jit_debug.c,v 1.8 2003/02/16 22:41:30 scog Exp $
+ * $Id: jit_debug.c,v 1.9 2003/02/24 06:58:37 sfink Exp $
*
* write stabs file for jit code
* when debugging jit code with gdb, do:
@@ -13,9 +13,59 @@
#include <parrot/parrot.h>
#include "parrot/jit.h"
+#define N_GSYM "32" /* global variable */
+#define N_FNAME "34"
+#define N_FUN "36"
+#define N_STSYM "38" /* variable in data section */
+#define N_LCSYM "40" /* bss section */
+#define N_MAIN "42"
+#define N_ROSYM "44"
+#define N_PC "48"
+#define N_NSYMS "50"
+#define N_NOMAP "52"
+#define N_OBJ "56"
+#define N_OPT "60"
+#define N_RSYM "64" /* register variable */
+#define N_M2C "66"
+#define N_SLINE "68"
+#define N_DSLINE "70"
+#define N_BSLINE "72"
+#define N_BROWS "72"
+#define N_DEFD "74"
+#define N_FLINE "76"
+#define N_EHDECL "80"
+#define N_MOD2 "80"
+#define N_CATCH "84"
+#define N_SSYM "96"
+#define N_ENDM "98"
+#define N_SO "100" /* filename */
+#define N_LSYM "128" /* stack variable */
+#define N_BINCL "130"
+#define N_SOL "132"
+#define N_PSYM "160" /* parameter */
+#define N_EINCL "162"
+#define N_ENTRY "164"
+#define N_LBRAC "192"
+#define N_EXCL "194"
+#define N_SCOPE "196"
+#define N_RBRAC "224"
+#define N_BCOMM "226"
+#define N_ECOMM "228"
+#define N_ECOML "232"
+#define N_WITH "234"
+#define N_NBTEXT "240"
+#define N_NBDATA "242"
+#define N_NBBSS "244"
+#define N_NBSTS "246"
+#define N_NBLCS "248"
+
#ifdef __GNUC__
void Parrot_jit_debug(struct Parrot_Interp* interpreter);
+#define BIT_SIZE(t) ((int)(sizeof(t)*8))
+#define BYTE_SIZE(t) ((int)sizeof(t))
+#define BIT_OFFSET(str, field) ((int)(offsetof(str, field) * 8))
+
typedef struct {
const char *name;
const char *spec;
@@ -23,7 +73,7 @@
static void
write_types(FILE *stabs)
{
- int i;
+ int i, j;
/* borrowed from mono */
static BaseTypes base_types[] = {
{"Void", "(0,1)"},
@@ -61,11 +111,10 @@
} else {
fprintf (stabs, "%s\"", base_types[i].spec);
}
- fprintf (stabs, ",128,0,0,0\n");
+ fprintf (stabs, "," N_LSYM ",0,0,0\n");
}
fprintf(stabs, ".stabs \"STRING:t(0,%d)=*(0,%d)\""
- ",128,0,0,0\n", i, i+1);
- i++;
+ "," N_LSYM ",0,0,0\n", i, i+1);
fprintf(stabs, ".stabs \"Parrot_String:T(0,%d)=s%d"
"bufstart:(0,14),%d,%d;"
"buflen:(0,6),%d,%d;" /* XXX type */
@@ -73,18 +122,60 @@
"bufused:(0,12),%d,%d;"
"strstart:(0,15),%d,%d;" /* fake a char* */
";\""
- ",128,0,0,0\n", i++, (int) sizeof(STRING),
- (int)(offsetof(STRING, bufstart) * 8),
- (int)(sizeof(void *)* 8),
- (int)(offsetof(STRING, buflen) * 8),
- (int)(sizeof(size_t) * 8),
- (int)(offsetof(STRING, obj.flags) * 8),
- (int)(sizeof(UINTVAL) * 8),
- (int)(offsetof(STRING, bufused) * 8),
- (int)(sizeof(UINTVAL) * 8),
- (int)(offsetof(STRING, strstart) * 8),
- (int)(sizeof(void *) * 8)
+ "," N_LSYM ",0,0,0\n", i++, BYTE_SIZE(STRING),
+ BIT_OFFSET(STRING, bufstart), BIT_SIZE(void*),
+ BIT_OFFSET(STRING, buflen), BIT_SIZE(size_t),
+ BIT_OFFSET(STRING, obj.flags), BIT_SIZE(UINTVAL),
+ BIT_OFFSET(STRING, bufused), BIT_SIZE(UINTVAL),
+ BIT_OFFSET(STRING, strstart), BIT_SIZE(void*)
+ );
+
+ fprintf(stabs, ".stabs \"PMCType:T(0,%d)=e", i++);
+ for (j = 0; j < enum_class_max; ++j) {
+ if (Parrot_base_vtables[j].name) {
+ STRING* name = (*Parrot_base_vtables[j].name)(NULL, NULL);
+ fwrite(name->strstart, name->strlen, 1, stabs);
+ fprintf(stabs, ":%d,", j);
+ }
+ }
+ fprintf(stabs, ";\"," N_LSYM ",0,0,0\n");
+
+ /* PMC type */
+ fprintf(stabs, ".stabs \"PMC:T(0,%d)=s%d", i, BYTE_SIZE(PMC));
+ fprintf(stabs, "obj:(0,%d),%d,%d;",
+ i + 1, BIT_OFFSET(PMC, obj), BIT_SIZE(pobj_t));
+ fprintf(stabs, "vtable:*(0,%d),%d,%d;",
+ i + 3, BIT_OFFSET(PMC, vtable), BIT_SIZE(void*));
+ fprintf(stabs, "data:(0,14),%d,%d;",
+ BIT_OFFSET(PMC, data), BIT_SIZE(void*));
+ fprintf(stabs, "metadata:*(0,%d),%d,%d;",
+ i, BIT_OFFSET(PMC, metadata), BIT_SIZE(void*));
+ fprintf(stabs, ";\"");
+ fprintf(stabs, "," N_LSYM ",0,0,0\n");
+
+ fprintf(stabs, ".stabs \"pobj_t:T(0,%d)=s%d"
+ "u:(0,%d),%d,%d;"
+ "flags:(0,12),%d,%d;"
+ ";\""
+ "," N_LSYM ",0,0,0\n", i + 1, (int)(sizeof(pobj_t)),
+ i + 2, BIT_OFFSET(pobj_t, u), BIT_SIZE(UnionVal),
+ BIT_OFFSET(pobj_t, flags), BIT_SIZE(Parrot_UInt)
+ );
+ fprintf(stabs, ".stabs \"UnionVal:T(0,%d)=u%d"
+ "int_val:(0,12),%d,%d;"
+ "pmc_val:*(0,%d),%d,%d;"
+ ";\""
+ "," N_LSYM ",0,0,0\n", i + 2, BYTE_SIZE(UnionVal),
+ BIT_OFFSET(UnionVal, int_val), BIT_SIZE(INTVAL),
+ i, BIT_OFFSET(UnionVal, pmc_val), BIT_SIZE(void*)
+ );
+ fprintf(stabs, ".stabs \"VTABLE:T(0,%d)=s%d"
+ "base_type:(0,%d),%d,%d;"
+ ";\""
+ "," N_LSYM ",0,0,0\n", i + 3, BYTE_SIZE(UnionVal),
+ i - 1, BIT_OFFSET(VTABLE, base_type), BIT_SIZE(INTVAL)
);
+ i += 4;
}
@@ -94,12 +185,14 @@
int i;
/* fake static var stabs */
for (i = 0; i < NUM_REGISTERS; i++) {
- fprintf(stabs, ".stabs \"I%d:S(0,12)\",38,0,0,%p\n", i,
+ fprintf(stabs, ".stabs \"I%d:S(0,12)\"," N_STSYM ",0,0,%p\n", i,
(char*)&interpreter->ctx.int_reg.registers[i]);
- fprintf(stabs, ".stabs \"N%d:S(0,13)\",38,0,0,%p\n", i,
+ fprintf(stabs, ".stabs \"N%d:S(0,13)\"," N_STSYM ",0,0,%p\n", i,
(char*)&interpreter->ctx.num_reg.registers[i]);
- fprintf(stabs, ".stabs \"S%d:S(0,16)\",38,0,0,%p\n", i,
+ fprintf(stabs, ".stabs \"S%d:S(0,16)\"," N_STSYM ",0,0,%p\n", i,
(char*)&interpreter->ctx.string_reg.registers[i]);
+ fprintf(stabs, ".stabs \"P%d:S*(0,18)\"," N_STSYM ",0,0,%p\n", i,
+ (char*)&interpreter->ctx.pmc_reg.registers[i]);
}
}
@@ -156,10 +249,10 @@
return;
/* filename info */
- fprintf(stabs, ".stabs \"%s\",100,0,0,0\n",
+ fprintf(stabs, ".stabs \"%s\"," N_SO ",0,0,0\n",
string_to_cstring(interpreter, pasmfile));
/* jit_func start addr */
- fprintf(stabs, ".stabs \"jit_func:F(0,1)\",36,0,1,%p\n",
+ fprintf(stabs, ".stabs \"jit_func:F(0,1)\"," N_FUN ",0,1,%p\n",
jit_info->arena.start);
write_types(stabs);
@@ -169,22 +262,24 @@
*/
/* jit_begin */
- fprintf(stabs, ".stabn 68,0,1,0\n");
+ fprintf(stabs, ".stabn " N_SLINE ",0,1,0\n");
line = 1;
lc = 0;
for (i = 0; i < jit_info->arena.map_size; i++) {
if (jit_info->arena.op_map[i].ptr) {
+ op_info_t* op =
&interpreter->op_info_table[interpreter->code->byte_code[i]];
if (interpreter->code->cur_cs->debug) {
line = (int)interpreter->code->cur_cs->debug->base.data[lc++];
}
- fprintf(stabs, ".stabn 68,0,%d,%d\n", line,
+ fprintf(stabs, ".stabn " N_SLINE ",0,%d,%d /* %s */\n", line,
(int)((char *)jit_info->arena.op_map[i].ptr -
- (char *)jit_info->arena.start));
+ (char *)jit_info->arena.start),
+ op->full_name);
line++;
}
}
/* eof */
- fprintf(stabs, ".stabs \"\",36,0,1,%p\n",
+ fprintf(stabs, ".stabs \"\"," N_FUN ",0,1,%p\n",
(char *) jit_info->arena.size);
fclose(stabs);
/* run the stabs file through C<as> generating file.o */
1.12 +1 -1 parrot/docs/running.pod
Index: running.pod
===================================================================
RCS file: /cvs/public/parrot/docs/running.pod,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -w -r1.11 -r1.12
--- running.pod 21 Oct 2002 08:47:08 -0000 1.11
+++ running.pod 24 Feb 2003 06:58:39 -0000 1.12
@@ -65,7 +65,7 @@
make libparrot.a
gcc -O3 -g -Iinclude -c foo.c -o foo.o
- gcc -g -o foo foo.o -L. -lparrot -ldl
+ gcc -g -o foo foo.o -L. -lparrot -ldl -lm
./foo # Runs it
=item B<make test>
1.1 parrot/docs/debug.pod
Index: debug.pod
===================================================================
=head1 TITLE
Debugging Parrot
=head1 HISTORY
=over 4
=item Version 1.0
First version by Steve Fink <[EMAIL PROTECTED]>
=back
=head1 ABSTRACT
This document describes ways to debug various parts of Parrot.
=head1 THE PARROT BINARY
First, you'll want to use the --debugging flag with Configure.pl to
generate debugging symbols for the parrot binary:
shell> perl Configure.pl --debugging
shell> make
You can then run the parrot binary under gdb.
=head2 MEMORY MANAGEMENT
Some of the more frequent and exasperating parrot bugs are related to
memory management in general, and garbage collection in particular.
=head3 Infant mortality
See L<dev/infant.dev> for details of one frequent problem: infant
mortality. Infant mortality is when you create a Parrot object, but
the garbage collector runs before you put it into a Parrot register or
in something else that is itself within a Parrot register.
To help in resolving these issues, the parrot binary accepts a
--gc-debug flag that makes such problems much more likely to occur (it
makes garbage collection occur as frequently as possible, to maximize
the probability that any newborn objects will run afoul of the garbage
collector if they are improperly coded.)
Within the --gc-debug mode, there is another tool to help narrow down
the problem. If you edit include/parrot/parrot.h and #define the
C<GC_VERBOSE> flag to 1, then after the garbage collector has traced
all objects to find which ones are still alive, it will scan through
all of the dead objects to see if any of them believe they are alive
(which will happen for infants, since they come into existence marked
live.) If it finds any, it will print them out. You can then re-run
the program with a breakpoint set on the routine that allocated the
object (e.g. C<get_free_object> in C<smallobject.c>). You'll probably
want to make the breakpoint conditional on the object having the
version number that was reported, because the same memory location
will probably hold many different objects over the lifetime of the
program.
=head1 IMCC AND PASM CODE
Let's say you have written (or generated) a huge .pasm or .imc file.
It's not working. You'd like some help in figuring out why.
=head2 pdb
One possible tool is C<pdb>, the Parrot Debugger. See L<debugger.pod>
for details on it.
=head2 stabs
If you are running on a jit-capable machine, you can also try using
GDB by having the JIT generate C<stabs> metadata and then stepping
through the code with GDB as if it were any other language.
To use this, you'll want to use C<imcc> to generate your bytecode
(.pbc file). It is not strictly necessary, but you'll get more
information into the bytecode this way.
Let's say your file is named C<test.pasm>. (Note: these instructions
will also work if you use C<test.imc> everywhere C<test.pasm> occurs.)
Step 1: Generate the .pbc file with extra debugging information.
shell> imcc -d -o test.pbc test.pasm
Step 2: Start up parrot under GDB
shell> gdb parrot
or
shell> emacs &
(in emacs) M-x gdb
(in emacs) type "parrot" so it says "gdb parrot"
Step 3: Set a breakpoint on runops_jit
gdb> b runops_jit
Step 4: Run your program under GDB with JIT and debugging on
gdb> run -j -d test.pbc
Step 5: GDB will stop at the beginning of runops_jit. Step through the
lines until just before the JITted code is executed (the line will be
something like C<(jit_code)(interpreter,pc)>.
gdb> n
gdb> n
.
.
.
Step 6: load in the debugging information from the symbol file that
the jit just generated.
gdb> add-symbol-file test.o 0
Step 7: Step into the JITted code
gdb> s
At this point, you can step through the instructions, or print out the
various Parrot registers. GDB will know about I0-I31, N0-N31, S0-S31,
and P0-P31.
=head3 WARNING: Stepping too far
One thing to watch out for is that GDB gets confused when attempting
to step over certain instructions. The only ones that I have noticed
having problems is keyed operations. With my version of GDB, if I do
'n' to step over the instruction, GDB will start running and only stop
when the entire parrot program has finished. To work around this, do
'si' twice just before executing any keyed op. For some reason, GDB
can then figure out when it's supposed to stop next. If you know of a
better technique, please let the mailing list know
(C<[EMAIL PROTECTED]>).
=head1 IMCC CODE GENERATION
The C<imcc> binary has a bunch of debugging flags for spewing out
information about various aspects of its processing. See
L<languages/imcc/docs/running.pod> for a list of flags.