Druga część jest łatwa do wytłumaczenia (jak poprawnie podano Flortify): GDB pokazuje oryginalną zawartość pamięci, a nie punkt przerwania "bajtów". W trybie domyślnym nawet usuwa punkty przerwania, gdy debugger zawiesza się i wstawia ponownie przed kontynuowaniem. Użytkownicy zazwyczaj chcą zobaczyć swój kod, a nie dziwne zmodyfikowane instrukcje używane dla punktów przerwania.
Za pomocą kodu C pominięto punkt przerwania dla kilku bajtów. GDB ustawia punkt przerwania pofunction prologue, ponieważ prolog funkcyjny zwykle nie jest tym, co użytkownicy gdb chcą zobaczyć.Tak więc, jeśli wstawisz break na foo, rzeczywisty punkt przerwania będzie zazwyczaj znajdował się kilka bajtów po tym (zależy to od kodu prologu, który jest zależny od funkcji, ponieważ może lub nie musi zapisywać wskaźnika stosu, wskaźnika ramki i tak dalej). Ale łatwo to sprawdzić. Użyłem tego kodu:
#include <stdio.h>
int main()
{
int i,j;
unsigned char *p = (unsigned char*)main;
for (j=0; j<4; j++) {
printf("%p: ",p);
for (i=0; i<16; i++)
printf("%.2x ", *p++);
printf("\n");
}
return 0;
}
Jeśli uruchomić ten program sam to drukuje:
0x40057d: 55 48 89 e5 48 83 ec 10 48 c7 45 f8 7d 05 40 00
0x40058d: c7 45 f4 00 00 00 00 eb 5a 48 8b 45 f8 48 89 c6
0x40059d: bf 84 06 40 00 b8 00 00 00 00 e8 b4 fe ff ff c7
0x4005ad: 45 f0 00 00 00 00 eb 27 48 8b 45 f8 48 8d 50 01
Teraz możemy uruchomić go w gdb (wyjściowe ponownie formatowane dla SO).
(gdb) break main
Breakpoint 1 at 0x400585: file ../bp.c, line 6.
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000400585 in main at ../bp.c:6
(gdb) disas/r main,+32
Dump of assembler code from 0x40057d to 0x40059d:
0x000000000040057d (main+0): 55 push %rbp
0x000000000040057e (main+1): 48 89 e5 mov %rsp,%rbp
0x0000000000400581 (main+4): 48 83 ec 10 sub $0x10,%rsp
0x0000000000400585 (main+8): 48 c7 45 f8 7d 05 40 00 movq $0x40057d,-0x8(%rbp)
0x000000000040058d (main+16): c7 45 f4 00 00 00 00 movl $0x0,-0xc(%rbp)
0x0000000000400594 (main+23): eb 5a jmp 0x4005f0
0x0000000000400596 (main+25): 48 8b 45 f8 mov -0x8(%rbp),%rax
0x000000000040059a (main+29): 48 89 c6 mov %rax,%rsi
End of assembler dump.
Dzięki temu możemy zweryfikować, że program jest drukowanie poprawnych bajtów. Ale to również pokazuje, że punkt przerwania został wstawiony przy 0x400585 (czyli po prologu funkcji), a nie na pierwszej instrukcji funkcji. Jeśli teraz uruchomić program, w ramach gdb (z run), a następnie „dalej” po punkt przerwania jest trafiony, możemy uzyskać ten wynik:
(gdb) cont
Continuing.
0x40057d: 55 48 89 e5 48 83 ec 10 cc c7 45 f8 7d 05 40 00
0x40058d: c7 45 f4 00 00 00 00 eb 5a 48 8b 45 f8 48 89 c6
0x40059d: bf 84 06 40 00 b8 00 00 00 00 e8 b4 fe ff ff c7
0x4005ad: 45 f0 00 00 00 00 eb 27 48 8b 45 f8 48 8d 50 01
To pokazuje teraz 0xcc drukowane na adres 9 bajtów na główne .
Istnieje interesujący artykuł na ten temat 'Jak działa debugger', spójrz na tę część artykułu' Magia za INT 3': http://www.alexonlinux.com/how-debugger-works # the_magic_behind_int_3 –