Loading...
Note: File does not exist in v4.6.
1#
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.
5#
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
9#
10# Credits:
11# Alexander Nyberg <alexn@telia.com>
12# V Srivatsa <vatsa@in.ibm.com>
13# Maneesh Soni <maneesh@in.ibm.com>
14#
15
16define bttnobp
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
28
29 while ($stackp < $stack_top)
30 if (*($stackp) > _stext && *($stackp) < _sinittext)
31 info symbol *($stackp)
32 end
33 set $stackp += 4
34 end
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
42
43 while ($stackp < $stack_top)
44 if (*($stackp) > _stext && *($stackp) < _sinittext)
45 info symbol *($stackp)
46 end
47 set $stackp += 4
48 end
49 set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
50 end
51 set $next_t=(char *)($next_t->tasks.next) - $tasks_off
52 end
53end
54document bttnobp
55 dump all thread stack traces on a kernel compiled with !CONFIG_FRAME_POINTER
56end
57
58define btthreadstack
59 set var $pid_task = $arg0
60
61 printf "\npid %d; comm %s:\n", $pid_task.pid, $pid_task.comm
62 printf "task struct: "
63 print $pid_task
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))
69
70 set $stackp = *((unsigned long *) $stackp)
71 while (($stackp < $stack_top) && ($stackp > $stack_bot))
72 set var $addr = *(((unsigned long *) $stackp) + 1)
73 info symbol $addr
74 set $stackp = *((unsigned long *) $stackp)
75 end
76end
77document btthreadstack
78 dump a thread stack using the given task structure pointer
79end
80
81
82define btt
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
89 btthreadstack $next_t
90
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)
96 end
97 set $next_t=(char *)($next_t->tasks.next) - $tasks_off
98 end
99end
100document btt
101 dump all thread stack traces on a kernel compiled with CONFIG_FRAME_POINTER
102end
103
104define btpid
105 set var $pid = $arg0
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
111
112 while ($next_t != $init_t)
113 set $next_t=(struct task_struct *)$next_t
114
115 if ($next_t.pid == $pid)
116 set $pid_task = $next_t
117 end
118
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
124 end
125 set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
126 end
127 set $next_t=(char *)($next_t->tasks.next) - $tasks_off
128 end
129
130 btthreadstack $pid_task
131end
132document btpid
133 backtrace of pid
134end
135
136
137define trapinfo
138 set var $pid = $arg0
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
144
145 while ($next_t != $init_t)
146 set $next_t=(struct task_struct *)$next_t
147
148 if ($next_t.pid == $pid)
149 set $pid_task = $next_t
150 end
151
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
157 end
158 set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
159 end
160 set $next_t=(char *)($next_t->tasks.next) - $tasks_off
161 end
162
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
165
166end
167document trapinfo
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.
171end
172
173define dump_record
174 set var $desc = $arg0
175 set var $info = $arg1
176 if ($argc > 2)
177 set var $prev_flags = $arg2
178 else
179 set var $prev_flags = 0
180 end
181
182 set var $prefix = 1
183 set var $newline = 1
184
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)
187
188 # handle data-less record
189 if ($begin & 1)
190 set var $text_len = 0
191 set var $log = ""
192 else
193 # handle wrapping data block
194 if ($begin > $next)
195 set var $begin = 0
196 end
197
198 # skip over descriptor id
199 set var $begin = $begin + sizeof(long)
200
201 # handle truncated message
202 if ($next - $begin < $info->text_len)
203 set var $text_len = $next - $begin
204 else
205 set var $text_len = $info->text_len
206 end
207
208 set var $log = &prb->text_data_ring.data[$begin]
209 end
210
211 # prev & LOG_CONT && !(info->flags & LOG_PREIX)
212 if (($prev_flags & 8) && !($info->flags & 4))
213 set var $prefix = 0
214 end
215
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))
220 set var $prefix = 0
221 end
222 # (!(info->flags & LOG_NEWLINE))
223 if (!($info->flags & 2))
224 set var $newline = 0
225 end
226 end
227
228 if ($prefix)
229 printf "[%5lu.%06lu] ", $info->ts_nsec / 1000000000, $info->ts_nsec % 1000000000
230 end
231 if ($text_len)
232 eval "printf \"%%%d.%ds\", $log", $text_len, $text_len
233 end
234 if ($newline)
235 printf "\n"
236 end
237
238 # handle dictionary data
239
240 set var $dict = &$info->dev_info.subsystem[0]
241 set var $dict_len = sizeof($info->dev_info.subsystem)
242 if ($dict[0] != '\0')
243 printf " SUBSYSTEM="
244 set var $idx = 0
245 while ($idx < $dict_len)
246 set var $c = $dict[$idx]
247 if ($c == '\0')
248 loop_break
249 else
250 if ($c < ' ' || $c >= 127 || $c == '\\')
251 printf "\\x%02x", $c
252 else
253 printf "%c", $c
254 end
255 end
256 set var $idx = $idx + 1
257 end
258 printf "\n"
259 end
260
261 set var $dict = &$info->dev_info.device[0]
262 set var $dict_len = sizeof($info->dev_info.device)
263 if ($dict[0] != '\0')
264 printf " DEVICE="
265 set var $idx = 0
266 while ($idx < $dict_len)
267 set var $c = $dict[$idx]
268 if ($c == '\0')
269 loop_break
270 else
271 if ($c < ' ' || $c >= 127 || $c == '\\')
272 printf "\\x%02x", $c
273 else
274 printf "%c", $c
275 end
276 end
277 set var $idx = $idx + 1
278 end
279 printf "\n"
280 end
281end
282document dump_record
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.
287end
288
289define dmesg
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
297
298 set var $desc_count = 1U << prb->desc_ring.count_bits
299 set var $prev_flags = 0
300
301 set var $id = prb->desc_ring.tail_id.counter
302 set var $end_id = prb->desc_ring.head_id.counter
303
304 while (1)
305 set var $desc = &prb->desc_ring.descs[$id % $desc_count]
306 set var $info = &prb->desc_ring.infos[$id % $desc_count]
307
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
313 end
314
315 if ($id == $end_id)
316 loop_break
317 end
318 set var $id = ($id + 1) & $id_mask
319 end
320end
321document dmesg
322 print the kernel ring buffer
323end