maemo SDK+ Debugging Guide

Document status

This document is currently a draft.

Introduction

This document explains how to do debugging in SDK+ environment. The guide is targeted for beginner level maemo SDK+ developers who need to do debugging in the maemo SDK+ environment. Majority of the material in this guide is based on the older 'Maemo Debugging Guide' document. However, we have updated those texts that are specific to SDK+ and Scratchbox-2.

We cover two basic debugging tools that are available in the SDK+ environment and show how to use them. The tools are:

  • gdb - The Gnu Project Debugger. General tool for various debugging needs.
  • valgrind - Debugger and profiler. Valgrind works only in the X86 environment under Scratchbox so this tool can not be used in the Tablet device.

We assume that you as the developer already know how to:

  • do software development in the Linux environment using the C-language
  • install software to the Tablet device
  • how to gain root access to the device
  • how to install osso-xterm and ssh to the device
  • configure repositories in the /etc/apt/sources.list file
  • setup USB networking between your Linux PC and the Tablet (you can also use the device over your local WLAN connection instead)
  • work with the SDK+ environment and know how to create and select target rootstraps

Prerequisites

To follow the debugging examples in this guide you need to have:

  • maemo SDK+ installed in your Linux PC
  • Nokia Internet Tablet device running the OS2008 Diablo release
  • USB cable to connect the device with the Linux PC
  • Internet access both for the Tablet and for your Linux PC
  • USB networking (or WLAN) setup between the Linux PC and the device
  • Root login access to the device over ssh
  • osso-xterm installed in the device
  • ssh software installed in the device

General notes about debugging

Don't forget to install the debug symbols for the widely used C-library itself. If you do debugging in the Internet Tablet device you need to install the libc6-dbg package in the device. You can do this by running apt-get install libc6-dbg in the Internet Tablet device itself.

Debugging issues on the ARM architecture

There are some issues you need to know and be aware when you are debugging on the ARM architecture.

  • To make backtraces work properly in ARM side you need to install the dbg packages of the libraries your application is using. Profiling and debugging (gdb) tools require code to have either framepointers or debugging symbols to unwind stack. This is needed for showing backtraces or call graphs.
  • C-language functions with the __attribute__((__noreturn__)) statement need to be compiled with the gcc option: -fno-omit-frame-pointer. Without framepointers you can not get backtrace through "noreturn" functions. In practice, what would happen is that when you use the bt command you would see infinite repeat of this kind of function.
  • In addition, for the gdb to be able to display correct function names during debugging it also needs to have access to the debug symbols. Without them it shows for the given address the preceding exported function name.

Debugging issues with Scratchbox-2

SDK+ is using Scratchbox-2 and there are some issues you need to be aware of.

When debugging threads in an application, gdb needs to be linked against the same thread library that the application is using.

The above-mentioned problem can produce warning: Cannot initialize thread debugging library: unknown thread_db error '22' messages in gdb output, and info threads command in gdb will show nothing.

When using valgrind tool there are some things you need to keep in mind. Valgrind is a statically linked binary and as such the scratchbox-2 can not trap the library calls and do it's pathmapping magic. For this reason the valgrind session must be run in a chrooted session similar to what scratchbox-1 is using.

Debugging in ARM-target with GDB

Debugging ARM binaries with standalone GDB is not possible due to limitations in QEMU user-mode emulator. However, QEMU emulator itself includes a built-in GDB server that makes it relatively easy to debug emulated ARM binaries inside the emulator.

The binary you are debugging can be under your ~/src/some_place directory or it can be inside the target rootstrap-directory (like: ~/.maemo-sdk/rootstraps/armel/diablo4.1.1_armel/home/user/). Both locations should work equally well.

Using the GDB server in QEMU

The GDB-server is built into the QEMU user-mode emulator and we need to use this built-in gdb server because the binary is owned by the QEMU-emulator.

Naturally the native X86 gdb can not get access nor do debugging with ARM-binaries.

In this example we use a simple and short C-program to do debugging under the ~/src/debugging/ directory.

First, copy&paste the following short C-program to a file debugtest.c inside your ~/src/debugging/ directory.


[host] $ mkdir -p ~/src/debugging
[host] $ cd ~/src/debugging

#
# copy and paste the simple code below to file debugtest.c in your ~/src/debugging directory
# so that when you do cat debugtest.c you get the same listing as below.
#
  
[host] $ cat debugtest.c

/* 
 * debugtest.c
 *
 * just a simple file to demonstrate GDB usage under SDK+
 *
 */

#include 

int main()
{
  int retval;

  retval = foobar();

  printf("foobar() returned = %d\n",retval);

  return 0;
}

/* 
 * just a simple foobar function
 */

int foobar()
{
  int yes=123;

  printf("Now in foobar.\n");
  return yes;

}
 

After you have got the debugtest.c file in you ~/src/debugging/ directory just compile it with the ARM-crosscompiler.


[host] $ maemo-sdk show rootstrap

diablo4.1.1_armel
  
[host] $ pwd
/home/you/src/debugging

[host]$ sb2 gcc debugtest.c -o debugtest -g

