world leader in high performance signal processing
Trace: » debuggers

Debuggers

gdb is the one and only standard debugger for the GNU toolchain. Learning and understanding gdb will not only help you do source level debugging on kernel, driver, libraries and applications, but will also improve your productivity. While graphical front ends like DDD, insight and eclipse simplify the interface to gdb, understanding gdb at a command line will also help you run the graphical front ends better.

gdb is not the only way to resolve issues -- check out debugging_applications for other methods.

gdb is part of the Blackfin toolchain and can be found on the Blackfin Linux website here. Click on the Files tab to obtain the latest release of gdb. To install gdb (for Ethernet or serial), since it is not packaged separately, check the instructions on installing the Blackfin toolchain to either build from source, or use a pre-compiled rpm for your system. If you want gdb for jtag you must install that separately. See the gdb/jtag site for more information.

There are two main types of code which need to be debugged:

  • applications (using gdb)
  • drivers or kernel (using kgdb or an ICE)

Debugging Single Applications

For more information see Compiling the Kernel and Adding User Applications.

To debug your program, the uClinux distribution must be build in a specific manner:

  1. add the program gdbserver as well as the application you wish to debug.
    • gdbserver is found in the Application Configuration window (displayed by choosing Customize Vendor/User Settings) under the Miscellaneous Applications category. This is normally set by default in the Analog Devices configurations (the entry may be marked as (old) and help text saying “mk68k targets only”- but this entry is OK).
  2. make the uImage.
  3. load this memory image onto the target system and boot the kernel and distribution.
  4. compile the application to debug with the ”-g” flag. This adds debugging information which GDB can work with. Also - to improve debug, set the optimization level to zero: ”-O0”.
  5. Load symbols into GDB from:
    1. if user-app is built into FLAT binary (bfin-uclinux-gcc), use the user-app.gdb file.
    2. if user-app is built into fdpic ELF binary (bfin-linux-uclibc-gcc), use the user-app directly
  6. since gdbserver can communicate with the host computer through a serial connection or through an Ethernet connection, you must decide which you want to do.

Debugging Via Serial Port

The following instruction explain how to remotely debug uClinux programs via the serial port.

  • on the target system enter the following command at the uClinux prompt:
    uClinux> gdbserver /dev/ttyS1 <program to debug>

This assumes you are connecting to gdb through the device ttyS1 on the target system.

  • on the Linux host computer enter the following command:
    bash$ bfin-uclinux-gdb -b 57600 <program to debug>.gdb

    or if you are using fdpic

    bash$ bfin-linux-uclibc-gdb -b 57600 <program to debug>

    The -b switch specifies the baud rate the program will use with the serial port, 57600 in this example. (you can also use set remotebaud 57600 at the gdb prompt if you forget to use the -b switch). If you are debugging a flat file, the *.gdb file for your program is generated when your program is compiled. If you are using fdpic, the file is the unstripped executable. It can be found in your program's directory. For more information see Adding User Applications. If your program complied successfully and the flat *.gdb file does not exist, ensure that you are calling gcc with the -g switch. This should be done by default when using the procedure described in the Adding User Applications section.

Once gdb is running on the Linux host type the following command at the gdb prompt to connect to the target system: gdb) target remote /dev/ttyS0 (This assumes you are connecting to gdbserver through the device ttyS0 on the Linux host)

  • You should now be connected to the target system. To start debugging your program with a breakpoint at the start of the function main enter the following commands at the gdb prompt:
    gdb) break main
    gdb) continue

    You must use the continue command instead of the run command because the program is already running on the remote system.

From the gdb prompt on the Linux host computer you should now be able to enter any standard gdb command.

Debugging Via Ethernet

