【问题标题】:Get all .text (code) section symbols / symbol of local lambda object call operator in gdb?获取gdb中本地lambda对象调用运算符的所有.text(代码)部分符号/符号?
【发布时间】:2022-01-16 16:35:57
【问题描述】:

背景:我正在尝试简化对问题c++ - Calling a lambda function in GDB - Stack Overflow 的回答。

考虑这个简单的程序

int main(){
    auto a=[&](int x){return x+1;};
}

编译后(例如到a.out),我可以看到

$ nm --demangle a.out  |grep lambda
000000000000113a t main::{lambda(int)#1}::operator()(int) const

$ nm  a.out  |grep 113a
000000000000113a t _ZZ4mainENKUliE_clEi

所以在文本(代码)部分中有一个符号 _ZZ4mainENKUliE_clEi 用于 lambda operator() 方法。

给定确切的名称,我可以在 gdb 中打印它的值,并且 tab-completion 也列出了符号:

$ gdb -q ./a.out

(gdb) print _ZZ4mainENKUliE_clEi
$1 = {int (const struct {...} * const, int)} 0x55555555513a <operator()(int) const>

(gdb) print 'main::{lambda(int)#1}::operator()(int) const'
$2 = {int (const struct {...} * const, int)} 0x55555555513a <operator()(int) const>

但是如何在不使用外部可执行文件nm(在 gdb 本身内部)的情况下找到符号? 首选使用 Python API 的答案。


尝试失败

正如c - Ask GDB to list all functions in a program - Stack Overflow中所建议的:

(gdb) info functions .*lambda.*
All functions matching regular expression ".*lambda.*":

File /build/gcc/src/gcc/libstdc++-v3/src/c++11/compatibility-thread-c++0x.cc:
        void std::once_flag::_Prepare_execution::_Prepare_execution<std::call_once<void (std::thread::*)(), std::
thread*>(std::once_flag&, void (std::thread::*&&)(), std::thread*&&)::{lambda()#1}>(void (std::thread::*&)())::{l
ambda()#1}::_FUN();

这不是我想要的,并且

(gdb) info functions .*ZZ4.*
All functions matching regular expression ".*ZZ4.*":

根本不匹配。

还尝试了Debugging with GDB - Examining the Symbol Table中的其他东西, maintenance print symbols 也没有。

Symbols In Python (Debugging with GDB)gdb.lookup_global_symbol("_ZZ4mainENKUliE_clEi")gdb.lookup_static_symbol("_ZZ4mainENKUliE_clEi") 都返回 None。

gdb 中的file ./a.out 没有帮助(GDB does not see symbols 建议)

【问题讨论】:

标签: c++ gdb


【解决方案1】:

此方案通过解析info files的文本输出找到.text部分的地址,然后通过解析info symbol gdb命令的输出找到每个地址对应的符号。

因为它会解析文本输出,在某些特殊情况下可能会中断。如果有人有任何更好的解决方案/改进,请提出/发布新的答案。

我查看了https://sourceware.org/gdb/current/onlinedocs/gdb/Progspaces-In-Python.html#Progspaces-In-Python/https://sourceware.org/gdb/current/onlinedocs/gdb/Objfiles-In-Python.html,但没有找到。

我不能使用block_for_pc,在this comment 中有解释。


运行 Python 代码。结果被收集到列表symbols中。

阅读代码中的 cmets 了解更多详细信息。

# (setup measure time)
import time
start=time.time()

# step 1. Find the limit of `.text`. Store in (a, b).
import re
[[a, b]]=[
        (int(match[1], 16), int(match[2], 16))
        for line in gdb.execute("info files", to_string=True).splitlines()
        for match in [re.fullmatch(r"\s*(0x[0-9a-f]+) - (0x[0-9a-f]+) is \.text", line)]
        if match
        ]

# Step 2. Iterate through symbols.
symbols=[]
mismatch=0
i=b-1
while i>=a:
    line=gdb.execute("info symbol "+hex(i), to_string=True)
    if line=='No symbol matches '+hex(i)+'.\n':
        # There's no symbol here. Unfortunately I can't find any way to quickly skip through it.
        i-=1
        mismatch+=1
        continue
    # Determine the symbol and the offset.
    match=re.fullmatch(r"(.+) \+ (\d+) in section \.text of .*\n?", line)
    if match:
        symbol=match[1]
        offset=int(match[2])
    else:
        match=re.fullmatch(r"(.+) in section \.text of .*\n?", line)
        symbol=match[1]
        offset=0
    # collect the symbol into the list.
    i-=offset
    symbols.append((symbol, hex(i)))
    i-=1

# (report time taken)
print(time.time()-start, len(symbols), mismatch)

对于相当大的可执行文件,nm 需要 0.042 秒,而脚本需要 0.778 秒并报告 5769 个符号和 44171 个未命中。 (大部分时间都是失误)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-09
    • 1970-01-01
    • 1970-01-01
    • 2011-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多