【问题标题】:How to deal with `__int128` in gdb?如何处理 gdb 中的`__int128`?
【发布时间】:2018-05-13 20:12:43
【问题描述】:

我目前正在努力使用 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 上的此类表达式?

【问题讨论】:

  • 您的第一次计算是错误的,因为1 &lt;&lt; (8 * 8) 的类型为int 并且 因此该表达式的行为是未定义
  • 事实上,我写这个表达式是因为它给出了一些答案......但是,我并不真正关心它,我正在寻找的总是给出最后一个错误消息。

标签: c gcc gdb


【解决方案1】:

如果您只需要打印一个常量值,py print(expr128) 的想法非常有效,因为 Python 具有任意整数精度。

但是,如果您需要使用 __int128 类型的实际 C 变量,则需要将其临时转换为 unsigned long long[2] 之类的东西,以便在 GDB 中对其执行操作,但请记住,您是然后使用 2 个 64 位值的数组,因此 X[0] &lt;&lt; 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; }

【讨论】:

    【解决方案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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-10
      • 2015-02-28
      • 2014-09-26
      • 1970-01-01
      • 1970-01-01
      • 2014-07-12
      • 1970-01-01
      • 2021-11-27
      相关资源
      最近更新 更多