无法使用GDB进入string.h函数

无法在GDB 7.5中单步执行string.h 。 这是一个简单的示例程序:

源代码:

 #include  #include  int main() { char str1[20]; strcpy(str1, "STEP INTO ME\n"); printf(str1); } 

编译: ~$ gcc -g foo.c

调用: ~$ gdb -q ./a.out

GDB:

 (gdb) break 5 Breakpoint 1 at 0x8048471: file foo.c, line 6. (gdb) break strcpy Function "strcpy" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 2 (strcpy) pending. (gdb) run Starting program: /home/user/a.out Breakpoint 1, main () at foo.c:6 6 strcpy(str_a, "Hello, world!\n"); (gdb) step 7 printf(str_a); 

我不应该在字符串库中吗? 相反,它继续printf()。


编辑:

斯科特的建议“有效”,但不是以预期的方式。

 Breakpoint 1, main () at foo.c:6 6 strcpy(str_a, "Hello, world!\n"); (gdb) ir $eip eip 0x80484a1 0x80484a1  (gdb) step Breakpoint 2, __strcpy_ssse3 () at ../sysdeps/i386/i686/multiarch/strcpy-ssse3.S:78 78 ../sysdeps/i386/i686/multiarch/strcpy-ssse3.S: No such file or directory. (gdb) ir $eip eip 0xb7e9c820 0xb7e9c820  

我对78中的目录感到惊讶…期望类似于:/ /lib/.../cmov/libc.so.6 。 声称没有这样的文件或目录。

使用gcc -fno-builtin -g foo.c编译代码,gdb step命令将起作用。 (参见-fno-builtin文档 )。 否则,小的strcpy()memcpy()调用通常会转换为开放式编码数据移动指令,例如在x86-64上:

 4 int main() { 0x000000000040052c <+0>: push %rbp 0x000000000040052d <+1>: mov %rsp,%rbp 0x0000000000400530 <+4>: sub $0x20,%rsp 5 char str1[20]; 6 strcpy(str1, "STEP INTO ME\n"); 0x0000000000400534 <+8>: lea -0x20(%rbp),%rax 0x0000000000400538 <+12>: movl $0x50455453,(%rax) 0x000000000040053e <+18>: movl $0x544e4920,0x4(%rax) 0x0000000000400545 <+25>: movl $0x454d204f,0x8(%rax) 0x000000000040054c <+32>: movw $0xa,0xc(%rax) 7 printf(str1); 0x0000000000400552 <+38>: lea -0x20(%rbp),%rax 0x0000000000400556 <+42>: mov %rax,%rdi 0x0000000000400559 <+45>: mov $0x0,%eax 0x000000000040055e <+50>: callq 0x400410  8 } 0x0000000000400563 <+55>: leaveq 0x0000000000400564 <+56>: retq 

您可以看到strpcy()调用被编译为多个MOV指令。

gcc -fno-builtin将相同的程序编译成:

 4 int main() { 0x000000000040057c <+0>: push %rbp 0x000000000040057d <+1>: mov %rsp,%rbp 0x0000000000400580 <+4>: sub $0x20,%rsp 5 char str1[20]; 6 strcpy(str1, "STEP INTO ME\n"); 0x0000000000400584 <+8>: lea -0x20(%rbp),%rax 0x0000000000400588 <+12>: mov $0x400660,%esi 0x000000000040058d <+17>: mov %rax,%rdi 0x0000000000400590 <+20>: callq 0x400450  7 printf(str1); 0x0000000000400595 <+25>: lea -0x20(%rbp),%rax 0x0000000000400599 <+29>: mov %rax,%rdi 0x000000000040059c <+32>: mov $0x0,%eax 0x00000000004005a1 <+37>: callq 0x400460  8 } 0x00000000004005a6 <+42>: leaveq 0x00000000004005a7 <+43>: retq 

你可以看到对的调用。

假设你想进入strcpy()来研究它的实现,你需要安装libc.so的调试信息。 不幸的是,获取调试信息的方式因Linux发行版而异。 在Fedora上,它就像debuginfo-install glibc一样简单。 它需要在Ubuntu和Debian上采取更多步骤。 此RPM DPKG Rosetta Stone页面包含指向Fedora,Ubuntu和Debian(搜索debuginfo )的说明。

因为您使用的是Ubuntu 12.10并且实际上想要查看strcpy()程序集源代码:

 $ sudo apt-get install libc6-dbg $ sudo apt-get source libc6-dev $ gdb ./a.out (gdb) directory eglibc-2.15/sysdeps Source directories searched: /home/scottt/eglibc-2.15/sysdeps:$cdir:$cwd (gdb) break strcpy Breakpoint 1 at 0x400450 (gdb) run Starting program: /home/scottt/a.out Breakpoint 1, __strcpy_sse2 () at ../sysdeps/x86_64/multiarch/../strcpy.S:32 32 movq %rsi, %rcx /* Source register. */ 

您试图为字符串库中定义的函数设置断点,该函数通常是standard C library - libc.so

并且正如gdb告诉你:

 (gdb) break strcpy Function "strcpy" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 2 (strcpy) pending. 

该库尚未加载。

但真正的问题是,即使加载了库,如果库(即libc.so中没有调试符号,您也无法使用gdb逐步执行库中的代码。

您可以启用详细模式以查看gdb能够加载哪些符号:

 (gdb) b main Breakpoint 1 at 0x400914: file test.cpp, line 7. (gdb) set verbose on (gdb) run Starting program: /home/agururaghave/.scratch/gdb-test/test Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done. Loaded symbols for /lib64/ld-linux-x86-64.so.2 Reading symbols from system-supplied DSO at 0x7ffff7ffb000...(no debugging symbols found)...done. Reading symbols from /usr/lib64/libstdc++.so.6...(no debugging symbols found)...done. Registering libstdc++-v6 pretty-printer for /usr/lib64/libstdc++.so.6 ... Loaded symbols for /usr/lib64/libstdc++.so.6 Reading symbols from /lib64/libm.so.6...(no debugging symbols found)...done. Loaded symbols for /lib64/libm.so.6 Reading symbols from /lib64/libgcc_s.so.1...(no debugging symbols found)...done. Loaded symbols for /lib64/libgcc_s.so.1 Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done. Loaded symbols for /lib64/libc.so.6 Breakpoint 1, main () at test.cpp:7 7 bool result = myObj1 < myObj2; 

例如,这一行告诉你它是否能够获取libc.so的符号:

 Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done. 

然后,您可以使用show debug-file-directory找出调试符号的拾取位置:

 (gdb) show debug-file-directory The directory where separate debug symbols are searched for is "/usr/lib/debug". 

如您所见/usr/lib/debug这里不包含带调试符号的完整.so。 相反,它只有调试信息,没有程序用来执行的实际libc.so的任何.text.data部分。

安装库的调试信息的解决方案将是特定于发行版的。

我认为这个libc6-dbg在基于debian的发行版上被称为libc6-dbg 。 在我的openSUSE机器上,它似乎被称为glibc-debuginfo

BTW,+1关于scottt建议使用-fno-builtin的建议,以便gcc不会将其内置方法用于strcpy等函数以及定义为C标准一部分的其他标准函数。

您的C库可能没有任何符号。 尝试stepi ,但要准备好只看到assembly说明。