l4kd -- The L4 Kernel Debugger

1 Synopsis

L4KD

2 Description

Jochen Liedtke's L4 microkernel comes with a minimalistic kernel debugger, L4KD, which is primarily intended for debugging the -kernel but also allows examining the kernel and user state of user tasks.

L4KD is not a symbolic debugger. The programmer using it should have a good understanding of the x86 architecture and should have an assembler or disassembler listing of whatever he needs to debug next to him to make sense of what's displayed.

When invoked, L4KD presents the user with its prompt, "L4KD:", and then waits for the user to enter single-character commands (see the section on commands).

L4KD is automatically invoked upon each boot of the L4 -kernel to give the user a chance to set any initial breakpoints, etc. Normally, the user has to enter an explicit "g" command (see below) to get the system going.

Once the system is running, there are several ways to invoke L4KD:

L4KD can be controlled using the system's video console or using a serial terminal - see the description of the "V" command below.

3 Commands

L4KD commands are single or double-character mnemonics; the case is significant. Commands are invoked automatically once all required arguments have been typed in; commands expecting no arguments are invoked immediately. There is no command line editing.

Typing in arguments can be finished by typing Return or Space.

In the following list of commands, the following argument types are used (all numbers must be given in hexadecimal representation):

addr
a virtual (or I/O) address.
size
width of a memory access in bytes; can be 1, 2, or 4.
threadid
an internal 2-byte (<=4 hex digits) thread reference number.
long_threadid
an external 4-byte (>4 hex digits) thread reference number; this is the low word of the external 8-byte thread ids.
tasknr
a task number (0-1ff).
threadnr
a thread number within a single task (0-7f).
framenr
a physical page frame number.
excpnr
an exception number.
errcode
an exception error code.

Now for the list of commands itself:

?
Show a short one-screen help.
g
Resume execution.
Shift+Num
Reboot the machine. (Only works on the system console, not via a serial line.)
a [ addr ]
Show absolute base addresses of the L4 kernel modules. Without an argument, shows all modules. With an 4-digit address, shows the module containing the code located at the address.

The module base addresses can be useful for setting a breakpoint base address using ``bb'' when debugging a particular kernel module; however, please note that the memory is mapped in at kernel virtual address 0xf0000000, so this value needs to be added to the module base address.

b
Show currently set machine breakpoint. (Please always use ``b Return'' instead of ``b Space'' - see the Bugs section).
b-
Delete a currently set machine breakpoint, and reset all breakpoint restrictions.
bb [ baseaddr ]
Set a base address for future breakpoints, or (when invoked without an argument) clear a previously base address. See also ``a''.
bi addr
Set an instruction breakpint at virtual address addr, or baseaddr+addr, if a base address has previously been set.
ba size addr
Set an read or write access breakpoint for access to the virtual address addr (or baseaddr+addr, if a base address has previously been set) with access width size (must be one of 1, 2, 4).
bw size addr
As ``ba'', but only for write accesses.
bt [ threadid ]
Restrict a previously set breakpoint to a particular thread, or (when not given an argument) remove such a restriction.
bx size addr lower_bound higher_bound
Restrict a previously set breakpoint. L4KD is only entered if addr contains a value of size size that is within the interval of [lower_bound, higher_bound]. If lower_bound is greater then higher_bound L4KD is only entered if value is not within the interval (higher_bound, lower_bound).
t [ threadid | long_threadid | tasknr.threadnr ]
Show TCBs (thread control blocks), the state associated with threads. The information displayed includes the thread's current kernel state, register set, and kernel stack.

When given without an argument, display the current thread's TCB. Otherwise display the given thread's TCB.

While displaying TCBs, the following additional commands are available:

