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_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) 184 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 235end 236document 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. 241end 242 243define dmesg 244 set $i = log_first_idx 245 set $end_idx = log_first_idx 246 set $prev_flags = 0 247 248 while (1) 249 set $msg = ((struct printk_log *) (log_buf + $i)) 250 if ($msg->len == 0) 251 set $i = 0 252 else 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 259 end 260 end 261end 262document dmesg 263 print the kernel ring buffer 264end 265