[host] $ ls -l
-rwxr-xr-x 1 you you 8582 2008-12-02 13:24 debugtest
-rw-r--r-- 1 you you  342 2008-12-02 13:07 debugtest.c

[host] $ file debugtest
debugtest: ELF 32-bit LSB executable, ARM, version 1 (SYSV), for GNU/Linux 2.4.17, dynamically linked (uses shared libs), not stripped

Above we first check that we have the right ARMEL-target activated (diablo4.1.1_armel). The we do a simple compilation of debugtest.c to create the debugtest ARM binary. In the end we check with file command that we got the type of binary we wanted.

Next we have to start the gdb-server inside QEMU emulator to serve our debugging session. We can check with the sb2-qemu-gdbserver-prepare command what sort of command we should use to start the server. Example below shows how to do this.


[host] $  sb2 -eR
bash-3.1# sb2-qemu-gdbserver-prepare ./debugtest
/usr/bin/sb2-qemu-arm -g 1234 -drop-ld-preload -L / -0 ./debugtest -libattr-hack ./debugtest

The output what kind of command we should use is provided to us by sb2-qemu-gdbserver-prepare command. Let's use that one.


bash-3.1# /usr/bin/sb2-qemu-arm -g 1234 -drop-ld-preload -L / -0 ./debugtest -libattr-hack ./debugtest

Now the built-in gdb-server in QEMU user-mode emulator is activated. It is listening in port 1234. The binary we are going to debug is the debugtest as is given in the end of the command.

Using GDB client to do debugging with the QEMU GDB-server

If you followed the instructions above you should now have the gdb-server waiting connections in port 1234.

Next, we need to use the correct version of GDB debugger to connect to the QEMU gdb-server. The gdb client should support the sysroot command and version 6.6.50 supports that.

If you have not yet installed the arm-2007q3 toolchain you should do it now because the gdb that is provided in that toolchain has the required support for sysroot command.

If that arm-2007q3 toolchain is missing from you installation you can install it with command:


[host] $ maemo-sdk install toolchain arm-2007q3

You need to know the full path of the location of rootstrap root. You can find this with the maemo-rootstrap command.


[host] $ maemo-rootstrap path
/home/your_nick_here/.maemo-sdk/rootstraps/armel/diablo4.1.1_armel

Next, lets start the gdb debugger that is included in the arm-2007q3 toolchain.


[host] $ cd ~/src/debugging/
[host] $ /opt/maemo/tools/arm-2007q3/bin/arm-none-linux-gnueabi-gdb ./debugtest
GNU gdb (GDB) 6.6.50.20070821-cvs
Copyright (C) 2007 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 "--host=i686-pc-linux-gnu --target=arm-none-linux-gnueabi".
For bug reporting instructions, please see:
.
..
(gdb)
(gdb) set sysroot  /home/your_nick_here/.maemo-sdk/rootstraps/armel/diablo4.1.1_armel

Above we first set the sysroot path with set sysroot command. The purpose of this command is to set alternative system root. The system root is used to load absolute shared library symbol files.


(gdb) target remote :1234
Remote debugging using :1234
(gdb) 

Above we inform the client that we should connect to the gdb-server inside QEMU-emulator. This is done with the target remote :1234 command. The parameter :1234 is the port number where to connect.

Next, let's do some simple debugging and start by setting a breakpoint to function foobar() and then continue the execution of the binary.


(gdb) br foobar
Breakpoint 1 at 0x83c4: file debugtest.c, line 28.
(gdb) cont
Continuing.

Breakpoint 1, foobar () at debugtest.c:28
28        int yes=123;

The execution of the binary has now reached the breakpoint at function foobar(). If you want to see how we got here you can try the backtrace bt command.


(gdb) bt
#0  foobar () at debugtest.c:28
#1  0x00008394 in main () at debugtest.c:15

The backtrace command reveals that the foobar() was called from the main() function.

The list command shows the part of source code where the execution is going. So, lets see where we are in the source code. Just type list and hit enter.


(gdb) list
23       * just for simple debugging demo 
24       */
25
26      int foobar()
27      {
28        int yes=123;
29
30        printf("Now in foobar.\n");
31        return yes;
32
(gdb)

The s command is the step command. It runs the program one statement at a time. Try it. Just hit s and hit enter. If you want to inspect the value of a variable use the print command as below.


(gdb) s
30        printf("Now in foobar.\n");
(gdb) print yes
$1 = 123
(gdb) 
(gdb) s
31        return yes;
(gdb) s
33      }
(gdb) s
main () at debugtest.c:17
17        printf("foobar() returned = %d\n",retval);
(gdb) print retval
$2 = 123
(gdb) s
19        return 0;
(gdb) s
20      }
(gdb) s
0x4301610c in __libc_start_main () from /home/your_nick_here/.maemo-sdk/rootstraps/armel/diablo4.1.1_armel/lib/libc.so.6
(gdb) s
Single stepping until exit from function __libc_start_main, 
which has no line number information.

Program exited normally.
(gdb) 

After you have got the gdb environment working with SDK+ then debugging under the ARM-target is very similar than debugging with gdb in any other gdb-server environment.

Debugging in i386-target with GDB

This section is not completed.

Debugging with valgrind in SDK+ environment

This section is not completed.