The following instruction explain how to remotely debug uClinux programs via an Ethernet connection.

  • if the target system not already been assigned an IP address this must be done with a command similar to the following:
    uClinux> ifconfig eth0 <IP address to assign to system>
    OR
    uClinux> dhcpcd &

    Once this is done you may wish to check if you can communicate with the Linux host by using the ping utility.

  • start gdbserver on the target system by entering the following commands:
    uClinux> gdbserver localhost:3456 <program to debug>

    Any port number (3456) may be used as long as it does not conflict with any port already in use on the system or the Linux host.

  • on the Linux host computer enter the following command:
    bash$ bfin-uclinux-gdb <program to debug>.gdb

    or

    bash$ bfin-linux-uclibc-gdb <program to debug>

    The *.gdb file for your program is generated when your program is compiled. If you are debugging a flat file, the *.gdb file for your program is generated when your program is compiled. If you are using fdpic, the file is the unstripped executable. It can be found in your program's directory. For more information see Adding User Applications. If your program complied successfully and the flat *.gdb file does not exist, ensure that you are calling gcc with the -g switch. This should be done by default when using the procedure described in the Adding User Applications section.

Once gdb is running on the Linux host type the following command at the gdb prompt to connect to the target system:

gdb) target remote <IP address of target system>:3456

(The port number must be the same as the port number that was specified when starting gdbserver)

  • You should now be connected to the target system. To start debugging your program with a breakpoint at the start of the function main enter the following commands at the host machine gdb prompt:
    gdb) break main
    gdb) continue
  • You must use the continue command instead of the run command because the program is already running on the remote system.

From the gdb prompt on the Linux host computer you should now be able to enter any standard gdb command.

Debugging Dynamic Object Libraries

The way to debug dynamic object library by GDB is nearly the same as that of application. Only several differences:

  1. User object library libusertest.so should be compiled with flag ”-shared -mfdpic -g -ldl”.
  2. User application usertest should be compiled with flag ”-mfdpic -g”.
  3. Library libdl.so and libusertest.so should be copied to folder “lib” in the root file system image first. User application “usertest” should be copied to a proper position in the same image.
  4. Start GDB on host with the user application.
     /> bfin-uclinux-gdb usertest
  5. Don't forget to set GDB environment variable solib-search-path to the library folders, where libdl.so and libusertest.so can be found.
    (gdb) set solib-search-path /library-directory/
    
    In case there are multiple library paths to be searched: 
    (To be safe you need to set solib-absolute-prefix to some non-exist directory so GDB only use solib-search-path).
    
    (gdb) set solib-absolute-prefix /non_exist_dir
    (gdb) set solib-search-path /home/test/toolchain/bfin-linux-uclibc/bfin-linux-uclibc/runtime/lib:/home/test/kernel/uclinux-dist/staging/usr/lib
    (gdb) info sharedlibrary 
    From        To          Syms Read   Shared Object Library
    0x00248c78  0x00269b34  Yes         /home/test/kernel/uclinux-dist/staging/usr/lib/libeXosip2.so.4
    0x00c88310  0x00c8834c  Yes         /home/test/toolchain/bfin-linux-uclibc/bfin-linux-uclibc/runtime/lib/libresolv.so.0
    0x02628490  0x02682ae4  Yes         /home/test/kernel/uclinux-dist/staging/usr/lib/libasound.so.2
  6. Run application on target board and connect gdb to it.

Debugging Kernel

Kernel debugging can be done similar to application debugging. The host based tools are exactly the same, and are installed in the same manner. However, the choice is to do kernel level debugging over ethernet/UART (using KGDB) or JTAG (using gdbproxy).

Debugging with KGDB

In the 2008R1.5 release and older, you need to patch the kernel with the KGDB patch before start debugging. Refer to kgdb_2008R1.5.

In the 2009R1+ release, kgdb has been supported in mainline kernel already, no additional patch is needed. Refer to kgdb.

Debugging via Jtag (gdbproxy)

Normally, most people are satisfied with debugging with gdb via Ethernet or serial as described above, but in some circumstances (debugging some kernel drivers, or debugging boot loaders), lower level debugging is required. JTAG debugging supports this need. Please refer to gdbproxy

Common gdb Commands

