From jalimo (inactive) Wiki
Jump to: navigation, search


Debug Cacao on the target device

This page explains how one can debug Cacao effectively in a cross-compilation environment.


  • saydone
  • NFS
  • OpenEmbedded
  • Editor
  • gdb/.gdbinit
  • some scripts


'saydone' or sd for short is a small helper function which you can put into your .bashrc and then prepend every longer taking command with it, e.g. "sd bitbake bla".

The result is that you get a nice message once the command finishes which also gives an indication whether the command succeeded or not.

sd ()
  local cmd=$@

  local app=$1
  ($app "$@")

  if [ $? = 0 ]
    notify-send ":-) done: '$cmd'"
    notify-send --urgency=critical ":'( <i>failed:</i> '$cmd'"

target device

The target device should be reachable through an IP network. We call its IP TARGET_IP from now on.

development box

The development box is where cross-compilation takes place. The IP of this device will now be called DEVBOX_IP.


Since Jalimo uses OpenEmbedded for package building you need a working OE environment. For the remainder of this discussion we call this directory OE_DIR, it may for instance be part of your home (e.g. /home/joe/oe) which lives on your development box.


Starting a NFS server on your development machine and mount a directory on the target device is a mandatory step for remote debugging. The reason is that GCC stores absolute file names in the executables and libraries to find the program sources. If you export your whole OpenEmbedded development directory under the same path on the target device everything will be fine. This is what we are going to do here.

Your /etc/exports should have the following entry:

