# Copyright (C) 2001-2004, The Perl Foundation.
# $Id: /mirror/trunk/docs/debug.pod 35409 2009-01-11T03:55:39.964567Z allison  $

=head1 NAME

docs/debug.pod - Debugging Parrot

=head1 ABSTRACT

This document describes how to debug various parts of Parrot.

=head1 VERSION

$Revision $

=head1 THE PARROT BINARY

=head2 Using a debugger

Per default the C<parrot> binary is being built with debugging symbols. This
means that you can run C<parrot> under an debugger like C<gdb>.

Debugging support can be explicitly enabled with:

    shell> perl Configure.pl --debugging
    shell> make

For testing it might be a good idea to make test runs without debug support. So
debugging can also be turned off with:

  shell> perl Configure.pl --debugging=0
  shell> make

=head2 Using a memory checker

You could, and should, also run the tests with a memory checker such as
C<valgrind>.  You can enable C<valgrind>, by running:

  shell> make test VALGRIND="valgrind --log-file=/tmp/grind"

Another possibility is to use Electric Fence, or ...

=head2 MEMORY MANAGEMENT

Some of the more frequent and exasperating C<parrot> bugs are related to memory
management in general, and garbage collection in particular.

Infant mortality

See F<docs/dev/infant.pod> 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 C<--gc-debug>
flag. This flag makes garbage collection occur as frequently as possible, which
maximizes the probability that any newborn objects will run afoul of the
garbage collector.

Within the C<--gc-debug> mode, there is another tool to help narrow down the
problem. You can edit F<src/gc/api.c> and C<#define> the C<GC_VERBOSE> flag to
1.  After recompiling C<parrot>, the garbage collector will perform additional
checks. 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 F<src/gc/mark_sweep.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 PIR AND PASM CODE

Let's say you have written (or generated) a huge .pasm or .pir file.  It's not
working. You'd like some help in figuring out why.

=head2 parrot_debugger

One possible tool is C<parrot_debugger>, the Parrot Debugger.
See F<docs/debugger.pod> for details on it.

=head2 stabs

If you are running on a jit-capable machine, you can also try using C<gdb> by
having the JIT compiler generate C<stabs> metadata and then stepping through
the code with C<gdb> as if it were any other language.

To use this, you'll want to use C<parrot> 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.pir> everywhere C<test.pasm> occurs.)

Step 1: Generate the .pbc file with extra debugging information.

  shell> parrot -d -o test.pbc test.pasm

Step 2: Start up C<parrot> under C<gdb>

  % gdb parrot

or

  % 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 C<gdb> with JIT and debugging on

  gdb> run -j -D4 test.pbc

Step 5: C<gdb> will stop at the beginning of runops_jit. Step through the lines
until just before the JITed 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 JITed code

  gdb> s

At this point, you can step through the instructions, or print out the
various Parrot registers. FIXME: C<gdb> will know about I0-I31,
N0-N31, S0-S31, and P0-P31.


WARNING: Stepping too far

One thing to watch out for is that C<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 C<gdb>, if I do 'n' to step over the
instruction, C<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, C<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<parrot-porters@perl.org>).

=head1 PIR CODE GENERATION

The C<parrot> binary has a bunch of debugging flags for spewing out information
about various aspects of its processing. See L<running.pod> for a
list of flags. Or have a look at the information provided by:

  shell> parrot --help

or

  shell> parrot --help-debug


=head1 BACKTRACING

=head2 auto-magical

If Parrot is built on a system with GNU libc it is capable of automatically
generating a backtrace on C<stderr> for debugging purposes.  Currently these
automatically backtraces are only generated by assertion failures but in the
future they also be produced by other bad events (for example, C<SEGV>).

Here is an example of a what a backtrace might look like:

    Backtrace - Obtained 15 stack frames (max trace depth is 32).
      (unknown)
        Parrot_confess
          Parrot_make_COW_reference
            Parrot_String_get_string
              Parrot_set_s_p
                (unknown)
                  (unknown)
                    (unknown)
                      (unknown)
                        Parrot_runops_fromc_args
                          Parrot_runcode
                            (unknown)
                              imcc_run
                                (unknown)
                                  __libc_start_main
                                    (unknown)

It must be noted that glibc's backtraces are not without limitation.  It's
method depends completely on information that is available at run time.

=over

=item * Functions marked as C<static> can only be identified by address as they
have no "symbol name" for dynamic linking in the executable's symbol table.
Static functions will appears as C<(unknown)>.

=item * There must be some means available for walking the stack at runtime.
On x86(-64)? the "stack pointer" must be in C<[re]sp> register.  For example,
this C<gcc> compliiation flag would break backtracing (except for functions
that do dynamic allocation on the stack as this optimization can no be allied
to them).  C<perl Configure.pl --ccflags=-fomit-frame-pointer>

=item * Some platforms may require extra linker flags in order to get all of
the required symbols exported in the symbol table.  C<Configure.pl
--ccflags=-rdynamic>

=item * Any debugging information embedded in the object is not accessible.  So
file and line number can not be included as part of the backtrace information.

=item * Be warned that signals may cause incorrect backtraces!

=back

=head2 gdb

On systems not equipped with libc, one will need to use an external debugger to
get backtrace information.   This method is actually more capable then the
L<auto-magical> approach as most debuggers will use debugging information if
it's available in the object code (for example, if parrot was built with
C<-g>).

