我正在尝试调试为什么ngspice在运行模拟时将烦人的换行符打印到stderr。我试图在可追溯到 1993 年的 2400 个源文件之一中找到它,但这并不像听起来那么容易!然而,这确实意味着我有一个嵌入了所有调试信息的二进制文件。
我的第一个想法是strace可以帮助我找到我认为有问题的调用并将其追溯到源代码。例如,我很确定这是有问题的系统调用:
brk(0x55d1a84e9000) = 0x55d1a84e9000
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, {tv_sec=0, tv_nsec=61462905}) = 0
>> write(2, "\n", 1) = 1
getrusage(RUSAGE_SELF, {ru_utime={tv_sec=0, tv_usec=26269}, ru_stime={tv_sec=0, tv_usec=35243}, ...}) = 0
openat(AT_FDCWD, "/proc/self/statm", O_RDONLY) = 3
Run Code Online (Sandbox Code Playgroud)
我曾希望,如果我跟踪一个具有调试信息的可执行文件,strace 会显示源代码中的位置,但这并没有自动发生,而且手册有点压倒性。
我在手册中找到了一个名为Tracing的部分,但找不到任何具体内容。
是否可以使用strace,如果可以:如何?如果没有,您还有其他建议吗?
事后看来很明显,但一个非常有用的标志是-k. 从手册页:
-k 在每次系统调用后打印被跟踪进程的执行堆栈跟踪。
这需要一个带有调试信息的二进制文件,它会变得非常嘈杂,但是结合一个简单的过滤器(-e write在这种情况下),您最终会得到如下所示的内容:
write(2, "\n", 1
) = 1
> /lib/x86_64-linux-gnu/libc-2.28.so(__write+0x14) [0xea504]
> /lib/x86_64-linux-gnu/libc-2.28.so(_IO_file_write+0x2d) [0x7b3bd]
> /lib/x86_64-linux-gnu/libc-2.28.so(_IO_file_setbuf+0xef) [0x7a75f]
> /lib/x86_64-linux-gnu/libc-2.28.so(_IO_do_write+0x19) [0x7c509]
> /lib/x86_64-linux-gnu/libc-2.28.so(_IO_file_overflow+0x103) [0x7c8f3]
> /home/pipe/src/ngspice/debug/src/ngspice(OUTendPlot+0x1ae) [0xd7643]
> /home/pipe/src/ngspice/debug/src/ngspice(DCop+0x167) [0x4cd788]
> /home/pipe/src/ngspice/debug/src/ngspice(CKTdoJob+0x428) [0x4c70dd]
> /home/pipe/src/ngspice/debug/src/ngspice(if_run+0x3b9) [0xe5d3e]
> /home/pipe/src/ngspice/debug/src/ngspice(dosim+0x428) [0xe02ee]
Run Code Online (Sandbox Code Playgroud)
在跟踪一些函数内联优化之后,我最终可以从中找到正确的位置。
使用 gdb,您可以根据系统调用的参数设置条件系统调用捕获点(类似于根据函数调用的参数在函数入口处设置条件断点的方式)。然后,当捕获点被触发时,您可以看到调用者所在的位置(文件名、行号和源代码)。
这是 x86_64 的示例。
$ cat gtest.c
#include <unistd.h>
int main()
{
write(1, "text\n", 5);
write(2, "text2\n", 6);
write(2, "\n", 1);
return 0;
}
$ cc gtest.c -g -o gtest
Run Code Online (Sandbox Code Playgroud)
$ gdb -q gtest
Reading symbols from gtest...done.
(gdb) list
1 #include <unistd.h>
2 int main()
3 {
4 write(1, "text\n", 5);
5 write(2, "text2\n", 6);
6 write(2, "\n", 1);
7 return 0;
8 }
(gdb) catch syscall write
Catchpoint 1 (syscall 'write' [1])
(gdb) condition 1 $rdi == 2 && *(char *)$rsi == '\n' && $rdx == 1
(gdb) r
Starting program: /home/mp/gtest
text
text2
Catchpoint 1 (call to syscall write), 0x00007fffff13b970 in __write_nocancel ()
at ../sysdeps/unix/syscall-template.S:84
84 ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) bt
#0 0x00007fffff13b970 in __write_nocancel () at ../sysdeps/unix/syscall-template.S:84
#1 0x00000000080006f6 in main () at gtest.c:6
(gdb) up
#1 0x00000000080006f6 in main () at gtest.c:6
6 write(2, "\n", 1);
(gdb)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
872 次 |
| 最近记录: |