Debugging 在C程序中调用哪个函数?
当我调用库函数时,我试图弄清楚调用的是哪个确切的函数(从哪个包含文件) 所以我有这个节目,Debugging 在C程序中调用哪个函数?,debugging,gcc,Debugging,Gcc,当我调用库函数时,我试图弄清楚调用的是哪个确切的函数(从哪个包含文件) 所以我有这个节目, #include <stdio.h> #include <math.h> int twice(int input) { int output; output = input * 2; return output; } int main(int argc, char **argv) { printf("Hello World and %f\n", sin(1));
#include <stdio.h>
#include <math.h>
int twice(int input) {
int output;
output = input * 2;
return output;
}
int main(int argc, char **argv) {
printf("Hello World and %f\n", sin(1));
printf("Output: %d\n", twice(3));
printf("Here is the end of the program... %d\n", 3);
}
然后转储程序集代码
objdump --source a.out > test.objdump
在test.objdump中,我看到如下行
int main(int argc, char **argv) {
400528: 55 push %rbp
400529: 48 89 e5 mov %rsp,%rbp
40052c: 48 83 ec 10 sub $0x10,%rsp
400530: 89 7d fc mov %edi,-0x4(%rbp)
400533: 48 89 75 f0 mov %rsi,-0x10(%rbp)
printf("Hello World and %f\n", sin(1));
400537: f2 0f 10 05 91 01 00 movsd 0x191(%rip),%xmm0 #4006d0<__dso_handle+0x50>
40053e: 00
40053f: bf 88 06 40 00 mov $0x400688,%edi
400544: b8 01 00 00 00 mov $0x1,%eax
400549: e8 c2 fe ff ff callq 400410 <printf@plt>
printf("Output: %d\n", twice(3));
40054e: bf 03 00 00 00 mov $0x3,%edi
400553: e8 bc ff ff ff callq 400514 <_Z5twicei>
400558: 89 c6 mov %eax,%esi
40055a: bf 9c 06 40 00 mov $0x40069c,%edi
40055f: b8 00 00 00 00 mov $0x0,%eax
400564: e8 a7 fe ff ff callq 400410 <printf@plt>
printf("Here is the end of the program... %d\n", 3);
400569: be 03 00 00 00 mov $0x3,%esi
40056e: bf a8 06 40 00 mov $0x4006a8,%edi
400573: b8 00 00 00 00 mov $0x0,%eax
400578: e8 93 fe ff ff callq 400410 <printf@plt>
40057d: b8 00 00 00 00 mov $0x0,%eax
}
(我也尝试了不带0x的400410),我得到了
这并没有给出printf函数的位置。有人能指出我的过程中的错误吗。是否有一些我没有通过的g++选项
非常感谢你的帮助。谢谢大家! 您正在将代码编译成目标代码,然后从目标代码中转储汇编代码。此时,链接器尚未将代码链接在一起,因此
printf
只是过程链接表中的一个符号。只有当程序已链接时,才会显示该定义
编辑:再次查看编译器选项时,我看到可执行文件正在链接在一起。如果内置了调试符号,则可能需要指定希望与addr2line
一起使用的节
至于使用
printf
,我相信addr2line
只能找到可执行文件本地的函数定义,而不能找到外部库定义的函数。从test.cpp
的角度来看,printf
存在于其自身之外,并且不能有一行定义它,因为它将仅由被链接的库记录。如果该库(在本例中为glibc)未编译为调试版本,则无法知道它是在哪个文件和行号上定义的。您正在将代码编译为目标代码,然后从目标代码中转储程序集代码。此时,链接器尚未将代码链接在一起,因此printf
只是过程链接表中的一个符号。只有当程序已链接时,才会显示该定义
编辑:再次查看编译器选项时,我看到可执行文件正在链接在一起。如果内置了调试符号,则可能需要指定希望与addr2line
一起使用的节
至于使用
printf
,我相信addr2line
只能找到可执行文件本地的函数定义,而不能找到外部库定义的函数。从test.cpp
的角度来看,printf
存在于其自身之外,并且不能有一行定义它,因为它将仅由被链接的库记录。如果该库(在这种情况下,GLUBC)没有编译为调试生成,则无法知道它定义了什么文件和行号。 < P>如果您只想找到“代码> Prtff())/<代码>(在C或C++中,您使用的问题不清楚),您可以这样做:
g++ -E test.cpp | less
其中-E
表示:
-只进行预处理;不要编译、组装或链接
然后向前/搜索printf
以查找声明(必须在使用前声明,因此必须是第一次命中)。然后向后搜索?对于^#
,查找包含此内容的文件
不需要编译、链接或对象转储
我还建议检查和,这两种方法都可以用于高效地在大型源代码树中查找符号
在进一步评论之后 通过编译和链接代码来查找定义可能并不总是可能的。您已经在
printf()
中看到了这一点,它不是您构建的,可能不存在于您的计算机上。还要考虑用其他语言编写的定义,或者在运行时要解决的定义。
而且可能是你最好的方法
祝你好运如果你只想找到<代码> Prtff()/Cuth>的声明(在C或C++中,你使用的问题不清楚),你可以这样做:
g++ -E test.cpp | less
其中-E
表示:
-只进行预处理;不要编译、组装或链接
然后向前/搜索printf
以查找声明(必须在使用前声明,因此必须是第一次命中)。然后向后搜索?对于^#
,查找包含此内容的文件
不需要编译、链接或对象转储
我还建议检查和,这两种方法都可以用于高效地在大型源代码树中查找符号
在进一步评论之后 通过编译和链接代码来查找定义可能并不总是可能的。您已经在
printf()
中看到了这一点,它不是您构建的,可能不存在于您的计算机上。还要考虑用其他语言编写的定义,或者在运行时要解决的定义。
而且可能是你最好的方法
祝你好运 addr2line只能找到给定可执行文件中包含的定义,因此它不会对
printf
给出答案做任何说明:
rafal:~/test$ addr2line -f 0x400448
??
??:0
rafal:~/test$ addr2line -f 0x400554
_Z5twicei
/home/rafal/test/c.cpp:4
要在共享库中查找有关函数的信息,也可以使用gdb
gdb a.out
(gdb) info symbol 0x400448
printf@plt in section .plt of /home/rafal/test/a.out
(gdb) info symbol 0x400554
twice(int) in section .text of /home/rafal/test/a.out
addr2line只能找到给定可执行文件中包含的定义,因此它不会说任何关于
printf
给出答案的内容:
rafal:~/test$ addr2line -f 0x400448
??
??:0
rafal:~/test$ addr2line -f 0x400554
_Z5twicei
/home/rafal/test/c.cpp:4
要在共享库中查找有关函数的信息,也可以使用gdb
gdb a.out
(gdb) info symbol 0x400448
printf@plt in section .plt of /home/rafal/test/a.out
(gdb) info symbol 0x400554
twice(int) in section .text of /home/rafal/test/a.out
试试这个:
g++ -g -static test.cpp
这会消除你所有的困惑
没有针对共享库的静态gcc链接。这意味着printf之类的函数根本不在程序中,而是在运行时从/lib加载的。这更节省空间,但可能会稍微慢一点(尽管您的系统作为一个整体将运行得更快)。您可以使用GDB检查正在运行的程序的内容,但要注意,共享代码意味着有很多令人困惑的gubbins,比如GOTs和PLTs等
编译为静态二进制文件会将所有