【问题标题】:Line number of the caller of a preloaded library function预加载库函数调用者的行号
【发布时间】:2021-05-23 23:10:32
【问题描述】:

假设我有一个使用标准 C 库中的 rand 函数的程序 (program.c)。

1 #include <stdlib.h>
2 int main(){
3     int rand_number = rand();
4 }

我还创建了一个共享库 (intercept.c),用于更改标准库中 rand 函数的行为(只需将 +1 加到结果中)。

int rand(void){
    int (*rand_func)();
    rand_func = dlsym(RTLD_NEXT, "rand");
    int result = (*rand_func)();
    return result + 1;
}

我运行程序

LD_PRELOAD=./intercept.so ./program

有没有什么方法可以在不修改program.c的源码的情况下获取行号(第3行)和调用者函数的名字(main)?

【问题讨论】:

  • C 标准没有为此提供任何便利。如果程序是用调试信息编译的,就有可能从中得到这些信息。这有点复杂,不太可能值得付出努力。
  • 在使用rand()之前,使用一些东西来为随机数生成器做种子,类似于:#include &lt;time.h&gt;srand( (unsigned)time( NULL) );
  • @user3629249 功能齐全的 rand 函数在这种情况下并不重要。我只是举个例子。

标签: c shared-libraries ld dlsym


【解决方案1】:

它不是立即的,但您可以使用backtrace() 来获取调用堆栈中的每一帧。 然后调用外部命令eu-addr2line -f -C -s --pretty-print -p your_pid the_previous_frames...(使用popen()pipe()/fork()/dup2()/exec()...)并解析其输出将提供您需要的信息 (如果使用-g 编译)。

【讨论】:

  • 我对 program.c 没有任何控制权。所以,不知道是不是用-g编译的。
  • @M.Soyturk 并且使用从program.c 获得的二进制文件按原样,您是否尝试过这种方法?当然backtrace()必须在你的代码中使用(intercept.c)如果调试信息偶然出现在原始代码中,eu-addr2line可能会给你一些东西程序。顺便说一句,为您无法控制的代码获取调用堆栈和行号有什么意义?
  • 我做了,但我无法获得行号。我正在尝试开发一个集体通信分析工具,我认为显示行号和堆栈跟踪将是提高生产力的一个很好的补充。感谢您的回答。
【解决方案2】:

关于:

有没有什么方法可以在不修改program.c的源代码的情况下获取行号(第3行)和调用者函数名(main)?

使用-ggdb3 选项编译程序,然后在要停止程序的位置设置断点。然后使用回溯命令bt。这将显示函数名称、行号等

【讨论】:

  • 我对 program.c 没有任何控制权。所以,我不知道编译 program.c 时使用了哪些标志
【解决方案3】:

另一种(Linux 特定的)方法是使用GCC 使用-g(可能还有-O)编译所有内容,并使用Ian Taylor 出色的libbacktrace

该库解析DWARF 调试信息并知道行号。

您需要几个小时才能理解libbacktrace(仔细阅读头文件)。我在RefPerSys使用它

【讨论】:

  • 我无法控制 program.c 的编译。因此,我不知道在编译 program.c 时使用了哪些标志。有没有其他选择?
  • 与提供program.o的人讨论。
  • 不幸的是,我现在还没有那么奢侈。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-14
  • 1970-01-01
  • 2021-10-18
  • 2019-02-18
  • 1970-01-01
相关资源
最近更新 更多