GDB 和 LLDB 都无法在简单的 C 文件中可靠地执行断点命令
Both GDB and LLDB failing to reliably execute breakpoint commands in simple C file
作为研究项目的一部分,我正在尝试编写一个 gdb 命令文件,该文件输出任意 C 源文件中每一行代码的特定信息,直到程序终止。这似乎很容易通过 while 循环完成,在循环中输出我想要的任何数据,然后在循环结束时调用 "next"。 (我知道我希望 "step" 进入函数调用;我现在不关心这个。)
但是,除了我每一行输出的数据之外,我还想在某些断点处执行特殊的命令。这似乎很容易用 "command" 完成。但是,我遇到了 while 循环和断点命令都不起作用的问题。
这是我正在使用的用于测试目的的极其简单的 C 文件:
int global;
int main() {
int x;
x=-1;
global = 5;
return(0);
}
我用gcc -g -o simple simple.c
编译它。那我运行gdb -x commands.txt
。如果commands.txt的内容如下:
set confirm off
exec-file simple
file simple
set logging file gdb_output.txt
set logging on
set pagination off
#Special commands I want to execute on certain breakpoints
break 5
command
echo COMMAND 1 ACTIVATED\n
end
break 6
command
echo COMMAND 2 ACTIVATED\n
end
break 7
command
echo COMMAND 3 ACTIVATED\n
end
run
next
next
next
continue
quit
...那么 gdb_output.txt 的内容如下,符合预期:
Breakpoint 1 at 0x4004da: file simple.c, line 5.
Breakpoint 2 at 0x4004e1: file simple.c, line 6.
Breakpoint 3 at 0x4004eb: file simple.c, line 7.
Breakpoint 1, main () at simple.c:5
5 x=-1;
COMMAND 1 ACTIVATED
Breakpoint 2, main () at simple.c:6
6 global = 5;
COMMAND 2 ACTIVATED
Breakpoint 3, main () at simple.c:7
7 return(0);
COMMAND 3 ACTIVATED
8 }
[Inferior 1 (process 29631) exited normally]
但是,如果我编辑命令文件以尝试作为循环执行,替换
next
next
next
continue
和
while true
next
end
但保留脚本的其余部分完全相同,然后我为第 6 行和第 7 行的断点指定的命令永远不会执行,运行 修改后 gdb_output.txt 的内容证明了这一点命令文件:
Breakpoint 1 at 0x4004da: file simple.c, line 5.
Breakpoint 2 at 0x4004e1: file simple.c, line 6.
Breakpoint 3 at 0x4004eb: file simple.c, line 7.
Breakpoint 1, main () at simple.c:5
5 x=-1;
COMMAND 1 ACTIVATED
Breakpoint 2, main () at simple.c:6
6 global = 5;
Breakpoint 3, main () at simple.c:7
7 return(0);
8 }
__libc_start_main (main=0x4004d6 <main()>, argc=1, argv=0x7fffffffe128, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe118) at ../csu/libc-start.c:325
325 ../csu/libc-start.c: No such file or directory.
[Inferior 1 (process 29652) exited normally]
commands.txt:30: Error in sourced command file:
The program is not being run.
我知道当前形式的循环是有问题的,因为它会一直调用 "next" 直到程序终止(所以它永远不会到达脚本底部的 "quit"),但这似乎不应该阻止断点命令成为 运行——但这似乎正在发生。 (如果断点命令 正在执行 ,我可以设置我的 while 循环在它遇到在 C 程序退出点之前设置的断点时终止。)
这是 GDB 中的错误,还是我误解了什么?如果这种构造根本行不通,那么有没有一种方法可以在程序的每个步骤 运行 上执行一系列固定的 GDB 命令,直到程序终止,同时还执行在某些断点处指定的命令——或者是使用 GDB 脚本这根本不可能?
(我的 gdb 版本是 7.11.1,如果重要的话,我的 OS 是 Linux。)
更新
我决定试一试 lldb 并 运行 解决一些更复杂的问题(使用与上面相同的 C 文件,使用相同的命令编译)。这是我的 lldb 脚本:
target create --no-dependents --arch x86_64 simple
breakpoint set --file simple.c --line 5
breakpoint command add
script print "COMMAND 1 ACTIVATED"
DONE
breakpoint set --file simple.c --line 6
breakpoint command add
script print "COMMAND 2 ACTIVATED"
DONE
breakpoint set --file simple.c --line 7
breakpoint command add
script print "COMMAND 3 ACTIVATED"
DONE
run
frame variable x
continue
frame variable x
continue
frame variable x
continue
quit
这表现出相当 st运行ge 的行为。上面的版本命中第一个断点,执行相关命令,然后忽略所有后续断点。如果我注释掉 仅第二个断点 、它的相关命令以及相应的 frame variable x
、continue
,那么断点 1 和 3 都会被命中,它们的相应命令也会被命中被执行。仅注释掉第一个或第三个断点及其关联的命令和 frame variable x
、continue
会导致 仅命中第一个未注释的断点 及其关联的命令 运行。简而言之,似乎在连续两行代码上设置断点会导致第一个断点之后的所有断点都被忽略。
有人知道这里发生了什么吗?有没有办法让我在每一行都有一个断点并让它们都被击中?这个问题是否与上述 gdb 问题有任何关系?
我仍然没有弄清楚为什么 gdb 和 lldb 会按照它们原来的方式运行,但我确实设计了一种替代方法来实现我想要的。我编写了一个脚本,使用两个命名管道与 lldb 通信,脚本的标准输出链接到 lldb 的标准输入,反之亦然,因此脚本可以发送 lldb 命令(frame variable -L
、bt
、step
, 等) 然后获取 lldb 的输出并解析它。该脚本当然可以循环所有它想要的,所以这绕过了我无法让 gdb 或 lldb 命令文件正确循环的问题。
作为研究项目的一部分,我正在尝试编写一个 gdb 命令文件,该文件输出任意 C 源文件中每一行代码的特定信息,直到程序终止。这似乎很容易通过 while 循环完成,在循环中输出我想要的任何数据,然后在循环结束时调用 "next"。 (我知道我希望 "step" 进入函数调用;我现在不关心这个。)
但是,除了我每一行输出的数据之外,我还想在某些断点处执行特殊的命令。这似乎很容易用 "command" 完成。但是,我遇到了 while 循环和断点命令都不起作用的问题。
这是我正在使用的用于测试目的的极其简单的 C 文件:
int global;
int main() {
int x;
x=-1;
global = 5;
return(0);
}
我用gcc -g -o simple simple.c
编译它。那我运行gdb -x commands.txt
。如果commands.txt的内容如下:
set confirm off
exec-file simple
file simple
set logging file gdb_output.txt
set logging on
set pagination off
#Special commands I want to execute on certain breakpoints
break 5
command
echo COMMAND 1 ACTIVATED\n
end
break 6
command
echo COMMAND 2 ACTIVATED\n
end
break 7
command
echo COMMAND 3 ACTIVATED\n
end
run
next
next
next
continue
quit
...那么 gdb_output.txt 的内容如下,符合预期:
Breakpoint 1 at 0x4004da: file simple.c, line 5.
Breakpoint 2 at 0x4004e1: file simple.c, line 6.
Breakpoint 3 at 0x4004eb: file simple.c, line 7.
Breakpoint 1, main () at simple.c:5
5 x=-1;
COMMAND 1 ACTIVATED
Breakpoint 2, main () at simple.c:6
6 global = 5;
COMMAND 2 ACTIVATED
Breakpoint 3, main () at simple.c:7
7 return(0);
COMMAND 3 ACTIVATED
8 }
[Inferior 1 (process 29631) exited normally]
但是,如果我编辑命令文件以尝试作为循环执行,替换
next
next
next
continue
和
while true
next
end
但保留脚本的其余部分完全相同,然后我为第 6 行和第 7 行的断点指定的命令永远不会执行,运行 修改后 gdb_output.txt 的内容证明了这一点命令文件:
Breakpoint 1 at 0x4004da: file simple.c, line 5.
Breakpoint 2 at 0x4004e1: file simple.c, line 6.
Breakpoint 3 at 0x4004eb: file simple.c, line 7.
Breakpoint 1, main () at simple.c:5
5 x=-1;
COMMAND 1 ACTIVATED
Breakpoint 2, main () at simple.c:6
6 global = 5;
Breakpoint 3, main () at simple.c:7
7 return(0);
8 }
__libc_start_main (main=0x4004d6 <main()>, argc=1, argv=0x7fffffffe128, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe118) at ../csu/libc-start.c:325
325 ../csu/libc-start.c: No such file or directory.
[Inferior 1 (process 29652) exited normally]
commands.txt:30: Error in sourced command file:
The program is not being run.
我知道当前形式的循环是有问题的,因为它会一直调用 "next" 直到程序终止(所以它永远不会到达脚本底部的 "quit"),但这似乎不应该阻止断点命令成为 运行——但这似乎正在发生。 (如果断点命令 正在执行 ,我可以设置我的 while 循环在它遇到在 C 程序退出点之前设置的断点时终止。)
这是 GDB 中的错误,还是我误解了什么?如果这种构造根本行不通,那么有没有一种方法可以在程序的每个步骤 运行 上执行一系列固定的 GDB 命令,直到程序终止,同时还执行在某些断点处指定的命令——或者是使用 GDB 脚本这根本不可能?
(我的 gdb 版本是 7.11.1,如果重要的话,我的 OS 是 Linux。)
更新
我决定试一试 lldb 并 运行 解决一些更复杂的问题(使用与上面相同的 C 文件,使用相同的命令编译)。这是我的 lldb 脚本:
target create --no-dependents --arch x86_64 simple
breakpoint set --file simple.c --line 5
breakpoint command add
script print "COMMAND 1 ACTIVATED"
DONE
breakpoint set --file simple.c --line 6
breakpoint command add
script print "COMMAND 2 ACTIVATED"
DONE
breakpoint set --file simple.c --line 7
breakpoint command add
script print "COMMAND 3 ACTIVATED"
DONE
run
frame variable x
continue
frame variable x
continue
frame variable x
continue
quit
这表现出相当 st运行ge 的行为。上面的版本命中第一个断点,执行相关命令,然后忽略所有后续断点。如果我注释掉 仅第二个断点 、它的相关命令以及相应的 frame variable x
、continue
,那么断点 1 和 3 都会被命中,它们的相应命令也会被命中被执行。仅注释掉第一个或第三个断点及其关联的命令和 frame variable x
、continue
会导致 仅命中第一个未注释的断点 及其关联的命令 运行。简而言之,似乎在连续两行代码上设置断点会导致第一个断点之后的所有断点都被忽略。
有人知道这里发生了什么吗?有没有办法让我在每一行都有一个断点并让它们都被击中?这个问题是否与上述 gdb 问题有任何关系?
我仍然没有弄清楚为什么 gdb 和 lldb 会按照它们原来的方式运行,但我确实设计了一种替代方法来实现我想要的。我编写了一个脚本,使用两个命名管道与 lldb 通信,脚本的标准输出链接到 lldb 的标准输入,反之亦然,因此脚本可以发送 lldb 命令(frame variable -L
、bt
、step
, 等) 然后获取 lldb 的输出并解析它。该脚本当然可以循环所有它想要的,所以这绕过了我无法让 gdb 或 lldb 命令文件正确循环的问题。