gdbmacros.txt 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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. define bttnobp
  16. set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
  17. set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next)
  18. set $init_t=&init_task
  19. set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
  20. set var $stacksize = sizeof(union thread_union)
  21. while ($next_t != $init_t)
  22. set $next_t=(struct task_struct *)$next_t
  23. printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm
  24. printf "===================\n"
  25. set var $stackp = $next_t.thread.sp
  26. set var $stack_top = ($stackp & ~($stacksize - 1)) + $stacksize
  27. while ($stackp < $stack_top)
  28. if (*($stackp) > _stext && *($stackp) < _sinittext)
  29. info symbol *($stackp)
  30. end
  31. set $stackp += 4
  32. end
  33. set $next_th=(((char *)$next_t->thread_group.next) - $pid_off)
  34. while ($next_th != $next_t)
  35. set $next_th=(struct task_struct *)$next_th
  36. printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm
  37. printf "===================\n"
  38. set var $stackp = $next_t.thread.sp
  39. set var $stack_top = ($stackp & ~($stacksize - 1)) + stacksize
  40. while ($stackp < $stack_top)
  41. if (*($stackp) > _stext && *($stackp) < _sinittext)
  42. info symbol *($stackp)
  43. end
  44. set $stackp += 4
  45. end
  46. set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
  47. end
  48. set $next_t=(char *)($next_t->tasks.next) - $tasks_off
  49. end
  50. end
  51. document bttnobp
  52. dump all thread stack traces on a kernel compiled with !CONFIG_FRAME_POINTER
  53. end
  54. define btthreadstack
  55. set var $pid_task = $arg0
  56. printf "\npid %d; comm %s:\n", $pid_task.pid, $pid_task.comm
  57. printf "task struct: "
  58. print $pid_task
  59. printf "===================\n"
  60. set var $stackp = $pid_task.thread.sp
  61. set var $stacksize = sizeof(union thread_union)
  62. set var $stack_top = ($stackp & ~($stacksize - 1)) + $stacksize
  63. set var $stack_bot = ($stackp & ~($stacksize - 1))
  64. set $stackp = *((unsigned long *) $stackp)
  65. while (($stackp < $stack_top) && ($stackp > $stack_bot))
  66. set var $addr = *(((unsigned long *) $stackp) + 1)
  67. info symbol $addr
  68. set $stackp = *((unsigned long *) $stackp)
  69. end
  70. end
  71. document btthreadstack
  72. dump a thread stack using the given task structure pointer
  73. end
  74. define btt
  75. set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
  76. set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next)
  77. set $init_t=&init_task
  78. set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
  79. while ($next_t != $init_t)
  80. set $next_t=(struct task_struct *)$next_t
  81. btthreadstack $next_t
  82. set $next_th=(((char *)$next_t->thread_group.next) - $pid_off)
  83. while ($next_th != $next_t)
  84. set $next_th=(struct task_struct *)$next_th
  85. btthreadstack $next_th
  86. set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
  87. end
  88. set $next_t=(char *)($next_t->tasks.next) - $tasks_off
  89. end
  90. end
  91. document btt
  92. dump all thread stack traces on a kernel compiled with CONFIG_FRAME_POINTER
  93. end
  94. define btpid
  95. set var $pid = $arg0
  96. set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
  97. set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next)
  98. set $init_t=&init_task
  99. set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
  100. set var $pid_task = 0
  101. while ($next_t != $init_t)
  102. set $next_t=(struct task_struct *)$next_t
  103. if ($next_t.pid == $pid)
  104. set $pid_task = $next_t
  105. end
  106. set $next_th=(((char *)$next_t->thread_group.next) - $pid_off)
  107. while ($next_th != $next_t)
  108. set $next_th=(struct task_struct *)$next_th
  109. if ($next_th.pid == $pid)
  110. set $pid_task = $next_th
  111. end
  112. set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
  113. end
  114. set $next_t=(char *)($next_t->tasks.next) - $tasks_off
  115. end
  116. btthreadstack $pid_task
  117. end
  118. document btpid
  119. backtrace of pid
  120. end
  121. define trapinfo
  122. set var $pid = $arg0
  123. set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
  124. set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next)
  125. set $init_t=&init_task
  126. set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
  127. set var $pid_task = 0
  128. while ($next_t != $init_t)
  129. set $next_t=(struct task_struct *)$next_t
  130. if ($next_t.pid == $pid)
  131. set $pid_task = $next_t
  132. end
  133. set $next_th=(((char *)$next_t->thread_group.next) - $pid_off)
  134. while ($next_th != $next_t)
  135. set $next_th=(struct task_struct *)$next_th
  136. if ($next_th.pid == $pid)
  137. set $pid_task = $next_th
  138. end
  139. set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
  140. end
  141. set $next_t=(char *)($next_t->tasks.next) - $tasks_off
  142. end
  143. printf "Trapno %ld, cr2 0x%lx, error_code %ld\n", $pid_task.thread.trap_no, \
  144. $pid_task.thread.cr2, $pid_task.thread.error_code
  145. end
  146. document trapinfo
  147. Run info threads and lookup pid of thread #1
  148. 'trapinfo <pid>' will tell you by which trap & possibly
  149. address the kernel panicked.
  150. end
  151. define dump_record
  152. set var $desc = $arg0
  153. set var $info = $arg1
  154. if ($argc > 2)
  155. set var $prev_flags = $arg2
  156. else
  157. set var $prev_flags = 0
  158. end
  159. set var $prefix = 1
  160. set var $newline = 1
  161. set var $begin = $desc->text_blk_lpos.begin % (1U << prb->text_data_ring.size_bits)
  162. set var $next = $desc->text_blk_lpos.next % (1U << prb->text_data_ring.size_bits)
  163. # handle data-less record
  164. if ($begin & 1)
  165. set var $text_len = 0
  166. set var $log = ""
  167. else
  168. # handle wrapping data block
  169. if ($begin > $next)
  170. set var $begin = 0
  171. end
  172. # skip over descriptor id
  173. set var $begin = $begin + sizeof(long)
  174. # handle truncated message
  175. if ($next - $begin < $info->text_len)
  176. set var $text_len = $next - $begin
  177. else
  178. set var $text_len = $info->text_len
  179. end
  180. set var $log = &prb->text_data_ring.data[$begin]
  181. end
  182. # prev & LOG_CONT && !(info->flags & LOG_PREIX)
  183. if (($prev_flags & 8) && !($info->flags & 4))
  184. set var $prefix = 0
  185. end
  186. # info->flags & LOG_CONT
  187. if ($info->flags & 8)
  188. # (prev & LOG_CONT && !(prev & LOG_NEWLINE))
  189. if (($prev_flags & 8) && !($prev_flags & 2))
  190. set var $prefix = 0
  191. end
  192. # (!(info->flags & LOG_NEWLINE))
  193. if (!($info->flags & 2))
  194. set var $newline = 0
  195. end
  196. end
  197. if ($prefix)
  198. printf "[%5lu.%06lu] ", $info->ts_nsec / 1000000000, $info->ts_nsec % 1000000000
  199. end
  200. if ($text_len)
  201. eval "printf \"%%%d.%ds\", $log", $text_len, $text_len
  202. end
  203. if ($newline)
  204. printf "\n"
  205. end
  206. # handle dictionary data
  207. set var $dict = &$info->dev_info.subsystem[0]
  208. set var $dict_len = sizeof($info->dev_info.subsystem)
  209. if ($dict[0] != '\0')
  210. printf " SUBSYSTEM="
  211. set var $idx = 0
  212. while ($idx < $dict_len)
  213. set var $c = $dict[$idx]
  214. if ($c == '\0')
  215. loop_break
  216. else
  217. if ($c < ' ' || $c >= 127 || $c == '\\')
  218. printf "\\x%02x", $c
  219. else
  220. printf "%c", $c
  221. end
  222. end
  223. set var $idx = $idx + 1
  224. end
  225. printf "\n"
  226. end
  227. set var $dict = &$info->dev_info.device[0]
  228. set var $dict_len = sizeof($info->dev_info.device)
  229. if ($dict[0] != '\0')
  230. printf " DEVICE="
  231. set var $idx = 0
  232. while ($idx < $dict_len)
  233. set var $c = $dict[$idx]
  234. if ($c == '\0')
  235. loop_break
  236. else
  237. if ($c < ' ' || $c >= 127 || $c == '\\')
  238. printf "\\x%02x", $c
  239. else
  240. printf "%c", $c
  241. end
  242. end
  243. set var $idx = $idx + 1
  244. end
  245. printf "\n"
  246. end
  247. end
  248. document dump_record
  249. Dump a single record. The first parameter is the descriptor,
  250. the second parameter is the info, the third parameter is
  251. optional and specifies the previous record's flags, used for
  252. properly formatting continued lines.
  253. end
  254. define dmesg
  255. # definitions from kernel/printk/printk_ringbuffer.h
  256. set var $desc_committed = 1
  257. set var $desc_finalized = 2
  258. set var $desc_sv_bits = sizeof(long) * 8
  259. set var $desc_flags_shift = $desc_sv_bits - 2
  260. set var $desc_flags_mask = 3 << $desc_flags_shift
  261. set var $id_mask = ~$desc_flags_mask
  262. set var $desc_count = 1U << prb->desc_ring.count_bits
  263. set var $prev_flags = 0
  264. set var $id = prb->desc_ring.tail_id.counter
  265. set var $end_id = prb->desc_ring.head_id.counter
  266. while (1)
  267. set var $desc = &prb->desc_ring.descs[$id % $desc_count]
  268. set var $info = &prb->desc_ring.infos[$id % $desc_count]
  269. # skip non-committed record
  270. set var $state = 3 & ($desc->state_var.counter >> $desc_flags_shift)
  271. if ($state == $desc_committed || $state == $desc_finalized)
  272. dump_record $desc $info $prev_flags
  273. set var $prev_flags = $info->flags
  274. end
  275. if ($id == $end_id)
  276. loop_break
  277. end
  278. set var $id = ($id + 1) & $id_mask
  279. end
  280. end
  281. document dmesg
  282. print the kernel ring buffer
  283. end