324 lines · plain
1#2# This file contains a few gdb macros (user defined commands) to extract3# useful information from kernel crashdump (kdump) like stack traces of4# all the processes or a particular process and trapinfo.5#6# These macros can be used by copying this file in .gdbinit (put in home7# directory or current directory) or by invoking gdb command with8# --command=<command-file-name> option9#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 bttnobp17 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_task20 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_t24 printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm25 printf "===================\n"26 set var $stackp = $next_t.thread.sp27 set var $stack_top = ($stackp & ~($stacksize - 1)) + $stacksize28 29 while ($stackp < $stack_top)30 if (*($stackp) > _stext && *($stackp) < _sinittext)31 info symbol *($stackp)32 end33 set $stackp += 434 end35 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_th38 printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm39 printf "===================\n"40 set var $stackp = $next_t.thread.sp41 set var $stack_top = ($stackp & ~($stacksize - 1)) + stacksize42 43 while ($stackp < $stack_top)44 if (*($stackp) > _stext && *($stackp) < _sinittext)45 info symbol *($stackp)46 end47 set $stackp += 448 end49 set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)50 end51 set $next_t=(char *)($next_t->tasks.next) - $tasks_off52 end53end54document bttnobp55 dump all thread stack traces on a kernel compiled with !CONFIG_FRAME_POINTER56end57 58define btthreadstack59 set var $pid_task = $arg060 61 printf "\npid %d; comm %s:\n", $pid_task.pid, $pid_task.comm62 printf "task struct: "63 print $pid_task64 printf "===================\n"65 set var $stackp = $pid_task.thread.sp66 set var $stacksize = sizeof(union thread_union)67 set var $stack_top = ($stackp & ~($stacksize - 1)) + $stacksize68 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 $addr74 set $stackp = *((unsigned long *) $stackp)75 end76end77document btthreadstack78 dump a thread stack using the given task structure pointer79end80 81 82define btt83 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_task86 set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)87 while ($next_t != $init_t)88 set $next_t=(struct task_struct *)$next_t89 btthreadstack $next_t90 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_th94 btthreadstack $next_th95 set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)96 end97 set $next_t=(char *)($next_t->tasks.next) - $tasks_off98 end99end100document btt101 dump all thread stack traces on a kernel compiled with CONFIG_FRAME_POINTER102end103 104define btpid105 set var $pid = $arg0106 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_task109 set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)110 set var $pid_task = 0111 112 while ($next_t != $init_t)113 set $next_t=(struct task_struct *)$next_t114 115 if ($next_t.pid == $pid)116 set $pid_task = $next_t117 end118 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_th122 if ($next_th.pid == $pid)123 set $pid_task = $next_th124 end125 set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)126 end127 set $next_t=(char *)($next_t->tasks.next) - $tasks_off128 end129 130 btthreadstack $pid_task131end132document btpid133 backtrace of pid134end135 136 137define trapinfo138 set var $pid = $arg0139 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_task142 set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)143 set var $pid_task = 0144 145 while ($next_t != $init_t)146 set $next_t=(struct task_struct *)$next_t147 148 if ($next_t.pid == $pid)149 set $pid_task = $next_t150 end151 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_th155 if ($next_th.pid == $pid)156 set $pid_task = $next_th157 end158 set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)159 end160 set $next_t=(char *)($next_t->tasks.next) - $tasks_off161 end162 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_code165 166end167document trapinfo168 Run info threads and lookup pid of thread #1169 'trapinfo <pid>' will tell you by which trap & possibly170 address the kernel panicked.171end172 173define dump_record174 set var $desc = $arg0175 set var $info = $arg1176 if ($argc > 2)177 set var $prev_flags = $arg2178 else179 set var $prev_flags = 0180 end181 182 set var $prefix = 1183 set var $newline = 1184 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 record189 if ($begin & 1)190 set var $text_len = 0191 set var $log = ""192 else193 # handle wrapping data block194 if ($begin > $next)195 set var $begin = 0196 end197 198 # skip over descriptor id199 set var $begin = $begin + sizeof(long)200 201 # handle truncated message202 if ($next - $begin < $info->text_len)203 set var $text_len = $next - $begin204 else205 set var $text_len = $info->text_len206 end207 208 set var $log = &prb->text_data_ring.data[$begin]209 end210 211 # prev & LOG_CONT && !(info->flags & LOG_PREIX)212 if (($prev_flags & 8) && !($info->flags & 4))213 set var $prefix = 0214 end215 216 # info->flags & LOG_CONT217 if ($info->flags & 8)218 # (prev & LOG_CONT && !(prev & LOG_NEWLINE))219 if (($prev_flags & 8) && !($prev_flags & 2))220 set var $prefix = 0221 end222 # (!(info->flags & LOG_NEWLINE))223 if (!($info->flags & 2))224 set var $newline = 0225 end226 end227 228 if ($prefix)229 printf "[%5lu.%06lu] ", $info->ts_nsec / 1000000000, $info->ts_nsec % 1000000000230 end231 if ($text_len)232 eval "printf \"%%%d.%ds\", $log", $text_len, $text_len233 end234 if ($newline)235 printf "\n"236 end237 238 # handle dictionary data239 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 = 0245 while ($idx < $dict_len)246 set var $c = $dict[$idx]247 if ($c == '\0')248 loop_break249 else250 if ($c < ' ' || $c >= 127 || $c == '\\')251 printf "\\x%02x", $c252 else253 printf "%c", $c254 end255 end256 set var $idx = $idx + 1257 end258 printf "\n"259 end260 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 = 0266 while ($idx < $dict_len)267 set var $c = $dict[$idx]268 if ($c == '\0')269 loop_break270 else271 if ($c < ' ' || $c >= 127 || $c == '\\')272 printf "\\x%02x", $c273 else274 printf "%c", $c275 end276 end277 set var $idx = $idx + 1278 end279 printf "\n"280 end281end282document dump_record283 Dump a single record. The first parameter is the descriptor,284 the second parameter is the info, the third parameter is285 optional and specifies the previous record's flags, used for286 properly formatting continued lines.287end288 289define dmesg290 # definitions from kernel/printk/printk_ringbuffer.h291 set var $desc_committed = 1292 set var $desc_finalized = 2293 set var $desc_sv_bits = sizeof(long) * 8294 set var $desc_flags_shift = $desc_sv_bits - 2295 set var $desc_flags_mask = 3 << $desc_flags_shift296 set var $id_mask = ~$desc_flags_mask297 298 set var $desc_count = 1U << prb->desc_ring.count_bits299 set var $prev_flags = 0300 301 set var $id = prb->desc_ring.tail_id.counter302 set var $end_id = prb->desc_ring.head_id.counter303 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 record309 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_flags312 set var $prev_flags = $info->flags313 end314 315 if ($id == $end_id)316 loop_break317 end318 set var $id = ($id + 1) & $id_mask319 end320end321document dmesg322 print the kernel ring buffer323end324