Comment puis-je faire GDB faire des déréférences supplémentaires dans une fonction d'impression comme x/s
?
Lorsque j'essaie des déréférences explicites dans x/
, J'obtiens l'erreur "Tentative de déréférencer un pointeur générique". Utiliser x/
Plusieurs fois fonctionne, car chaque utilisation inclut une déréférence implicite, mais c'est ennuyeux car je dois copier et coller chaque résultat intermédiaire.
Considérez le programme C très utile, example.c
:
#include <stdio.h>
int main(int argc, char **argv) {
printf("argv[0] = %s\n", argv[0]);
}
Si je le construis et le charge dans GDB, je vois que argv
est stocké dans 0xc(%ebp)
, car une double dérivation de celui-ci est passée comme deuxième argument à printf
( c'est-à-dire dans 0x4(%esp)
) sur la ligne 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 <printf@plt>
0x08048403 <+31>: leave
0x08048404 <+32>: ret
End of assembler dump.
Je casse à printf
et exécute le programme avec les arguments first
et 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
J'essaie d'imprimer argv[0]
Dans GDB, mais j'obtiens l'erreur "pointeur générique":
Breakpoint 1, 0x080483e5 in main ()
(gdb) x/s **(0xc + $ebp)
Attempt to dereference a generic pointer.
Cependant, en utilisant 'x/xw' pour déréférencer manuellement plusieurs fois, je peux finalement imprimer argv[0]
(Et 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)
Mais c'est ennuyeux et indirect (comme la programmation de pointeurs ne le sera pas?)
La solution consiste à lancer les pointeurs avant de les déréférencer.
Par exemple, reprendre là où nous nous étions arrêtés ci-dessus:
(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"
Notez que l'adresse de pile 0xc + $ebp
est lui-même un pointeur vers le contenu de cet emplacement de pile, et nous avons donc besoin de char ***
et pas char **
.