使用 gdb 的 Python 回溯不同的 OS 线程,当 gdb 不是 OS-aware 时
Using gdb's Python to backtrace different OS threads, when gdb is not OS-aware
我仍在学习如何在 gdb 中使用 python 调试 C(在我的例子中是 arm-none-eabi-gdb)。我正在尝试使用此工具在 ARM Cortex-M 上获取实时 OS 运行 的线程信息。读取一些 OS 结构,我可以访问 OS 的 the 线程控制块。我知道每个线程的 PC 和 SP。我如何使用 gdb 的 Python 来转储线程的回溯。给定 PC 和 SP 时,是否有通用的 API 可以遍历堆栈?
我已阅读 https://sourceware.org/gdb/current/onlinedocs/gdb/Unwinding-Frames-in-Python.html#Unwinding-Frames-in-Python,我觉得可能有一种方法可以实现,但我需要一些帮助。
此外,如果可能的话,我可以让 gdb 知道 OS 的不同线程吗?这个link:
https://sourceware.org/gdb/current/onlinedocs/gdb/Threads-In-Python.html#Threads-In-Python 涉及线程但依赖于 OS 信息。根据我对来自各自控制块的不同 OS 线程的了解,这些是否会过载?
谢谢!
经过更多阅读并尝试利用我多年来积累的旧调试器知识,我设法使它工作。它缺乏优化,但就目前而言,我非常高兴。这可以被认为是一个穷人的调试器,它利用 GDB 的 Python 支持来跟踪系统中的活动线程。我认为它是通用的,但实现针对的是 RTX(Keil 的 OS)。它适用于 Cortex-M0。它可能需要一些调整以适应其他操作系统或不同的内核。
主要思想:
- 使用 OS 结构来识别线程控制块所在的位置。
- 从线程控制块中确定不同线程堆栈的位置。
- 从堆栈中读取所有重要的寄存器; SP、LR 和 PC
- 为当前 运行 线程保存相同的寄存器。
- 遍历不同线程,将重要寄存器更改为与线程匹配的寄存器,然后打印回溯。
- 享受穷人的 OS 感知调试器。
脚本可以在这里找到:
https://gitlab.com/hesham/gdb-rtx-thread-backtrce/blob/master/rtx-threads-bt.py
探索 GDB Python 扩展功能的一个很好的练习!
对于 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 行。我可以在 printtasks 的输出中看到这一点。
我仍在学习如何在 gdb 中使用 python 调试 C(在我的例子中是 arm-none-eabi-gdb)。我正在尝试使用此工具在 ARM Cortex-M 上获取实时 OS 运行 的线程信息。读取一些 OS 结构,我可以访问 OS 的 the 线程控制块。我知道每个线程的 PC 和 SP。我如何使用 gdb 的 Python 来转储线程的回溯。给定 PC 和 SP 时,是否有通用的 API 可以遍历堆栈?
我已阅读 https://sourceware.org/gdb/current/onlinedocs/gdb/Unwinding-Frames-in-Python.html#Unwinding-Frames-in-Python,我觉得可能有一种方法可以实现,但我需要一些帮助。
此外,如果可能的话,我可以让 gdb 知道 OS 的不同线程吗?这个link: https://sourceware.org/gdb/current/onlinedocs/gdb/Threads-In-Python.html#Threads-In-Python 涉及线程但依赖于 OS 信息。根据我对来自各自控制块的不同 OS 线程的了解,这些是否会过载?
谢谢!
经过更多阅读并尝试利用我多年来积累的旧调试器知识,我设法使它工作。它缺乏优化,但就目前而言,我非常高兴。这可以被认为是一个穷人的调试器,它利用 GDB 的 Python 支持来跟踪系统中的活动线程。我认为它是通用的,但实现针对的是 RTX(Keil 的 OS)。它适用于 Cortex-M0。它可能需要一些调整以适应其他操作系统或不同的内核。
主要思想:
- 使用 OS 结构来识别线程控制块所在的位置。
- 从线程控制块中确定不同线程堆栈的位置。
- 从堆栈中读取所有重要的寄存器; SP、LR 和 PC
- 为当前 运行 线程保存相同的寄存器。
- 遍历不同线程,将重要寄存器更改为与线程匹配的寄存器,然后打印回溯。
- 享受穷人的 OS 感知调试器。
脚本可以在这里找到:
https://gitlab.com/hesham/gdb-rtx-thread-backtrce/blob/master/rtx-threads-bt.py
探索 GDB Python 扩展功能的一个很好的练习!
对于 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 行。我可以在 printtasks 的输出中看到这一点。