【问题标题】:GDB: Attempt to dereference generic pointerGDB:尝试取消引用通用指针
【发布时间】:2013-12-23 06:16:13
【问题描述】:

如何让 GDB 在打印功能中进行额外的取消引用,例如 x/s?

当我在 x/ 中尝试显式取消引用时,我收到错误“尝试 取消引用通用指针”。多次使用 x/ 有效,因为 每次使用都包含一个隐式取消引用,但这很烦人,因为 我必须复制并粘贴每个中间结果。

示例

考虑一下非常有用的 C 程序,example.c

#include <stdio.h>
int main(int argc, char **argv) {
  printf("argv[0] = %s\n", argv[0]);
}

如果我构建它并将其加载到 GDB 中,我会看到 argv 存储在 0xc(%ebp),因为它的双重引用作为第二个传递 第 26 行 printf 的参数(即在 0x4(%esp) 中):

$ gcc -o example example.c
$ gdb example

(gdb) disass main
Dump of assembler code for function main:
   0x080483e4 <+0>:   push   %ebp
   0x080483e5 <+1>:   mov    %esp,%ebp
   0x080483e7 <+3>:   and    $0xfffffff0,%esp
   0x080483ea <+6>:   sub    $0x10,%esp
   0x080483ed <+9>:   mov    0xc(%ebp),%eax
   0x080483f0 <+12>:  mov    (%eax),%edx
   0x080483f2 <+14>:  mov    $0x80484e0,%eax
   0x080483f7 <+19>:  mov    %edx,0x4(%esp)
   0x080483fb <+23>:  mov    %eax,(%esp)
   0x080483fe <+26>:  call   0x8048300 <printf@plt>
   0x08048403 <+31>:  leave  
   0x08048404 <+32>:  ret    
End of assembler dump.

我在printf 中断并使用参数first 和运行程序 second:

(gdb) break *main + 26
Breakpoint 1 at 0x80483fe

(gdb) run first second
Starting program: /var/tmp/SO-attempt-to-dereference-generic-pointer/example first second

我尝试在 GDB 中打印 argv[0],但我得到了“通用指针” 错误:

Breakpoint 1, 0x080483e5 in main ()
(gdb) x/s **(0xc + $ebp)
Attempt to dereference a generic pointer.

但是,通过使用 'x/xw' 手动取消引用几次,我 最终能够打印argv[0](和argv[1]):

(gdb) x/xw 0xc + $ebp
0xbfffeba4: 0xbfffec34
(gdb) x/xw 0xbfffec34
0xbfffec34: 0xbfffedc8
(gdb) x/s 0xbfffedc8
0xbfffedc8:  "/var/tmp/SO-attempt-to-dereference-generic-pointer/example"

(gdb) x/xw 0xbfffec34 + 4
0xbfffec38: 0xbfffee03
(gdb) x/s 0xbfffee03
0xbfffee03:  "first"
(gdb) 

但这很烦人而且是间接的(因为指针编程不应该是这样的?)

【问题讨论】:

    标签: c debugging assembly gdb


    【解决方案1】:

    解决方案是在解除引用之前强制转换指针。

    例如,从上面离开的地方继续:

    (gdb) x/s **((char ***) (0xc + $ebp))
    0xbfffedc8:  "/var/tmp/SO-attempt-to-dereference-generic-pointer/example"
    (gdb) x/s *(*((char ***) (0xc + $ebp)) + 1)
    0xbfffee03:  "first"
    (gdb) x/s *(*((char ***) (0xc + $ebp)) + 2)
    0xbfffee09:  "second"
    

    请注意,堆栈地址0xc + $ebp 本身就是一个指向 该堆栈位置的内容,因此我们需要char *** 而不是 char **.

    【讨论】:

    • 为什么这个过程不能被 GDB 自动化?我知道我正在使用指针,否则我不会要求取消引用。显然,如果我要求再次取消引用,那么第一次取消引用的结果必须是一个指针......
    猜你喜欢
    • 2016-04-16
    • 1970-01-01
    • 2013-02-21
    • 2013-01-08
    • 2013-08-21
    • 2018-02-14
    • 2020-06-05
    • 1970-01-01
    • 2012-07-06
    相关资源
    最近更新 更多