【问题标题】:How can I break on multiple clang/ubsan warnings in gdb?如何打破 gdb 中的多个 clang/ubsan 警告?
【发布时间】:2014-05-22 21:05:51
【问题描述】:

拿下面的测试程序(用clang 3.4编译,在gdb 7.6.1下运行):

#include <limits.h>
#include <stdio.h>

int main(void)
{
    int a = INT_MAX + 1;
    int b = INT_MAX + 2;
    printf("Result: a = %d, b = %d\n", a, b);
}

我希望能够在此处 (int b = ...)第二 次出现未定义行为时使用 gdb 自动停止。

如果我编译:

clang -fsanitize=undefined -O0 -ggdb3 -o test test.c

...然后在 gdb 下运行程序只会导致它运行完成:

test.c:6:21: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
test.c:7:21: runtime error: signed integer overflow: 2147483647 + 2 cannot be represented in type 'int'
Result: a = -2147483648, b = -2147483647
[Inferior 1 (process 24185) exited normally]

但如果我使用:

clang -fsanitize=undefined-trap -fsanitize-undefined-trap-on-error -O0 -ggdb3 -o test test.c

...那么我无法在第一次出现后继续:

Program received signal SIGILL, Illegal instruction.
0x0000000000400556 in main () at test.c:6
6       int a = INT_MAX + 1;
(gdb) c
Continuing.

Program terminated with signal SIGILL, Illegal instruction.
The program no longer exists.

是否有可能在(且仅在)未定义的行为被标记时让 gdb 中断,但让程序继续运行?我追求的技术不仅适用于这个例子,而且一般来说,有问题的行可能在循环内,值可能在运行时确定,等等。

【问题讨论】:

  • 使用第一种编译方式,在write上插入断点,查看堆栈跟踪。

标签: c gdb clang undefined-behavior


【解决方案1】:

在 x86-64 上,导致 SIGILL 并停止程序的指令是 ud2 (http://asm.inightmare.org/opcodelst/index.php?op=UD2)。为了归档您的目标,您可以更改 SIGILL 的 gdb 处理并使用跳转(您需要在 x86_64 上将 2 添加到 $pc):

这就是指令 ud2 在 x86_64 上的测试程序代码中的放置方式:

   0x00000000004004f0 <+32>:    0f 85 02 00 00 00       jne    0x4004f8 <main+40>
=> 0x00000000004004f6 <+38>:    0f 0b   ud2
   0x00000000004004f8 <+40>:    b8 ff ff ff 7f  mov    $0x7fffffff,%eax

这些是必须使用的 gdb 命令:

handle SIGILL stop print nopass
set $pc = $pc + 2

这是您的测试程序的示例:

$ gdb -q ./test
Reading symbols from /home/test...done.
(gdb) handle SIGILL stop print nopass
Signal        Stop      Print   Pass to program Description
SIGILL        Yes       Yes     No              Illegal instruction
(gdb) r
Starting program: /home/test

Program received signal SIGILL, Illegal instruction.
0x00000000004004f6 in main () at test.c:6
6         int a = INT_MAX + 1;
(gdb) set $pc = $pc + 2
(gdb) c
Continuing.

Program received signal SIGILL, Illegal instruction.
0x000000000040051f in main () at test.c:7
7         int b = INT_MAX + 2;
(gdb) set $pc = $pc + 2
(gdb) c
Continuing.
Result: a = -2147483648, b = -2147483647
[Inferior 1 (process 7898) exited normally]
(gdb)

有用的链接:

【讨论】:

    猜你喜欢
    • 2015-09-15
    • 1970-01-01
    • 2021-06-03
    • 1970-01-01
    • 2018-02-02
    • 2017-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多