Here at ARM, a colleague recently wanted to port Linux to a prototype of a new high-performance Cortex-A9 based platform. To develop and debug this port, he needed to be able to set breakpoints, view registers, view memory, single-step at source level, and so on, in fact all the normal facilities provided by a debugger, but he wanted to do these both before the MMU is enabled (with a physical memory map), and after the MMU is enabled (with a virtual memory map).
The DS-5 Debugger has a slick Debug Configuration dialog in Eclipse that makes it easy to configure a debugging session to a target. Predefined debug configuration types include "Bare Metal Debug", "Linux Application Debug", and "Linux Kernel and/or Device Driver Debug". The latter is the topic of this blog. This debug configuration type is primarily designed for post-MMU debug to provide full kernel awareness, but also has some extra features that allow it to be used for pre-MMU debug too. This makes it possible to debug the Linux kernel, all the way from its entry point, through the pre-MMU stages, and then seamlessly through the MMU enable stage to post-MMU debug with full kernel awareness, all with source-level symbols and all without the need for tedious disconnecting/reconfiguring/ reconnecting!
Screenshot of Project type = "Linux Kernel and/or Device Driver Debug"
My colleague had already started using DS-5 Debugger's Debug Configuration Project type = "Linux Kernel and/or Device Driver Debug" to establish a connection to his target but was seeing data aborts occurring when a breakpoint was being hit at the entry point, after loading the kernel's debug symbols from the vmlinux file. This was because vmlinux contains virtual addresses so usage of it assumes the OS is up and running with the MMU enabled. After loading the debug symbols from vmlinux with the "file" command, the DS-5 Debugger will attempt to access various symbol locations in the kernel to support its kernel awareness, for example, "init_nsproxy.uts_ns->name" to get the kernel name and version, to support its "info os-version" command. If the MMU is not yet on, it will access invalid addresses, leading to data aborts occurring. However, this kernel awareness support feature can be temporarily disabled during the pre-MMU stage with the CLI command "set os enabled off", and later (post-MMU) re-enabled with the CLI command "set os enabled on". Furthermore, the debug symbols in vmlinux are virtual addresses and can't be used as-is until the MMU is on, but can be used to debug pre-MMU at source-level if an offset is applied to them.Let's consider the case where the kernel is loaded and started by a bootloader such as U-Boot.The general sequence is:
Now we will look at how the above sequence would work with a specific example using DS-5.
To debug the kernel at source-level, the kernel must be built with debug info: CONFIG_KERNEL_DEBUG=y, CONFIG_DEBUG_INFO=y, and (in kernel versions 2.6.36 and later) CONFIG_DEBUG_INFO_REDUCED=n.For DS-5 users, a ready-made example Linux distribution for BeagleBoard is provided, already built with debug info, complete with SD-Card image, vmlinux symbols file, file system, and full source code. To debug the kernel at source level, unzip/untar source.tar.bz2. Program a blank SD-Card with the supplied SD-Card image as described in the DS-5 documentation, then insert the SD-Card into the BeagleBoard.
Right-mouse-click in the Disassembly view, and select "Show in Source". DS-5 Debugger will try to open head.S in its Editor view. If you are using the ready-made vmlinux file provided with DS-5, that was built using different directory paths than your host machine, you will need to set a source path substitution to point the debugger at the kernel sources in .../distribution/kernel/linux-2.6.35-patched/source/, from the untar'd source.tar.bz2. Make sure that both the "Image Path" and "Host Path" both end with a corresponding directory; for example, ".../foo/linux-2.6.35-patched/source/" and "...\bar\linux-2.6.35-patched\source\". Use of a shorter path is usually best. Then right-mouse-click again in the Disassembly view, and select "Show in Source". head.S will open in the Editor view.
You can now set breakpoints, view registers, view memory, single-step, and other usual debug operations at this pre-MMU stage, all at source level.
Screenshot of pre-MMU source-level debug
Screenshot of post-MMU source-level debug
Many of the above steps can be automated, either with a script file, or by filling-in the Debug Configuration's fields before launching.
In summary, we have looked at how DS-5 can be used to debug the Linux kernel, both pre-MMU enable and post-MMU enable stages, to help porting Linux to a new platform.