5 # Place a '<' marker on the current task
6 # if ($arg0 == current)
7 # For PowerPC, register r2 points to the 'current' task
8 if ($arg0 == $r2)
9 printf '<'
10 else
11 printf ' '
12 end
13
14 # State
15 if ($arg0->state == 0)
16 printf 'Running '
17 else
18 if ($arg0->state == 1)
19 printf 'Sleeping '
20 else
21 if ($arg0->state == 2)
22 printf 'Disksleep '
23 else
24 if ($arg0->state == 4)
25 printf 'Zombie '
26 else
27 if ($arg0->state == 8)
28 printf 'sTopped '
29 else
30 if ($arg0->state == 16)
31 printf 'Wpaging '
32 else
33 printf '%2d ', $arg0->state
34 end
35 end
36 end
37 end
38 end
39 end
40
41 # User NIP
42 if ($arg0->thread.regs)
43 printf '0x%08X ', $arg0->thread.regs->nip
44 else
45 printf ' '
46 end
47
48 # Display the kernel stack pointer
49 printf '0x%08X ', $arg0->thread.ksp
50
51 # device
52 if ($arg0->signal->tty)
53 printf '%s ', $arg0->signal->tty->name
54 else
55 printf '(none) '
56 end
57
58 # comm
59 printf '%s
', $arg0->comm
60 end
Line 3 displays the address of the task_struct. Lines 8 through 12 display the process ID. If this is the current process (the process that was currently running on this CPU at the time the breakpoint was hit), it is marked with a < character.
Lines 14 through 39 decode and display the state of the process. This is followed by displaying the user process next instruction pointer (NIP) and the kernel stack pointer (SP). Finally, the device associated with the process is displayed, followed by the name of the process (stored in the ->comm element of the task_struct .)
It is important to note that this macro is architecture dependent, as shown in lines 7 and 8. In general, macros such as these are highly architecture- and version-dependent. Any time a change in the underlying structure is made, macros such as these must be updated. However, if you spend a lot of time debugging the kernel using gdb, the payback is often worth the effort.
For completeness, we present the find_next_task macro. Its implementation is less than obvious and deserves explanation. (It is assumed that you can easily deduce the task_struct_header that completes the series necessary for the ps macro presented in this section. It is nothing more than a single line arranging the column headers with the correct amount of whitespace.) Listing 14-15 presents the find_next_task macro used in our ps and find_task macros.
Listing 14-15. gdb find_next_task Macro
define find_next_task
# Given a task address, find the next task in the linked list
set $t = (struct task_struct *)$arg0
set $offset=((char *)&$t->tasks - (char *)$t)
set $t=(struct task_struct *)((char *)$t->tasks.next- (char *)$offset)
end
The function performed by this macro is simple. The implementation is slightly less than straightforward. The goal is to return the ->next pointer, which points to the next task_struct on the linked list. However, the task_struct structures are linked by the address of the struct list_head member called tasks, as opposed to the common practice of being linked by the starting address of the task_struct itself. Because the ->next pointer points to the address of the task structure element in the next task_struct on the list, we must subtract to get the address of the top of the task_struct itself. The value we subtract from the ->next pointer is the offset from that pointer's address to the top of task_struct. First we calculate the offset and then we use that offset to adjust the ->next pointer to point to the top of task_struct. Figure 14-5 should make this clear.
Figure 14-5. Task structure list linking

Now we present one final macro that will be useful in the next section when we discuss debugging loadable modules. Listing 14-16 is a simple macro that displays the kernel's list of currently installed loadable modules.
Listing 14-16. gdb List Modules Macro
1 define lsmod
2 printf 'Address Module
'
3 set $m=(struct list_head *)&modules
4 set $done=0
5 while (!$done)
6 # list_head is 4-bytes into struct module