Cursor Up/Down/Left/Right
Modify the displayed kernel stack pointer. (This does not really modify the thread's stack pointer but is intended for use with the next command.)
Return
Recalculate the displayed register set (taken from the kernel stack) based on a new kernel stack pointer adjusted with the previous commands. L4KD assumes to find a pusha like sequence plus an additional error code on the stack (the page fault handler seems to be the only one that generates this sequence). This can be used to evaluate the state of a thread that raised a page fault. Move the stack pointer up until the error code (0xfe00000?) is gone and press return.
d [ addr ]
Dump (display) memory at the current thread's virtual address addr (0 if none given). By default, the memory is displayed in hexadecimal form using 4-byte integers.

While dumping memory, the following additional commands are available:

Cursor Up/Down/Left/Right
Change cursor position.
PageUp/Down
Scroll the display down/up one screen.
Space
Change the displayed data format. This command cycles between the following formats:

  • hexadecimal display of 4-byte integers (default when invoking ``d''),
  • hexadecimal display of bytes (1-byte integers),
  • characters,
  • x86 page table.
Return
Interpret the 4-byte integer the cursor is positioned at as a pointer and start dumping memory at that address.
Home
Return to the address of the pointer last dereferenced with Return. (L4KD doesn't keep a history of all previous Returns, only the last one.)
p [ tasknr | addr ]
Dump x86 page table or page directory for task tasknr, or interpret memory at addr as a page table and dump it.

The same commands as with ``d'' are available here, too, with two modifications:

m [ framenr ]
Display mappings from the mapping database for physical page frame framenr (i.e., for physical address framenr*0x1000).

The mapping database represents mappings using a tree data structure. The display's last three colums represent the links within this tree. You can use the Cursor Down/Left/Right keys to traverse the tree. You can follow a link as long as the last bit of the link is zero. If you follow a link to the left/right with a least significant bit set to one it will lead you back to the previous level. If you follow such a link down, you will stay at the same point.

v addr tasknr
Display the virtual-to-physical address mapping for virtual address addr in task taskno.
k
Display global kernel state. This includes root pointers for various thread queues, the system clock, and the page directory pointer.
i size addr
Input a value of width size from I/O address addr and display it. size must be one of 1, 2, 4.
i [ a | i ] addr
Input a value from the APIC (``ia'') resp. the I/O APIC (``ii'') at address addr and display it.
o [ size | a | i ] addr value
Like the corresponding form of ``i'', but output the value given.
H
Halt the current thread. (See the bugs section)
T [ + | - ]
Turn on and off single-stepping.
P [ + | * | - ]
Monitor all page faults in the system (``P+'' and ``P*''), or turn off monitoring (``P-'').

``P+'' stops the system upon each page fault and gives the user the option of entering the kernel debugger (press ``i'' when a page fault message turns up) or simply resuming execution (any other key).

``P*'' just displays all page fault messages and doesn't offer entering L4KD at page fault time.

X [ + excpnr [ errcode_low errcode_high ] | - ]
Enter L4KD upon catching an excpnr exception with an error code in the given range. (The error code range is only prompted for for exceptions delivering error codes.)

``X-'' turns of exception monitoring.

I [ + | - ]
The command ``I+'' starts monitoring the keyboard (and a serial line, if initialized using ``VT'') in the timer interrupt for a press of the Escape key. If such an event occurs, L4KD is entered. Also, the timer interrupt will output a progress indicator on the video console (not on a serial terminal!) to make it easier to detect a hung system.

``I-'' disables this monitoring.

V [ a | c | m | h | T]
Select a video mode for interaction with L4KD. ``Vc'' selects the CGA output, and ``Vh'' or ``Vm'' select MGA (or Hercules) output. ``Va'' makes an atomatic choice between the first few options (it uses the default video mode of the machine).

``VT'' additionally enables output via a serial terminal (attached to COM2; 115.2kBit/s, 8N1). Input from the terminal can also be enabled by typing the character ``+'' on the terminal. Once this initialization has been completed, the terminal can also be used to send Escape characters to enter L4KD (see ``I+'').

Serial I/O and video console I/O can be used to control L4KD at the same time: Any character typed on any of the input media will appear on the other console device, too.

4 Bugs

4.1 Serious Bugs

The "H" command (halt kernel thread) currently doesn't work.

In all current versions of L4, all user tasks are privileged in the sense that it is trivial for them to invoke L4KD, e.g. using the enter_kdebug interface.

4.2 Minor Bugs

"b Space" doesn't show the current breakpoint (it displays nothing) - use "b Return".

(Pentium version only:) Due to machine limitations, instruction pointer breakpoints in the virtual address space of tasks which have been put into an L4 ``small address space'' have to be specified with the instruction's linear address which is its virtual address plus the small address space's segment's start address. Segments for small address spaces start at linear address 0xC0000000.

When displaying on a serial terminal, the last (80th) column is not displayed, and the display cannot be adjusted to 24 instead of 25 lines. In practice, this seldom hurts.

When using a serial terminal, the PageUp/PageDown keys are reverted, and the Home key is unavailable; also, there is no easy way to reboot the machine (Shift-Num doesn't work).

There is no way to browse the memory of a thread different from the current one in a "d"-like way. The only way to inspect memory of a different task is to lookup single pages of memory through the task's page directory using "p".

When browsing page directories using "p", dereferencing pointers to super (4 MB) pages (by pressing Return) doesn't work correctly.

There is no way to modify memory, even though there is a way to in/out bytes through I/O memory ("i"/"o").

There is currently no direct way to circumvent the initial invocation of L4KD during boot. However, this can be accomplished indirectly using rmgr(8).

In this manual page, the description of the "m" command is too terse.

5 See Also

l4kd_api , rmgr
Michael Hohmuth, Jean Wolter