Commit | Line | Data |
---|---|---|
b089f4a6 VG |
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 | ||
16 | define bttnobp | |
17 | set $tasks_off=((size_t)&((struct task_struct *)0)->tasks) | |
a0c20dea | 18 | set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next) |
b089f4a6 VG |
19 | set $init_t=&init_task |
20 | set $next_t=(((char *)($init_t->tasks).next) - $tasks_off) | |
a0c20dea | 21 | set var $stacksize = sizeof(union thread_union) |
b089f4a6 VG |
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" | |
a0c20dea CM |
26 | set var $stackp = $next_t.thread.sp |
27 | set var $stack_top = ($stackp & ~($stacksize - 1)) + $stacksize | |
b089f4a6 VG |
28 | |
29 | while ($stackp < $stack_top) | |
30 | if (*($stackp) > _stext && *($stackp) < _sinittext) | |
31 | info symbol *($stackp) | |
32 | end | |
33 | set $stackp += 4 | |
34 | end | |
a0c20dea | 35 | set $next_th=(((char *)$next_t->thread_group.next) - $pid_off) |
b089f4a6 VG |
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" | |
a0c20dea CM |
40 | set var $stackp = $next_t.thread.sp |
41 | set var $stack_top = ($stackp & ~($stacksize - 1)) + stacksize | |
b089f4a6 VG |
42 | |
43 | while ($stackp < $stack_top) | |
44 | if (*($stackp) > _stext && *($stackp) < _sinittext) | |
45 | info symbol *($stackp) | |
46 | end | |
47 | set $stackp += 4 | |
48 | end | |
a0c20dea | 49 | set $next_th=(((char *)$next_th->thread_group.next) - $pid_off) |
b089f4a6 VG |
50 | end |
51 | set $next_t=(char *)($next_t->tasks.next) - $tasks_off | |
52 | end | |
53 | end | |
54 | document bttnobp | |
55 | dump all thread stack traces on a kernel compiled with !CONFIG_FRAME_POINTER | |
56 | end | |
57 | ||
a0c20dea CM |
58 | define 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 | |
76 | end | |
77 | document btthreadstack | |
78 | dump a thread stack using the given task structure pointer | |
79 | end | |
80 | ||
81 | ||
b089f4a6 VG |
82 | define btt |
83 | set $tasks_off=((size_t)&((struct task_struct *)0)->tasks) | |
a0c20dea | 84 | set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next) |
b089f4a6 VG |
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 | |
a0c20dea | 89 | btthreadstack $next_t |
b089f4a6 | 90 | |
a0c20dea | 91 | set $next_th=(((char *)$next_t->thread_group.next) - $pid_off) |
b089f4a6 VG |
92 | while ($next_th != $next_t) |
93 | set $next_th=(struct task_struct *)$next_th | |
a0c20dea CM |
94 | btthreadstack $next_th |
95 | set $next_th=(((char *)$next_th->thread_group.next) - $pid_off) | |
b089f4a6 VG |
96 | end |
97 | set $next_t=(char *)($next_t->tasks.next) - $tasks_off | |
98 | end | |
99 | end | |
100 | document btt | |
101 | dump all thread stack traces on a kernel compiled with CONFIG_FRAME_POINTER | |
102 | end | |
103 | ||
104 | define btpid | |
105 | set var $pid = $arg0 | |
106 | set $tasks_off=((size_t)&((struct task_struct *)0)->tasks) | |
a0c20dea | 107 | set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next) |
b089f4a6 VG |
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 | ||
a0c20dea | 119 | set $next_th=(((char *)$next_t->thread_group.next) - $pid_off) |
b089f4a6 VG |
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 | |
a0c20dea | 125 | set $next_th=(((char *)$next_th->thread_group.next) - $pid_off) |
b089f4a6 VG |
126 | end |
127 | set $next_t=(char *)($next_t->tasks.next) - $tasks_off | |
128 | end | |
129 | ||
a0c20dea | 130 | btthreadstack $pid_task |
b089f4a6 VG |
131 | end |
132 | document btpid | |
133 | backtrace of pid | |
134 | end | |
135 | ||
136 | ||
137 | define trapinfo | |
138 | set var $pid = $arg0 | |
139 | set $tasks_off=((size_t)&((struct task_struct *)0)->tasks) | |
a0c20dea | 140 | set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next) |
b089f4a6 VG |
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 | ||
a0c20dea | 152 | set $next_th=(((char *)$next_t->thread_group.next) - $pid_off) |
b089f4a6 VG |
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 | |
a0c20dea | 158 | set $next_th=(((char *)$next_th->thread_group.next) - $pid_off) |
b089f4a6 VG |
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 | ||
166 | end | |
167 | document trapinfo | |
168 | Run info threads and lookup pid of thread #1 | |
169 | 'trapinfo <pid>' will tell you by which trap & possibly | |
f18190bd | 170 | address the kernel panicked. |
b089f4a6 | 171 | end |
8428cfe8 | 172 | |
d8bae33d CM |
173 | define dump_log_idx |
174 | set $idx = $arg0 | |
175 | if ($argc > 1) | |
176 | set $prev_flags = $arg1 | |
177 | else | |
178 | set $prev_flags = 0 | |
179 | end | |
180 | set $msg = ((struct printk_log *) (log_buf + $idx)) | |
181 | set $prefix = 1 | |
182 | set $newline = 1 | |
183 | set $log = log_buf + $idx + sizeof(*$msg) | |
8428cfe8 | 184 | |
d8bae33d CM |
185 | # prev & LOG_CONT && !(msg->flags & LOG_PREIX) |
186 | if (($prev_flags & 8) && !($msg->flags & 4)) | |
187 | set $prefix = 0 | |
188 | end | |
189 | ||
190 | # msg->flags & LOG_CONT | |
191 | if ($msg->flags & 8) | |
192 | # (prev & LOG_CONT && !(prev & LOG_NEWLINE)) | |
193 | if (($prev_flags & 8) && !($prev_flags & 2)) | |
194 | set $prefix = 0 | |
195 | end | |
196 | # (!(msg->flags & LOG_NEWLINE)) | |
197 | if (!($msg->flags & 2)) | |
198 | set $newline = 0 | |
199 | end | |
200 | end | |
201 | ||
202 | if ($prefix) | |
203 | printf "[%5lu.%06lu] ", $msg->ts_nsec / 1000000000, $msg->ts_nsec % 1000000000 | |
204 | end | |
205 | if ($msg->text_len != 0) | |
206 | eval "printf \"%%%d.%ds\", $log", $msg->text_len, $msg->text_len | |
207 | end | |
208 | if ($newline) | |
209 | printf "\n" | |
210 | end | |
211 | if ($msg->dict_len > 0) | |
212 | set $dict = $log + $msg->text_len | |
213 | set $idx = 0 | |
214 | set $line = 1 | |
215 | while ($idx < $msg->dict_len) | |
216 | if ($line) | |
217 | printf " " | |
218 | set $line = 0 | |
219 | end | |
220 | set $c = $dict[$idx] | |
221 | if ($c == '\0') | |
222 | printf "\n" | |
223 | set $line = 1 | |
224 | else | |
225 | if ($c < ' ' || $c >= 127 || $c == '\\') | |
226 | printf "\\x%02x", $c | |
227 | else | |
228 | printf "%c", $c | |
229 | end | |
230 | end | |
231 | set $idx = $idx + 1 | |
232 | end | |
233 | printf "\n" | |
234 | end | |
235 | end | |
236 | document dump_log_idx | |
237 | Dump a single log given its index in the log buffer. The first | |
238 | parameter is the index into log_buf, the second is optional and | |
239 | specified the previous log buffer's flags, used for properly | |
240 | formatting continued lines. | |
241 | end | |
8428cfe8 | 242 | |
d8bae33d CM |
243 | define dmesg |
244 | set $i = log_first_idx | |
245 | set $end_idx = log_first_idx | |
246 | set $prev_flags = 0 | |
8428cfe8 | 247 | |
d8bae33d CM |
248 | while (1) |
249 | set $msg = ((struct printk_log *) (log_buf + $i)) | |
250 | if ($msg->len == 0) | |
251 | set $i = 0 | |
8428cfe8 | 252 | else |
d8bae33d CM |
253 | dump_log_idx $i $prev_flags |
254 | set $i = $i + $msg->len | |
255 | set $prev_flags = $msg->flags | |
256 | end | |
257 | if ($i == $end_idx) | |
258 | loop_break | |
8428cfe8 AM |
259 | end |
260 | end | |
261 | end | |
262 | document dmesg | |
263 | print the kernel ring buffer | |
264 | end |