当gdb不支持操作系统时,使用gdb的Python来回溯不同的OS线程

时间:2016-09-20 16:05:06

标签: c debugging operating-system gdb gdb-python

我还在学习在gdb中使用python调试C(在我的例子中是arm-none-eabi-gdb)。我正在尝试使用此工具来获取在ARM Cortex-M上运行的实时操作系统的线程信息。阅读一些操作系统结构,我可以访问操作系统的 线程控制块。我知道每个线程的PC和SP。我怎样才能使用gdb的Python来转储线程'回溯。在给定PC和SP时,是否存在可以遍历堆栈的通用API?

我已阅读https://sourceware.org/gdb/current/onlinedocs/gdb/Unwinding-Frames-in-Python.html#Unwinding-Frames-in-Python,我觉得可能有办法实现这一目标,但我需要一些帮助。

另外,如果可能的话,我可以让gdb知道操作系统的不同线程吗?这个链接: https://sourceware.org/gdb/current/onlinedocs/gdb/Threads-In-Python.html#Threads-In-Python涉及线程,但依赖于操作系统信息。根据我对各自控制块的不同操作系统线程的了解,这些是否会过载?

谢谢!

2 个答案:

答案 0 :(得分:0)

经过多次阅读并试图利用我多年来积累的旧调试器知识,我设法让这个工作。它缺乏优化,但就目前而言,我非常高兴。这可以被认为是一个穷人的调试器,利用GDB的Python支持来跟踪系统中的活动线程。我认为它是通用的,但实现针对的是RTX(Keil的操作系统)。它适用于Cortex-M0。可能需要进行一些调整以适应其他操作系统或不同的核心。

主要想法:

  1. 使用OS结构来识别线程控制块所在的位置。
  2. 从线程控制块中识别不同线程堆栈的位置。
  3. 从堆栈中读取所有重要的寄存器; SP,LR和PC
  4. 为当前正在运行的线程保存相同的寄存器。
  5. 遍历不同的线程,将重要的寄存器更改为与线程匹配的寄存器,然后打印回溯。
  6. 享受一个穷人的操作系统感知调试器。
  7. 脚本可以在这里找到:

    https://gitlab.com/hesham/gdb-rtx-thread-backtrce/blob/master/rtx-threads-bt.py

    探索GDB的Python扩展功能是一次非常好的练习!

答案 1 :(得分:0)

对于FreeRTOS,我使用以下gdb脚本:

define printtasklist
  # $arg0 is a pointer to an uxList of tasks.
  set $plist = (List_t*)$arg0
  printf ": %d tasks\n", $plist->uxNumberOfItems
  set $iter = $plist->xListEnd.pxNext
  while ($iter != &$plist->xListEnd)
    set $vtask = ($iter->pvOwner)
    set $task = (tskTCB*)$vtask
    print $task
    print $task->pcTaskName
    set $iter = $iter->pxNext
  end
end

define printtasks
  printf "%d tasks:\n", uxCurrentNumberOfTasks
  printf "pending ready"
  printtasklist &xPendingReadyList
  printf "suspended"
  printtasklist &xSuspendedTaskList
  printf "delayedW"
  printtasklist pxDelayedTaskList
  printf "delayedO"
  printtasklist pxOverflowDelayedTaskList
  set $prio = 0
  set $maxprio = sizeof(pxReadyTasksLists) / sizeof(pxReadyTasksLists[0])
  while ($prio < $maxprio)
    printf " ready at prio"
    printf "%d", $prio
    printtasklist &pxReadyTasksLists[$prio]
    set $prio = $prio + 1  
  end
end

define savestate
  set $svpc = $pc
  set $svsp = $sp
  set $svlr = $lr
end

define restorestate
  set $pc = $svpc
  set $sp = $svsp
  set $lr = $svlr
end

define cm3bttask
       # arg0: task handle (pointer to tskTCB)
  savestate
  set $ptsk = (tskTCB*)$arg0
  set $tskstk = (uint32_t*)$ptsk->pxTopOfStack
  set $lr = $tskstk[13]
  set $pc = $tskstk[14]
  set $sp= $tskstk + 16
  bt
end

我的想法是我使用printtasks来获取任务控制块列表,如果我感兴趣的任务在打印的GDB历史记录中有控制块指针,则使用cm3bttask $26行26美元。我可以在printtasks的输出上看到它。