2 # This file contains a few gdb macros (user defined commands) to extract
3 # useful information from kernel crashdump (kdump) like stack traces of
4 # all the processes or a particular process and trapinfo.
6 # These macros can be used by copying this file in .gdbinit (put in home
7 # directory or current directory) or by invoking gdb command with
8 # --command=<command-file-name> option
11 # Alexander Nyberg <alexn@telia.com>
12 # V Srivatsa <vatsa@in.ibm.com>
13 # Maneesh Soni <maneesh@in.ibm.com>
17 set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
18 set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next)
19 set $init_t=&init_task
20 set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
21 set var $stacksize = sizeof(union thread_union)
22 while ($next_t != $init_t)
23 set $next_t=(struct task_struct *)$next_t
24 printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm
25 printf "===================\n"
26 set var $stackp = $next_t.thread.sp
27 set var $stack_top = ($stackp & ~($stacksize - 1)) + $stacksize
29 while ($stackp < $stack_top)
30 if (*($stackp) > _stext && *($stackp) < _sinittext)
31 info symbol *($stackp)
35 set $next_th=(((char *)$next_t->thread_group.next) - $pid_off)
36 while ($next_th != $next_t)
37 set $next_th=(struct task_struct *)$next_th
38 printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm
39 printf "===================\n"
40 set var $stackp = $next_t.thread.sp
41 set var $stack_top = ($stackp & ~($stacksize - 1)) + stacksize
43 while ($stackp < $stack_top)
44 if (*($stackp) > _stext && *($stackp) < _sinittext)
45 info symbol *($stackp)
49 set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
51 set $next_t=(char *)($next_t->tasks.next) - $tasks_off
55 dump all thread stack traces on a kernel compiled with !CONFIG_FRAME_POINTER
59 set var $pid_task = $arg0
61 printf "\npid %d; comm %s:\n", $pid_task.pid, $pid_task.comm
62 printf "task struct: "
64 printf "===================\n"
65 set var $stackp = $pid_task.thread.sp
66 set var $stacksize = sizeof(union thread_union)
67 set var $stack_top = ($stackp & ~($stacksize - 1)) + $stacksize
68 set var $stack_bot = ($stackp & ~($stacksize - 1))
70 set $stackp = *((unsigned long *) $stackp)
71 while (($stackp < $stack_top) && ($stackp > $stack_bot))
72 set var $addr = *(((unsigned long *) $stackp) + 1)
74 set $stackp = *((unsigned long *) $stackp)
77 document btthreadstack
78 dump a thread stack using the given task structure pointer
83 set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
84 set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next)
85 set $init_t=&init_task
86 set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
87 while ($next_t != $init_t)
88 set $next_t=(struct task_struct *)$next_t
91 set $next_th=(((char *)$next_t->thread_group.next) - $pid_off)
92 while ($next_th != $next_t)
93 set $next_th=(struct task_struct *)$next_th
94 btthreadstack $next_th
95 set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
97 set $next_t=(char *)($next_t->tasks.next) - $tasks_off
101 dump all thread stack traces on a kernel compiled with CONFIG_FRAME_POINTER
106 set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
107 set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next)
108 set $init_t=&init_task
109 set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
110 set var $pid_task = 0
112 while ($next_t != $init_t)
113 set $next_t=(struct task_struct *)$next_t
115 if ($next_t.pid == $pid)
116 set $pid_task = $next_t
119 set $next_th=(((char *)$next_t->thread_group.next) - $pid_off)
120 while ($next_th != $next_t)
121 set $next_th=(struct task_struct *)$next_th
122 if ($next_th.pid == $pid)
123 set $pid_task = $next_th
125 set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
127 set $next_t=(char *)($next_t->tasks.next) - $tasks_off
130 btthreadstack $pid_task
139 set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
140 set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next)
141 set $init_t=&init_task
142 set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
143 set var $pid_task = 0
145 while ($next_t != $init_t)
146 set $next_t=(struct task_struct *)$next_t
148 if ($next_t.pid == $pid)
149 set $pid_task = $next_t
152 set $next_th=(((char *)$next_t->thread_group.next) - $pid_off)
153 while ($next_th != $next_t)
154 set $next_th=(struct task_struct *)$next_th
155 if ($next_th.pid == $pid)
156 set $pid_task = $next_th
158 set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
160 set $next_t=(char *)($next_t->tasks.next) - $tasks_off
163 printf "Trapno %ld, cr2 0x%lx, error_code %ld\n", $pid_task.thread.trap_no, \
164 $pid_task.thread.cr2, $pid_task.thread.error_code
168 Run info threads and lookup pid of thread #1
169 'trapinfo <pid>' will tell you by which trap & possibly
170 address the kernel panicked.
174 set var $desc = $arg0
175 set var $info = $arg1
177 set var $prev_flags = $arg2
179 set var $prev_flags = 0
185 set var $begin = $desc->text_blk_lpos.begin % (1U << prb->text_data_ring.size_bits)
186 set var $next = $desc->text_blk_lpos.next % (1U << prb->text_data_ring.size_bits)
188 # handle data-less record
190 set var $text_len = 0
193 # handle wrapping data block
198 # skip over descriptor id
199 set var $begin = $begin + sizeof(long)
201 # handle truncated message
202 if ($next - $begin < $info->text_len)
203 set var $text_len = $next - $begin
205 set var $text_len = $info->text_len
208 set var $log = &prb->text_data_ring.data[$begin]
211 # prev & LOG_CONT && !(info->flags & LOG_PREIX)
212 if (($prev_flags & 8) && !($info->flags & 4))
216 # info->flags & LOG_CONT
217 if ($info->flags & 8)
218 # (prev & LOG_CONT && !(prev & LOG_NEWLINE))
219 if (($prev_flags & 8) && !($prev_flags & 2))
222 # (!(info->flags & LOG_NEWLINE))
223 if (!($info->flags & 2))
229 printf "[%5lu.%06lu] ", $info->ts_nsec / 1000000000, $info->ts_nsec % 1000000000
232 eval "printf \"%%%d.%ds\", $log", $text_len, $text_len
238 # handle dictionary data
240 set var $dict = &$info->dev_info.subsystem[0]
241 set var $dict_len = sizeof($info->dev_info.subsystem)
242 if ($dict[0] != '\0')
245 while ($idx < $dict_len)
246 set var $c = $dict[$idx]
250 if ($c < ' ' || $c >= 127 || $c == '\\')
256 set var $idx = $idx + 1
261 set var $dict = &$info->dev_info.device[0]
262 set var $dict_len = sizeof($info->dev_info.device)
263 if ($dict[0] != '\0')
266 while ($idx < $dict_len)
267 set var $c = $dict[$idx]
271 if ($c < ' ' || $c >= 127 || $c == '\\')
277 set var $idx = $idx + 1
283 Dump a single record. The first parameter is the descriptor,
284 the second parameter is the info, the third parameter is
285 optional and specifies the previous record's flags, used for
286 properly formatting continued lines.
290 # definitions from kernel/printk/printk_ringbuffer.h
291 set var $desc_committed = 1
292 set var $desc_finalized = 2
293 set var $desc_sv_bits = sizeof(long) * 8
294 set var $desc_flags_shift = $desc_sv_bits - 2
295 set var $desc_flags_mask = 3 << $desc_flags_shift
296 set var $id_mask = ~$desc_flags_mask
298 set var $desc_count = 1U << prb->desc_ring.count_bits
299 set var $prev_flags = 0
301 set var $id = prb->desc_ring.tail_id.counter
302 set var $end_id = prb->desc_ring.head_id.counter
305 set var $desc = &prb->desc_ring.descs[$id % $desc_count]
306 set var $info = &prb->desc_ring.infos[$id % $desc_count]
308 # skip non-committed record
309 set var $state = 3 & ($desc->state_var.counter >> $desc_flags_shift)
310 if ($state == $desc_committed || $state == $desc_finalized)
311 dump_record $desc $info $prev_flags
312 set var $prev_flags = $info->flags
315 set var $id = ($id + 1) & $id_mask
322 print the kernel ring buffer