2

我的程序有 100 个线程,其中大部分是空闲的,并且在空闲时共享一个定义明确的回溯。大多数时候,我只对非空闲的线程感兴趣,因此没有“通用”回溯。我认为使用 gdb 脚本将是一个很好的方法。

define backtraces
    thread apply all bt
end

该脚本将简单地打印所有回溯。有没有办法将此输出存储到一个变量中,然后我可以只处理、修剪和显示相关的回溯?

我天真地尝试过:

define backtraces
    set $bts = thread apply all bt
    // do whatever processing here
end

但正如预期的那样失败了:

当前上下文中没有符号“线程”。

有一个更好的方法吗?或者关于如何在 gdb 中为脚本供电的好教程?

4

3 回答 3

2

有一个更好的方法吗?

您需要使用Python 脚本来实现您想要的结果。

过滤回溯可能是一个好的开始。

于 2013-05-09T18:50:12.150 回答
2

使用 Employed Russian 的答案中的链接,我能够得到一些工作。这是为了后代,因为它完全不明显。

import gdb

# This loops through all the Thread objects in the process
for thread in gdb.selected_inferior().threads():

    # This is equivalent to 'thread X'
    thread.switch()       

    print "Thread %s" % thread.num

    # Just execute a raw gdb command
    gdb.execute('bt')

    framesNames = []
    f = gdb.newest_frame()
    while f is not None:
        framesNames.append(gdb.Frame.name(f))
        f = gdb.Frame.older(f)

    # do something with the name of each frame

如果这是在一个名为 的文件中traces.py,那么您可以从 gdb 执行 python:

source traces.py

还有其他方法可以调用这个 python 脚本。

于 2013-05-09T23:44:42.020 回答
0

这是我基于 JaredC 得出的结论:

import gdb

class FilteredThreadBacktraceCommand(gdb.Command):
    """
    Implements a command that allows printing the backtrace only for threads
    that do not have given frames.

    The class must be instantiated with a list of the frames to ignore. If the
    stack for a thread has any of those frames then the stack for that thread
    will not be printed (a visual dot will be printed to show a thread was just
    ignored and provide a notion of progress).
    """
    def __init__(self, ignored_frames):
        super (FilteredThreadBacktraceCommand, self).__init__ ("fbt", gdb.COMMAND_STACK)
        self.ignored_frames = ignored_frames

    def invoke(self, arg, from_tty):
        args = gdb.string_to_argv(arg)
        if len(args) != 0:
            gdb.write("ERROR: invalid number of arguments.\n")
            return

        # This loops through all the Thread objects in the process
        for thread in gdb.selected_inferior().threads():

            # This is equivalent to 'thread X'
            thread.switch()

            f = gdb.newest_frame()
            frames = []
            invalid_thread = False
            while f is not None:
                if any(ignored_frame in f.name() for ignored_frame in self.ignored_frames):
                        invalid_thread = True
                        break
                frames.append(f)
                f = gdb.Frame.older(f)

            if invalid_thread:
                # Visual effect as iterating frames might take a while
                sys.stdout.write('.')
                sys.stdout.flush()
                continue

            print "\nThread %s:" % thread.num
            for i in range(len(frames)):
                f = frames[i]
                funcInfo = f.function()
                printStr = "#{} in {}".format(i, f.name())
                if f.function():
                    printStr += " at {}:{}".format(funcInfo.symtab.filename, funcInfo.line)
                else:
                    printStr += " at (???)"
                print(printStr)

 FilteredThreadBacktraceCommand(["os::PlatformEvent::park"])

您可以在创建时向班级提供要忽略的框架。也可以使其通用,以便为要注册的命令提供名称,以便您可以使用具有不同过滤的不同命令。

于 2020-04-24T19:07:51.540 回答