如何在gdb中处理`__int128`?

时间:2018-05-13 20:12:44

标签: c gcc gdb

我目前正在努力与gdb一起处理gdb中特定于gcc的类型__int128。我设法做了一些实时计算,例如:

(gdb) p /x (__int128) (1 << (8 * 8))
$1 = 0x00000000000000000000000000000001
(gdb) ptype bitmask
type = const __int128 unsigned

但是,每当我在表达式中尝试评估时会更复杂,我得到:

(gdb) p /x ((((__int128) 1) << (8 * 8)) - 1)
That operation is not available on integers of more than 8 bytes.
(gdb) p /x (__int128) 0xfffffffffffffffffffffffff
Numeric constant too large.

那么,有没有办法在gdb中的__int128上评估这样的表达式?

2 个答案:

答案 0 :(得分:2)

  

那么,有没有办法在gdb

中的128上评估这样的表达式

不是直接的,但你可以使用内置的python(具有无限的精度)来实现一些相同的结果:

(gdb) py print('0x%x' % ((1 << (8 * 8)) - 1))
0xffffffffffffffff

(gdb) py print('0x%x' % ((1 << (8 * 8 + 5)) + 1))
0x200000000000000001

答案 1 :(得分:2)

如果您只需要打印一个常量值,py print(expr128)这个想法可以归结为Python的任意整数精度。

但是,如果您需要使用__int128类型的实际C变量,则需要将其暂时转换为unsigned long long[2]之类的内容以在GDB中对其执行操作,但请记住然后,您正在使用2个64位值的数组,因此X[0] << 64将无法像使用真正的128位__int128类型那样工作。 GDB可以打印该值;它只是无法操纵它的位。 GCC允许你操纵它的位;您的libc无法使用printf打印该值,甚至可能没有任何GCC特定的代码允许它这样做。

这是一个示例shell会话,显示了在GDB中使用此特定于编译器的类型的麻烦:

$ nl bar.c
    1   int main(void)
    2   {
    3       __int128 v = 1;
    4       v <<= 62;
    5       v <<= 2;
    6   }
$ gcc -g -o bar bar.c
$ gdb -q ./bar
Reading symbols from ./bar...done.
(gdb) break 5
Breakpoint 1 at 0x5e8: file bar.c, line 5.
(gdb) run
Starting program: /home/luser/bar

Breakpoint 1, main () at bar.c:5
5       v <<= 2;
(gdb) print/x *(long long(*)[2])&v
$1 = {0x4000000000000000, 0x0}
(gdb) print/x (*(long long(*)[2])&v)[0]+1
$2 = {0x4000000000000001, 0x0}
(gdb) next
6   }
(gdb) print/x *(long long(*)[2])&v
$3 = {0x0, 0x1}
(gdb) print/x (*(long long(*)[2])&v)[0]+1
$4 = {0x1, 0x1}

考虑到我的机器的小端CPU,结果是清楚的:

$1 = 0x0000 0000 0000 0000
       4000 0000 0000 0000  # 1<<62
$2 = 0x0000 0000 0000 0000
       4000 0000 0000 0001  #(1<<62) + 1
$3 = 0x0000 0000 0000 0001
       0000 0000 0000 0000  # 1<<64
$4 = 0x0000 0000 0000 0001
       0000 0000 0000 0001  #(1<<64) + 1

对于这么大的值,甚至十六进制都会变得有点麻烦,但你明白了:在GDB中使用这些值可能是你需要处理的所有括号的问题,而且你需要保持在操作值以及跟踪溢出时,记住目标机器的字节顺序。

我的建议:在一些与__int128值一起使用的算术例程中链接以帮助调试,这样您就可以在GDB中使用call negate128 (value)之类的东西来获取C表达式-value的结果其中value的类型为__int128。不需要溢出检查,因为机器将像处理任何其他类型那样为你处理,所以继续写这样的事情(假设你正在使用溢出不会扼杀程序或整个系统的系统)机):

__int128 add128(__int128 a, __int128 b) { return a + b; }
__int128 sub128(__int128 a, __int128 b) { return a - b; }
__int128 shl128(__int128 a, int n) { return a << n; }
__int128 shr128(__int128 a, int n) { return a >> n; }