Since the C<Parrot_confess> symbol is I<always> compiled into parrot it can be
used as a break point to obtain a backtrace.  Here is an example of doing this
with gdb and a version of parrot compiled with C<gcc> and the C<-g> flag.

    $ gdb parrot
    GNU gdb 6.6
    Copyright (C) 2006 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    Type "show copying" to see the conditions.
    There is absolutely no warranty for GDB.  Type "show warranty" for details.
    This GDB was configured as "i686-pc-linux-gnu"...
    Using host libthread_db library "/lib/libthread_db.so.1".
    (gdb) b main
    Breakpoint 1 at 0x80488a0: file src/main.c, line 38.
    (gdb) r foo.pir
    Starting program: /home/moanui/jhoblitt/parrot/parrot foo.pir
    Failed to read a valid object file image from memory.
    [Thread debugging using libthread_db enabled]
    [New Thread -1213900128 (LWP 23148)]
    [Switching to Thread -1213900128 (LWP 23148)]

    Breakpoint 1, main (argc=-400292727, argv=0x159a0) at src/main.c:38
    38      {
    (gdb) b Parrot_confess
    Breakpoint 2 at 0xb7c542a0: file src/exceptions.c, line 767.
    (gdb) c
    Continuing.
    [New Thread -1214039152 (LWP 23151)]
    [New Thread -1222431856 (LWP 23152)]
    1..1

    Breakpoint 2, Parrot_confess (cond=0xb7eeda65 "s", 
        file=0xb7eeda58 "src/string.c", line=129) at src/exceptions.c:767
    warning: Source file is more recent than executable.
    767     {
    (gdb) bt full
    #0  Parrot_confess (cond=0xb7eeda65 "s", file=0xb7eeda58 "src/string.c", 
        line=129) at src/exceptions.c:767
    No locals.
    #1  0xb7c433b1 in Parrot_make_COW_reference (interp=0x804e008, s=0x0)
        at src/string.c:129
            d = (STRING *) 0x81c21b8
            __PRETTY_FUNCTION__ = "Parrot_make_COW_reference"
    #2  0xb7e40db3 in Parrot_String_get_string (interp=0x804e008, pmc=0x81c8578)
        at src/pmc/string.c:310
    No locals.
    #3  0xb7cc7d41 in Parrot_set_s_p (cur_opcode=0x825d470, interp=0x804e008)
        at src/ops/set.ops:159
    No locals.
    #4  0xb7c9da32 in runops_slow_core (interp=0x804e008, pc=0x825d470)
        at src/runops_cores.c:184
    No locals.
    #5  0xb7c67acf in runops_int (interp=0x804e008, offset=0)
        at src/interpreter.c:816
            pc = (opcode_t * const) 0x8239730
            lo_var_ptr = 134537224
            core = (opcode_t *(*)(Parrot_Interp, 
        opcode_t *)) 0xb7c9d940 <runops_slow_core at src/runops_cores.c:169>
    #6  0xb7c6854e in runops (interp=0x804e008, offs=0) at src/inter_run.c:100
            offset = 0
            old_runloop_id = 0
            our_runloop_level = 1
            our_runloop_id = 1
    #7  0xb7c687da in runops_args (interp=0x804e008, sub=0x8204d58, obj=0x80912d8, 
        meth_unused=0x0, sig=0xb7eefca6 "vP", 
        ap=0xbfec614c "@M \bï¿½bï¿½ï¿½Pï¿½\222K\230ï¿½\004\b@\236\"\b@M \bXM
	    \b\004ï¿½ï¿½ï¿½ï¿½tï¿½ï¿½\bï¿½\004\b\001") at src/inter_run.c:216
            offset = 0
            dest = (opcode_t *) 0x8239730
            ctx = (Parrot_Context *) 0x822a3b0
            new_sig = ""
            sig_p = 0xb7eefca7 "P"
            old_ctx = (Parrot_Context * const) 0x804e298
    #8  0xb7c688fb in Parrot_runops_fromc_args (interp=0x804e008, sub=0x8204d58, 
        sig=0xb7eefca6 "vP") at src/inter_run.c:293
            args = 0xbfec614c "@M \bï¿½bï¿½ï¿½Pï¿½\222K\230ï¿½\004\b@\236\"\b@M
		\bXM \b\004ï¿½ï¿½ï¿½ï¿½tï¿½ï¿½\bï¿½\004\b\001"
            ctx = (Parrot_Context *) 0xb7fa1548
    #9  0xb7c50c51 in Parrot_runcode (interp=0x804e008, argc=1, argv=0xbfec62e8)
        at src/embed.c:783
            userargv = (PMC *) 0x8204d40
            main_sub = (PMC *) 0x8204d58
    #10 0xb7ed74a1 in imcc_run_pbc (interp=0x804e008, obj_file=0, output_file=0x0, 
        argc=1, argv=0xbfec62e8) at compilers/imcc/main.c:614
    No locals.
    #11 0xb7ed7d90 in imcc_run (interp=0x804e008, sourcefile=0xbfec6e0a "foo.pir", 
        argc=1, argv=0xbfec62e8) at compilers/imcc/main.c:815
            obj_file = 0
            yyscanner = (yyscan_t) 0x822a090
            output_file = 0x0
    #12 0x080489b7 in main (argc=136704448, argv=0x825f220) at src/main.c:62
            sourcefile = 0xbfec6e0a "foo.pir"
            interp = (Interp *) 0x804e008
            executable_name = (STRING *) 0x821b8e4
            executable_name_pmc = (PMC *) 0x8204d70
            status = 1267896320
    (gdb) 
