0001 #
0002 # This file contains a few gdb macros (user defined commands) to extract
0003 # useful information from kernel crashdump (kdump) like stack traces of
0004 # all the processes or a particular process and trapinfo.
0005 #
0006 # These macros can be used by copying this file in .gdbinit (put in home
0007 # directory or current directory) or by invoking gdb command with
0008 # --command=<command-file-name> option
0009 #
0010 # Credits:
0011 # Alexander Nyberg <alexn@telia.com>
0012 # V Srivatsa <vatsa@in.ibm.com>
0013 # Maneesh Soni <maneesh@in.ibm.com>
0014 #
0015
0016 define bttnobp
0017 set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
0018 set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next)
0019 set $init_t=&init_task
0020 set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
0021 set var $stacksize = sizeof(union thread_union)
0022 while ($next_t != $init_t)
0023 set $next_t=(struct task_struct *)$next_t
0024 printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm
0025 printf "===================\n"
0026 set var $stackp = $next_t.thread.sp
0027 set var $stack_top = ($stackp & ~($stacksize - 1)) + $stacksize
0028
0029 while ($stackp < $stack_top)
0030 if (*($stackp) > _stext && *($stackp) < _sinittext)
0031 info symbol *($stackp)
0032 end
0033 set $stackp += 4
0034 end
0035 set $next_th=(((char *)$next_t->thread_group.next) - $pid_off)
0036 while ($next_th != $next_t)
0037 set $next_th=(struct task_struct *)$next_th
0038 printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm
0039 printf "===================\n"
0040 set var $stackp = $next_t.thread.sp
0041 set var $stack_top = ($stackp & ~($stacksize - 1)) + stacksize
0042
0043 while ($stackp < $stack_top)
0044 if (*($stackp) > _stext && *($stackp) < _sinittext)
0045 info symbol *($stackp)
0046 end
0047 set $stackp += 4
0048 end
0049 set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
0050 end
0051 set $next_t=(char *)($next_t->tasks.next) - $tasks_off
0052 end
0053 end
0054 document bttnobp
0055 dump all thread stack traces on a kernel compiled with !CONFIG_FRAME_POINTER
0056 end
0057
0058 define btthreadstack
0059 set var $pid_task = $arg0
0060
0061 printf "\npid %d; comm %s:\n", $pid_task.pid, $pid_task.comm
0062 printf "task struct: "
0063 print $pid_task
0064 printf "===================\n"
0065 set var $stackp = $pid_task.thread.sp
0066 set var $stacksize = sizeof(union thread_union)
0067 set var $stack_top = ($stackp & ~($stacksize - 1)) + $stacksize
0068 set var $stack_bot = ($stackp & ~($stacksize - 1))
0069
0070 set $stackp = *((unsigned long *) $stackp)
0071 while (($stackp < $stack_top) && ($stackp > $stack_bot))
0072 set var $addr = *(((unsigned long *) $stackp) + 1)
0073 info symbol $addr
0074 set $stackp = *((unsigned long *) $stackp)
0075 end
0076 end
0077 document btthreadstack
0078 dump a thread stack using the given task structure pointer
0079 end
0080
0081
0082 define btt
0083 set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
0084 set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next)
0085 set $init_t=&init_task
0086 set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
0087 while ($next_t != $init_t)
0088 set $next_t=(struct task_struct *)$next_t
0089 btthreadstack $next_t
0090
0091 set $next_th=(((char *)$next_t->thread_group.next) - $pid_off)
0092 while ($next_th != $next_t)
0093 set $next_th=(struct task_struct *)$next_th
0094 btthreadstack $next_th
0095 set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
0096 end
0097 set $next_t=(char *)($next_t->tasks.next) - $tasks_off
0098 end
0099 end
0100 document btt
0101 dump all thread stack traces on a kernel compiled with CONFIG_FRAME_POINTER
0102 end
0103
0104 define btpid
0105 set var $pid = $arg0
0106 set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
0107 set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next)
0108 set $init_t=&init_task
0109 set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
0110 set var $pid_task = 0
0111
0112 while ($next_t != $init_t)
0113 set $next_t=(struct task_struct *)$next_t
0114
0115 if ($next_t.pid == $pid)
0116 set $pid_task = $next_t
0117 end
0118
0119 set $next_th=(((char *)$next_t->thread_group.next) - $pid_off)
0120 while ($next_th != $next_t)
0121 set $next_th=(struct task_struct *)$next_th
0122 if ($next_th.pid == $pid)
0123 set $pid_task = $next_th
0124 end
0125 set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
0126 end
0127 set $next_t=(char *)($next_t->tasks.next) - $tasks_off
0128 end
0129
0130 btthreadstack $pid_task
0131 end
0132 document btpid
0133 backtrace of pid
0134 end
0135
0136
0137 define trapinfo
0138 set var $pid = $arg0
0139 set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
0140 set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next)
0141 set $init_t=&init_task
0142 set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
0143 set var $pid_task = 0
0144
0145 while ($next_t != $init_t)
0146 set $next_t=(struct task_struct *)$next_t
0147
0148 if ($next_t.pid == $pid)
0149 set $pid_task = $next_t
0150 end
0151
0152 set $next_th=(((char *)$next_t->thread_group.next) - $pid_off)
0153 while ($next_th != $next_t)
0154 set $next_th=(struct task_struct *)$next_th
0155 if ($next_th.pid == $pid)
0156 set $pid_task = $next_th
0157 end
0158 set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
0159 end
0160 set $next_t=(char *)($next_t->tasks.next) - $tasks_off
0161 end
0162
0163 printf "Trapno %ld, cr2 0x%lx, error_code %ld\n", $pid_task.thread.trap_no, \
0164 $pid_task.thread.cr2, $pid_task.thread.error_code
0165
0166 end
0167 document trapinfo
0168 Run info threads and lookup pid of thread #1
0169 'trapinfo <pid>' will tell you by which trap & possibly
0170 address the kernel panicked.
0171 end
0172
0173 define dump_record
0174 set var $desc = $arg0
0175 set var $info = $arg1
0176 if ($argc > 2)
0177 set var $prev_flags = $arg2
0178 else
0179 set var $prev_flags = 0
0180 end
0181
0182 set var $prefix = 1
0183 set var $newline = 1
0184
0185 set var $begin = $desc->text_blk_lpos.begin % (1U << prb->text_data_ring.size_bits)
0186 set var $next = $desc->text_blk_lpos.next % (1U << prb->text_data_ring.size_bits)
0187
0188 # handle data-less record
0189 if ($begin & 1)
0190 set var $text_len = 0
0191 set var $log = ""
0192 else
0193 # handle wrapping data block
0194 if ($begin > $next)
0195 set var $begin = 0
0196 end
0197
0198 # skip over descriptor id
0199 set var $begin = $begin + sizeof(long)
0200
0201 # handle truncated message
0202 if ($next - $begin < $info->text_len)
0203 set var $text_len = $next - $begin
0204 else
0205 set var $text_len = $info->text_len
0206 end
0207
0208 set var $log = &prb->text_data_ring.data[$begin]
0209 end
0210
0211 # prev & LOG_CONT && !(info->flags & LOG_PREIX)
0212 if (($prev_flags & 8) && !($info->flags & 4))
0213 set var $prefix = 0
0214 end
0215
0216 # info->flags & LOG_CONT
0217 if ($info->flags & 8)
0218 # (prev & LOG_CONT && !(prev & LOG_NEWLINE))
0219 if (($prev_flags & 8) && !($prev_flags & 2))
0220 set var $prefix = 0
0221 end
0222 # (!(info->flags & LOG_NEWLINE))
0223 if (!($info->flags & 2))
0224 set var $newline = 0
0225 end
0226 end
0227
0228 if ($prefix)
0229 printf "[%5lu.%06lu] ", $info->ts_nsec / 1000000000, $info->ts_nsec % 1000000000
0230 end
0231 if ($text_len)
0232 eval "printf \"%%%d.%ds\", $log", $text_len, $text_len
0233 end
0234 if ($newline)
0235 printf "\n"
0236 end
0237
0238 # handle dictionary data
0239
0240 set var $dict = &$info->dev_info.subsystem[0]
0241 set var $dict_len = sizeof($info->dev_info.subsystem)
0242 if ($dict[0] != '\0')
0243 printf " SUBSYSTEM="
0244 set var $idx = 0
0245 while ($idx < $dict_len)
0246 set var $c = $dict[$idx]
0247 if ($c == '\0')
0248 loop_break
0249 else
0250 if ($c < ' ' || $c >= 127 || $c == '\\')
0251 printf "\\x%02x", $c
0252 else
0253 printf "%c", $c
0254 end
0255 end
0256 set var $idx = $idx + 1
0257 end
0258 printf "\n"
0259 end
0260
0261 set var $dict = &$info->dev_info.device[0]
0262 set var $dict_len = sizeof($info->dev_info.device)
0263 if ($dict[0] != '\0')
0264 printf " DEVICE="
0265 set var $idx = 0
0266 while ($idx < $dict_len)
0267 set var $c = $dict[$idx]
0268 if ($c == '\0')
0269 loop_break
0270 else
0271 if ($c < ' ' || $c >= 127 || $c == '\\')
0272 printf "\\x%02x", $c
0273 else
0274 printf "%c", $c
0275 end
0276 end
0277 set var $idx = $idx + 1
0278 end
0279 printf "\n"
0280 end
0281 end
0282 document dump_record
0283 Dump a single record. The first parameter is the descriptor,
0284 the second parameter is the info, the third parameter is
0285 optional and specifies the previous record's flags, used for
0286 properly formatting continued lines.
0287 end
0288
0289 define dmesg
0290 # definitions from kernel/printk/printk_ringbuffer.h
0291 set var $desc_committed = 1
0292 set var $desc_finalized = 2
0293 set var $desc_sv_bits = sizeof(long) * 8
0294 set var $desc_flags_shift = $desc_sv_bits - 2
0295 set var $desc_flags_mask = 3 << $desc_flags_shift
0296 set var $id_mask = ~$desc_flags_mask
0297
0298 set var $desc_count = 1U << prb->desc_ring.count_bits
0299 set var $prev_flags = 0
0300
0301 set var $id = prb->desc_ring.tail_id.counter
0302 set var $end_id = prb->desc_ring.head_id.counter
0303
0304 while (1)
0305 set var $desc = &prb->desc_ring.descs[$id % $desc_count]
0306 set var $info = &prb->desc_ring.infos[$id % $desc_count]
0307
0308 # skip non-committed record
0309 set var $state = 3 & ($desc->state_var.counter >> $desc_flags_shift)
0310 if ($state == $desc_committed || $state == $desc_finalized)
0311 dump_record $desc $info $prev_flags
0312 set var $prev_flags = $info->flags
0313 end
0314
0315 set var $id = ($id + 1) & $id_mask
0316 if ($id == $end_id)
0317 loop_break
0318 end
0319 end
0320 end
0321 document dmesg
0322 print the kernel ring buffer
0323 end