A summary of some common gdb commands are given below:

  • break <function or filename:line#> - This command sets a breakpoint at the specified function or line number. (e.g. break main, break myprog.c:7).
  • continue - This command continues program execution from the point where it was last stopped.
  • delete <breakpoint# or watchpoint#> - This command deletes the breakpoint or watchpoint specified by the breakpoint or watchpoint number. The watchpoint / breakpoint number is given when the watchpoint / breakpoint is first set.
  • disable <breakpoint#> - This command disables the breakpoint specified by the breakpoint number. The breakpoint number is given when the breakpoint is first set.
  • run - This command starts the program being debugged. The continue command is used instead of run when debugging a program on a remote target.
  • set variable <symbol> = <value> - This commands sets a variable specified by symbol to the given value. (e.g. set variable x = 3).
  • step - This command executes the next line of code given in the source file.
  • watch <symbol> - This command sets a watchpoint for the variable specified by the given symbol. Whenever the value of the variable is changed gdb will alert you to the old value and the new value of the variable. (e.g. To watch the value of a variable called X enter the command watch X).
  • info registers - dumps the processor registers
  • x/4 0x839f80 - dumps memory at location 0x839f80

gdb provides much more functionality that cannot be covered here. Click here for the gdb manual.

There are some advanced time saving gdb scripts, which can be used with kgdb and gdb. Check out the gdb snippets section.

Using a Graphical Debugger

Insight

http://www.sourceware.org/insight/ Insight is a graphical user interface to GDB, the GNU Debugger written in TCL/Tk by people working at Red Hat, Inc. and Cygnus Solutions. It is combined together with GDB, and built together with GDB.

Starting with the 2007R2 toolchain, insight has been integrated into the normal toolchain build. Invoking one of bfin-elf-insight or bfin-linux-uclibc-insight or bfin-uclinux-insight will start the Insight.

DDD

Data Display Debugger (ddd) is a graphical front-end for command-line debuggers such as bfin-uclinux-gdb. For most distributions of Linux, ddd can be installed through the host package manager; alternately, the source code for ddd is available here for you to compile yourself. The complete ddd manual can be found formatted in html or as a pdf. The problem with DDD is that the upstream development is not terribly active. However, it is usable, especially for people who are not familiar with GDB commands.

Once ddd is installed you must ensure that the correct gdb program will be used. To remotely debug uClinux programs, the Blackfin bfin-uclinux-gdb program described earlier must be used. To remotely debug the kernel, the Blackfin bfin-elf-gdb program should be used. To use ddd with either, invoke ddd with the -debugger option.

ddd –debugger bfin-uclinux-gdb

An overview of the main ddd window is given below. It's also an example of the beginning of a typical debugging session. See the command line window of ddd in the following screen shot for using file and target remote to connect to the target board:

Source Text Window

This window shows your source code along with any breakpoints you have inserted. The arrow indicates the next line of source code to be executed.

GDB Console

This window shows the output from the gdb program. You can also enter gdb commands in this window.

Command Buttons

These buttons execute some common ddd and gdb commands.

Argument Field

This text field sets the value for the argument () which is passed to the commands executed by the command buttons. In this example clicking on the breakpoint command button would clear the breakpoint at myprog.c:5 (myprog.c line 5) as this is the value in the argument field. The current line or text selection in the source text window is written to this field. You may also type a value into this field.

Eclipse

Eclipse is an excellent IDE framework. It supports a lot of plug-ins and the eclipse community keeps growing. In another page debugging_using_eclipse, we introduced how to set up eclipse for debugging on Blackfin uClinux. Since Eclipse is written in Java, it requires more memory for development system. Eclipse talks with GDB using Machine Interface, while DDD is using command interface. Machine Interface is considered to be more stable.

The GNAT Programming Studio (GPS)

https://libre2.adacore.com/gps/ GPS, the GNAT Programming Studio, is a Free Software IDE. With its intuitive interface, GPS is easy to use, simplifying source navigation and highlighting the fundamental ideas in the program.

Compared the DDD, the debugging interface looks much like modern IDEs.

GPS is invoked the same way as DDD:

ddd –debugger bfin-uclinux-gdb

And here is a snap shot:

External Resources

Complete Table of Contents/Topics