【问题标题】:Getting stacktrace of all threads without attaching GDB在不附加 GDB 的情况下获取所有线程的堆栈跟踪
【发布时间】:2012-09-05 20:56:16
【问题描述】:

有没有办法在不附加 GDB 的情况下打印所有线程的堆栈跟踪?

或者是否有一个命令可以用作 gdb 批处理模式来打印所有线程的堆栈跟踪?

【问题讨论】:

  • 任何答案对您有用吗?你能得到堆栈跟踪吗?

标签: c++ linux gdb


【解决方案1】:

GDB 中有一个thread apply all 命令:

(gdb) thread apply all bt
Thread 12 (Thread 0x7f7fe2116700 (LWP 5466)):
#0  sem_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:86
#1  0x0000000000425358 in ?? ()
...
Thread 1 (Thread 0x7f7feabc27c0 (LWP 5465)):
#0  0x00007f7fe76c5203 in select () at ../sysdeps/unix/syscall-template.S:82

遗憾的是,GDB 似乎无法从管道读取命令,因此要以批处理模式运行命令,必须使用临时文件:

$ gdbbt() {
  tmp=$(tempfile)
  echo thread apply all bt >"$tmp"
  gdb -batch -nx -q -x "$tmp" -p "$1"
  rm -f "$tmp"
}
$ gdbbt $(pidof $SHELL)

那么你将只能“暂时”附加gdb,然后分离。

【讨论】:

【解决方案2】:

elfutils 在其他实用程序中包括eu-stack

eu-stack
    Print a stack for each thread in a process or core file.

它比 gdb 或 pstack 快,后者只是 gdb 的一个 shell 脚本包装器。要打印堆栈跟踪,请运行eu-stack,如下所示:

$ eu-stack -p 2209
PID 2209 - process
TID 2209:
#0  0x00007f53476b667b __poll
#1  0x00007f5348f98e99 g_main_context_iterate.isra.23
#2  0x00007f5348f99232 g_main_loop_run
#3  0x000055e604b1e56a main
#4  0x00007f53475cc00a __libc_start_main
#5  0x000055e604b1e76a _start
TID 2223:
#0  0x00007f53476b667b __poll
#1  0x00007f5348f98e99 g_main_context_iterate.isra.23
#2  0x00007f5348f98fac g_main_context_iteration
#3  0x00007f5348f98ff1 glib_worker_main
#4  0x00007f5348fc0486 g_thread_proxy
#5  0x00007f534813761b start_thread
#6  0x00007f53476c2c2f __clone
TID 2224:
#0  0x00007f53476b667b __poll
#1  0x00007f5348f98e99 g_main_context_iterate.isra.23
#2  0x00007f5348f99232 g_main_loop_run
#3  0x00007f5349581b56 gdbus_shared_thread_func
#4  0x00007f5348fc0486 g_thread_proxy
#5  0x00007f534813761b start_thread
#6  0x00007f53476c2c2f __clone

【讨论】:

  • 在现代 64 位 Linux 上,这应该被标记为正确答案!
  • 我想不出办法让它显示行号?
  • 尝试使用-s 选项运行:eu-stack -s -p <pid>。它至少显示了一些可用的调试信息的行号。
【解决方案3】:

以下脚本适用于我在 linux 上 请注意,它首先找到可执行文件的目录并更改到该目录(因为可执行文件可以通过使用 -Wl,-rpath,$dir 在链接期间指定具有相对路径的共享库,并且您希望 gdb 找到符号对于这些用于堆栈跟踪的共享库)。 它还假设系统上存在 gdb。

#!/bin/bash

pid=$1

EXE=`readlink -f /proc/$pid/exe`

DIR=`dirname $EXE`

cd $DIR

gdb $EXE --batch -ex "attach $pid" -ex "thread apply all bt"

【讨论】:

    【解决方案4】:

    我一直在用这个:

    pidof program | xargs -n1 sudo gdb --batch -ex "thread apply all bt" -p
    

    【讨论】:

      【解决方案5】:

      与 linux 一样,所有线程本质上都是轻量级进程,它们获得单独的 LWP PID。您可以使用基于pstop 的脚本或echoing w in w 转储这些状态。这将为您提供/var/log/messages 中线程的I/O 状态。

      虽然这不会给你完整的堆栈跟踪。但它是定期调试线程状态的好方法。

      您还可以通过查看/proc/sched_debug 来了解当前调度程序的状态,以查看哪些任务正在被调度等等。

      【讨论】:

        【解决方案6】:

        pstack?

        用法:

        pstack <pid>
        

        来自手册页:

        pstack - print a stack trace of a running process
        ...
        If the process is part of a thread group, then pstack will print out a stack trace for each of the threads in the group.
        

        【讨论】:

        • 确实不行(而且不像 GDB 那样普遍):“pstack 目前只能在 Linux 上工作,只能在运行 32 位 ELF 二进制文件的 x86 机器上工作(不支持 64 位)”跨度>
        • @fork0: “真的不行”——你能说得更具体点吗?此外,OP 将问题标记为“Linux”,因此 pstack 是相关的。
        • @fork0: "64 位不支持" -- 来源?我有一台 64 位机器(Linux 2.6.18)并且 pstack 在那里。
        • 关于 Debian 测试的 pstack 手册页。它在我的 64bit/3.5.3 机器上没有显示任何有用的东西(一些随机线程的 ip,没有别的)
        • 在 Fedora 上 pstack 是一个方便的 shell 脚本包装器,它在 gdb 中执行 thread apply all。所以这个答案和fork0的答案基本一致。
        猜你喜欢
        • 1970-01-01
        • 2016-05-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-28
        • 1970-01-01
        • 2011-06-15
        相关资源
        最近更新 更多