Back to home page

OSCL-LXR

 
 

    


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