GDB: попытка разыменовать общий указатель

Как я могу заставить 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), поскольку двойное отклонение от него передается как второе аргумент printf (т.е. в 0x4(%esp)) в строке 26:

$ 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 <[email protected]>
   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

Я пытаюсь напечатать argv[0] в GDB, но я получаю "общий указатель" Ошибка:

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) 

Но это раздражает и косвенно (поскольку программирование указателя не будет?)

Ответ 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 **.