$OE_DIR $TARGET_IP(rw,no_root_squash,map_static=/etc/

As you saw above a file /etc/ is mentioned in this configuration. This is a static mapping file which map user and group ids from the target device to some sane numbers on your development box. On the target machine you are usually root while you have normal user privileges on the development box. Thus the map file should like like this:

# make root on $TARGET_IP a normal user on $DEVBOX_IP
uid 0 1000
gid 0 100

You get your user id by running id -u and your group id with id -g. Replace the above numbers with yours.

On the target device create the directories which are named like $OE_DIR on the developement box. Eg. if your $OE_DIR is actually /home/joe/oe do a mkdir -p /home/joe/oe on the target device.

Now mount the remote directory with mount -t nfs $DEVBOX_IP:$OE_DIR $OE_DIR. If anything is failing at this point your NFS setup may be flaky, check the net for help.

If the mount succeeded check if you can successfully write to the remote filesystem (Write access is not a must but can be helpful) by invoking touch $OE_DIR/bla on the target device. Do a ls -lh $OE_DIR/bla from the development box and confirm that the file has your user's ownership.

Edit, update patch and rebuild

It is assumed that you work on the cacao sources in a mercurial sandbox and that you add your changes to the cacao in OpenEmbedded through a patch which is mentioned in the build recipe.

GDB however accesses the sources which are contained within the OpenEmbedded environment. In order to easily update your sources with an updates patch we need a small script.

Mine looks like this:


(cd $DIR && quilt pop -a)
hg diff > $DIR/patches/cacao-jitcache-arm+i386.patch
(cd $DIR && quilt push -a)

The first line sets the directory in which the cacao sources are compiled. /home/rob/oe is my $OE_DIR. The next command removes all currenlty applied patches of the quilt patch series from the sources. Afterwards the new patch is generated with hg diff and its output overwrites the existing patch file. In in the patches inside the sources. Finally all patches of the series are re-applied which now includes the modified one.

The last remaining bit it how to rebuild the sources is actually pretty easy. Just load the variables for your OE environment and run sd bitbake -f -c install cacao. This will in fact only do the install step in OE but it results in make install to be called and this command will also rebuilt any object whose source has changed. The nice thing about OE's install command is that it copies all relevant files into a directory resembling a root directory. We will later run the cacao binary from exactly this directory.


A .gdbinit file in the directory where you want to run a test class is very important. The file allows to set up all the things automatically you would normally have to type by hand.

#handle SIGABRT nostop noprint pass
handle SIGSEGV nostop noprint pass
handle SIGILL nostop noprint pass
handle SIGXCPU nostop noprint pass
handle SIGPWR nostop noprint pass

# VM and program arguments

set args -XX:+DebugJitCache -Xbootclasspath/p:/home/rob/oe/om-2007.2/tmp/work/armv4t-angstrom-linux-gnueabi/cacao-0.98\+hg20080505-r0/image/usr/share/cacao/ Test

# with exception tracing
#set args -XX:+DebugJitCache -XX:+TraceExceptions -XX:+TraceJavaCalls -Xbootclasspath/p:/home/rob/oe/om-2007.2/tmp/work/armv4t-angstrom-linux-gnueabi/cacao-0.98\+hg20080505-r0/image/usr/share/cacao/ FieldTest

# with java call tracing
#set args -XX:+DebugJitCache -XX:+TraceExceptions -XX:+TraceJavaCalls -Xbootclasspath/p:/home/rob/oe/om-2007.2/tmp/work/armv4t-angstrom-linux-gnueabi/cacao-0.98\+hg20080505-r0/image/usr/share/cacao/ FieldTest

# Jit Cache filter functionality
set environment NO_FILTER
#set environment TEST_CLASS java/lang/Integer
#set environment TEST_METHOD toString
#set environment TEST_DESCRIPTOR (II)Ljava/lang/String;

# Cross-compilation
set environment LD_LIBRARY_PATH /home/rob/oe/om-2007.2/tmp/work/armv4t-angstrom-linux-gnueabi/cacao-0.98+hg20080505-r0/image/usr/lib
file /home/rob/oe/om-2007.2/tmp/work/armv4t-angstrom-linux-gnueabi/cacao-0.98\+hg20080505-r0/image/usr/bin/cacao
set solib-search-path /home/rob/oe/om-2007.2/tmp/work/armv4t-angstrom-linux-gnueabi/cacao-0.98\+hg20080505-r0/image

# Local
#file /home/rob/classpath/INSTALL/kaffe/jre/bin/kaffe-bin
#file /usr/bin/cacao
#set args -cp /usr/share/java/jline.jar:/usr/share/java/bsh.jar bsh.Interpreter
#set args Test
#set args JComboBoxTest

set breakpoint pending on

# notice whether this happens
#break threadMain
#break threads_set_current_threadobject
#break GC_init_thread_local
#break GC_new_thread
#break GC_thr_init_foreign
#break filter_end
break filter_match

define djit
  x/10i $pc

define hook-stop
  handle SIGSEGV stop print

define nosegf
  handle SIGSEGV nostop noprint pass
document nosegf
Disables handling of SIGSEGV which is used by the garbage collector. This *MUST* be called each
time before returning control from the debugger to the VM.

define sigi
  handle SIGILL stop
document sigi
Enables handling of SIGILL. Cacao uses this for handling code patching.

define bjc
  break jitcache.c:$arg0
document bjc
Creates a breakpoint at the given line in jitcache.c

define bpc
  break patcher.c:$arg0
document bpc
Creates a breakpoint at the given line in patcher.c

define bcc
  break codegen.c:$arg0
document bcc
Creates a breakpoint at the given line in codegen.c

define pmi
  x/10i ($arg0)->code->entrypoint
document pmi
Dissassembles 10 instructions of the given methodinfo structure.

define p8
  print ($arg0)->text
document p8
Prints a utf structure.

define get_codeinfo
  p code_find_codeinfo_for_pc ($arg0)
document get_codeinfo
Retrieves the codeinfo pointer for a given jitted code location. Calls user code!

define pm
  printf "%s %s %s\n", ($arg0)->clazz->name->text, ($arg0)->name->text, ($arg0)->descriptor->text
document pm
Printf the class name, method name and method descriptor for a given methodinfo pointer.

define pmpc
  p code_find_codeinfo_for_pc ($arg0)
  pm $->m
document pmpc
Printf the class name, method name and method descriptor for a given jitted code location.

define xi
  x/$arg0i cd->mcodebase
document xi
Disassembles n instruction. It implicitly references "cd->mcodebase" which is available in the codegenerator only.

define brm
  break *(($arg0)->code->entrypoint)
document brm
Creates a breakpoint for the jitted code of the given methodinfo

define get_field_by_offset 
 p *(*(java_handle_t *) (*((s4 *) ($arg0 + $arg1))))->vftbl
document get_field_by_offset
Retrieves the (java_handle_t *) of a non-static field by taking the address of the base object and the offset of the field.
This is a very simple function of not much value.

define get_field_by_index
 p ((java_handle_t *) $arg0)->vftbl->clazz->fields[$arg1]->offset
 get_field_by_offset $arg0 $
document get_field_by_index
Retrieves the (java_handle_t *) of a non-static field by taking the address of the base object and the index of the field
(the field's offset is automatically used).