From LinuxMIPS
Jump to: navigation, search

For many Linux kernel developers, KGDB is a life-saving tool. With KGDB, you can debug the kernel while it runs! You can set breakpoints or do single stepping at the source code level.

To do this, you will need a dedicated serial port on your target, and use a crossover-cable (also known as a null-modem) to connect it to your development host. If you are also using a serial console, this implies you will need two serial ports on your target. It is possible to do both kernel debug and serial console through a single serial port. This will be mentioned later in this chapter.

When you configure the kernel, select the 'Remote GDB kernel debugging' which is listed under "Kernel hacking". Do a 'make clean' and recompile the kernel so that debugging symbols are compiled into your kernel image. Try to make a new image. You will soon discover two missing symbols in the final linking stage:

   arch/mips/kernel/kernel.o: In function `getpacket':
   arch/mips/kernel/kernel.o(.text+0x85ac): undefined reference to `getDebugChar'
   arch/mips/kernel/kernel.o(.text+0x85cc): undefined reference to `getDebugChar'
   arch/mips/kernel/kernel.o(.text+0x8634): undefined reference to `getDebugChar'
   arch/mips/kernel/kernel.o(.text+0x864c): undefined reference to `getDebugChar'
   arch/mips/kernel/kernel.o(.text+0x8670): undefined reference to `putDebugChar'
   arch/mips/kernel/kernel.o(.text+0x8680): undefined reference to `putDebugChar'
   arch/mips/kernel/kernel.o(.text+0x8698): undefined reference to `putDebugChar'
   arch/mips/kernel/kernel.o(.text+0x86a0): undefined reference to `putDebugChar'

You need to supply these two functions for your own boards:

   int putDebugChar(uint8 byte)
   uint8 getDebugChar(void)

As an example, here is the dbg_io.c for DDB5476 board. DDB5476 uses a standard UART serial port to implement those two functions.

After supplying those two functions, you are ready to debug the kernel. Run the new kernel image. If you also use the early printk patch, you should be able to see something like this on your console:

   Wait for gdb client connection ...

Assuming you have already connected a cross-over serial cable between the dedicated serial port on the target and a serial port on your host (say, COM0), you can then set the appropriate baud rate and start the cross gdb on your host:

   stty -F /dev/ttyS0 38400
   mipsel-linux-gdb vmlinux

At the gdb prompt, type

   target remote /dev/ttyS0

And, voila! You should be talking to the kernel through KGDB - if you are lucky enough!

A couple of tips on using KGDB:

  • Any functions preceded with the '__init' label will not break very well with breakpoints. Sometimes it will screw up the line numbers of other functions in the same file. Try undefining __init to be an empty macro in your 'include/linux/init.h' file. Refer to the patch. [NOTE: This problem is fixed in the latest gdb version, at least in gdb 5.2]
  • Sometimes if you break on a function, you cannot see the correct value in variables and cannot do back-tracing. This is probably because certain registers are still not initialized [HELP: because kernel is compiled with -O2 flag?]. Step into the function a couple of lines, and you should see the variable and back-tracing fine.

What if the board only has one serial port?

Some boards only have one serial port. If you use it as serial console, you cannot really use it for KGDB - unless you do some tricks to it.

There are two solutions. One is GDB console, and the other is to use a KGDB demuxing script.

It is easy to use the GDB console. When you select 'Remote GDB kernel debugging' under the 'Kernel hacking' sub-menu, you are also prompted for 'Console output to GDB'. Simply selecting that choice will work! In fact, this option is so easy to use you might want to use it even if you have a second serial port.

However, this option has a limit. When the kernel goes to userland, the console stops working. This is because the KGDB stub in the kernel and GDB are not designed to provide interactive output. [HELP: any volunteers?]

The second option uses a script called 'kgdb_demux' written by Brian Moyle. It creates two virtual ports, typically ttya0 and ttya1. It then listens to the real serial port (such as ttyS0). It will forward console traffic to ttya0 and KGDB traffic to ttya1. All you have to do then is to start minicom on /dev/ttya0 (port setting does not matter) and KGDB on /dev/ttya1.

You can download the tarball here. A couple of usage tips.

  • Untar the file to some place.
  • Copy kgdb_demux script to your execution path, and modify it properly.
  • Set the port parameters properly before you start kgdb_demux.

Next page: Linux Interrupts