http://bootloader.wikidot.com/android:kgdb Enabling KGDB for Android
KGDB may be one of the best tools for kernel debugging, besides the famous printk. It allows a developer to connect to the target device from GDB on a host PC. Basic information about KGDB can be found here: http://kgdb.linsyssoft.com. KGDB has two parts: the kgdb core (kernel/kgdb.c) and a few connection interfaces — currently supporting a serial tty device (specified by kgdboc=<serial tty device>) and the ethernet connection (kgdboe=<ip:port>). It supports many architectures like x86 and ARM, but there are still some challenges to use it effectively on Android. The main challenge is that Android phones usually don't have an exposed serial port or an ethernet port, which KGDB usually requires. To use KGDB on a device without a serial or an ethernet port, one may need to get the USB driver to work with KGDB, or to get KGDB to work on an emulator (like Android goldfish). So far, it doesn't seem these options are working yet. So I will first try to enable KGDB over the USB connection available on the Android phone. To use KGDB over a tty device, the tty device would have to explicitly support character I/O under an atomic context. For example, the serial port driver would need to be able to send/receive characters by polling the I/O ports (or memory-mapped addresses), in addition to its standard equivalent operations which may use interrupts and may contain complicated operations on upper tty layers. For KGDB, all it can do is quickly get a character over the serial line, restore all hardware states, and return the character to KGDB (the same for sending a character). This can be a bit more challenging for the USB device, since a USB device may have multiple interfaces and endpoints with data going on. When KGDB stops the kernel, and the KGDB driver is doing I/O with one specific interface (two endpoints), some hardware interrupts for other interfaces may get missed by their normal handlers. Fortunately, it turned out that this sometimes is not too big a problem if the interrupts are level-triggered, and can stay there for a while while we debug with KGDB. Here, I will first quickly explain the theory of operation for the KGDB USB driver. To use KGDB with "kgdboc=<tty-device>", the tty driver needs to support three ops: poll_init, poll_get_char, and poll_put_char to communicate with a remote GDB client. They are special versions of character I/O in addition to what every tty driver supports, such as put_char, and some char push mechanism based on interrupts.
It's not too hard to implement these functions for the USB controller on an MSM chip. They can be based on the USB drivers in Android's MSM kernel. I will make the code available after some more testing. After implementing the I/O functions for KGDB, there are still a couple of things to do. One of them is that KGDB is initialized very early during boot-up, and it might not be able to access the USB driver when it is first invoked by the kernel. I added a small delay in it to retry the USB driver after a few seconds. This turns out to be working quite well. Of course, another option is to initialize the USB driver earlier if its dependencies can be resolved too. On the host side, one need to fire up a USB serial driver in order to see the serial device over the USB. This can be a command like "modprobe usbserial vendor=<vendor id> product=<product id>". The good thing is that one probably won't need to worry about the baud rate at all for USB serial drivers — they are either not fully supported by the drivers, or no driver really cares about them. The USB hardware can work well without knowing what baud rate has been specified on either end of the channel. One remaining issue might be that the usbserial driver may conflict with the ADB driver, which makes it hard to use ADB and KGDB at the same time. The problem is after the "modprobe usbserial…" command, all USB devices that look like a serial port are opened, which include the one for KGDB and the one normally for ADB, so when ADB is run, it gets access denied. Of course, to fix this, one can modify the usbserial driver to avoid the ADB interface. Hopefully all these will work out. I will update this post and post code when things work a bit beyond the proof-of-concept stage. KGDB for Android downloadThe source is available at http://github.com/dankex/kgdb-android. This is the first version. Please post comments on github. Compile KGDB for AndroidAfter merging the KGDB USB code into the Android Kernel, you would need to turn on the followings flags: Configure the kernelCONFIG_KGDB (for KGDB) Configure Android USB composite driver to include "acm"Enable CONFIG_USB_ANDROID_ACM
Use these functions in the usb composite:
This composite will include adb and a USB serial port ttyGS0 (through f_acm.c), which we can use for the kgdb-host connection. Configure kernel command lineSpecify ttyGS0 as the kgdboc device. Add the following into the kernel command line (possibly in BoardConfig.mk)
The second option "kgdbretry=4" is a new parameter added to kgdboc.c. It means that if kgdb cannot find the device "ttyGS0" in early boot, it will retry once after the specified number of seconds. This is a work-around if the USB device is not immediately initialized during system boot. Connect to kgdb from a host PCWhen the device is in the KGDB mode, you can use gdb to
connect to it. The device enters the KGDB mode in one of the
following conditions: Before a break point is set, to invoke KGDB for the first time, what we can do is through ADB:
Then, we can connect to the phone with gdb for ARM:
The tool "arm-eabi-gdb" can be found in the "prebuilt" directory in an Android build. "vmlinux" is the Android kernel containing symbols. You can also use "set architecture" to choose a specific ARM architecture before connecting to the device. If everything turns out to be working right, you would see the following prompt in GDB:
TroubleshootingAfter loading the kernel including the "acm" device, one may want to check if the "cdc-acm" gadget device is recognized on the host. This can be done with "lsusb" and "cat /proc/bus/usb/devices". The command "lsusb" lists all usb devices. It should include the usb composite with specific vendor/product ids specified in the board file above. For example,
The usb device file can show the details in the composite device, for example:
If the above steps show that the composite driver supports the cdc-acm serial port, then you can probably find the port as /dev/ttyACM0 or ttyACM1, which is ready to use for GDB. Some examples of using KGDBHere are a couple of examples of using KGDB to do something in kernel debugging. KGDB example: mkdir syscall
From the ADB Shell, trigger KGDB
Connect to KGDB from the host, and set a break point at "sys_mkdir"
Create a directory from the ADB shell
The kernel hits the break point:
KGDB can display and modify local variables as well as global symbols. See if the result is expected in ADB shell:
|