HTML |
---|
/* To make a ToC move with the page, add a HTML macro and put this in it */
<style> .toc-macro {position: static !important;} </style>
/* To make a ToC wider */
<style> .toc-macro {width: 350px !important;} </style>
/* Make the ToC in-line (not float on the right) */
<style> .toc-macro {float: none !important;} </style> |
Table of Contents
Note: It is assumed that OpenOCD is built, patched and installed as per instructions on this page.
It is possible to use OpenOCD and Eclipse to source level debug the Linux kernel. This means means kernel space (device drivers), not application space (at least not easily and maybe not very useful). For application space, you need to use traditional gdb, not JTAG. The reason is that Linux applications run in virtual address space, so the settings of the MMU must be considered. However, while the Linux kernel also runs at a virtual address, the address space is fixed so it is possible to use openOCD and JTAG.
General Considerations:
Here are some considerations to take in account:
...
You must build the kernel with the following configuration options. Not that =y means they must be enabled, and =n means they just be disabled. Please use menuconfig to confirm each one.
...
Because of the default compiler optimization level (-O2), stepping thru the code may be problematic / unpredictable. Using menuconfig you can only select between -O2 and -Os (CC_OPTIMIZE_FOR_PERFORMANCE
, CC_OPTIMIZE_FOR_SIZE
). There's also a relatively new CC_OPTIMIZE_FOR_PERFORMANCE_O3
to select -O3 but no real way to choose a lower optimization level. It is not mandatory but to get a code flow that is easier to follow, you can manually hack the Makefile and turn -O2 into -O1:
You need to add the follow to your kernel boot arguments:
...
The maxcpus=1
makes sure that even in a multi-core system, only one core is used.
It is assumed that Arm Trusted Firmware and u-boot are working and programmed into the chosen boot medium (QSPI, eMMC or SD). It may also be convenient to set-up u-boot to load and boot the kernel via the network (tftp) to make sure that the symbols loaded in gdb always match the kernel that is executed / under debug (in fact the kernel binary is not loaded via JTAG).
First you need to import the kernel as makefile project (you can also clone and import, similarly to what is documented here). If the toolchain is configured properly before Eclipse is launched, it is possible to build the kernel using the GUI, i.e. by clicking on the hammer icon. The only configuration needed is for the custom build arguments (right click on the project -> Properties -> C/C++ Build -> Behavior tab:
TBD
One of the most common uses when it comes to Linux kernel is to debug a device driver, this happens well after most of the low level architectural configurations are done and at this stage the MMU has already been enabled.
The debug configuration has to be created. Right click on the project -> Debug As - > Debug Configurations. Create a new configuration under "GDB OpenOCD Debugging", name "linux-kernel":
Then the "Debugger" tab (adapt paths to where OpenOCD is installed):
And finally, the most important one is the "Startup" tab:
As explained previously the Initialization Commands depend on the boot media. If the boot media is QSPI they are:
...
Then u-boot would normally move the image from 0x4A08_0000 to 0x4A02_0000, this is where the breakpoint is set in the command list above. For the explanation of the complete list of commands, refer to this page.
The Run/Restart commands are:
...
Note: Remove All Breakpoints if something unexpected happens during the launch.
Most of the times you do not really have to care about multi-core. In fact it is always possible, for example, to debug a device driver disabling the multi-core passing the already mentioned max-cpus=1
to the kernel boot arguments. However it is possible to use OpenOCD and Eclipse to debug the Linux kernel also after the smp initialization. OpenOCD exposes the different cores as different HW threads to gdb and the CTI (Cross Trigger Interface), configured in the RZ target file, makes sure that when a breakpoint is hit by one core, the other cores are stopped too. This possibility may be useful in the rare cases where a bug does not show up when using one core, maybe because of a missing / wrong synchronization in accessing a critical resource.
...
This example is for the dual core RZ/G2L, it can be easily adapted for other multi-core devices. A temporary HW breakpoint is added at the sched_init_smp
function instead of start_kernel
.
It is now necessary to disconnect (red square button in the debug view) and reconnect again using the second debug configuration linux-kernel-after-smp-init. This configuration is identical to the first, obviously apart from the Initialization Commands:
...
mem 0xffff800010000000 0xffff80001fffffff ro mem 0xffff000000000000 0xffff0000ffffffff rw si