I'm using gdb 7.5.1, on a more-or-less vanilla amd64 box. I'm seeing that it is possible to 1. set a breakpoint somewhere 2. load a new version of the executable being debugged 3. observe the breakpoint 0xCC byte end up in the middle of an instruction, causing havoc The 0xCC byte corrupts the instruction it ends up in. Furthermore, unless one knows that a breakpoint is involved, the observed behavior is extremely mysterious. The output of "disass /r" doesn't display the 0xCC, so the user thinks they're stepping through one instruction, while gdb is executing a completely different one. To reproduce, I have the following source I named tst.c: ============================== #include <stdio.h> #include <stdlib.h> static void f(void) { #ifdef PAD char c = 3; #endif int a = 5; printf("0x%x\n", a); } int main(void) { f(); return 0; } ============================== I compile this with and without defining PAD: gcc-4.7 -DPAD -g -o tst_pad tst.c; gcc-4.7 -g -o tst tst.c I then load "tst_pad", set the breakpoint on the "a=5" line, then load "tst". The old breakpoint stays at the same exact address, corrupting the a=5 statement. This can be shown by running "gdb -x gdb.cmd" with gdb.cmd as ============================== file /tmp/tst_pad b main r s n b info b c file /tmp/tst r info b disass /r f c q ============================== The output I see from this is ============================== GNU gdb (GDB) 7.5.1 Copyright (C) 2012 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-unknown-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Breakpoint 1 at 0x400539: file tst.c, line 16. Breakpoint 1, main () at tst.c:16 16 f(); f () at tst.c:7 7 char c = 3; 9 int a = 5; Breakpoint 2 at 0x400518: file tst.c, line 9. Num Type Disp Enb Address What 1 breakpoint keep y 0x0000000000400539 in main at tst.c:16 breakpoint already hit 1 time 2 breakpoint keep y 0x0000000000400518 in f at tst.c:9 0x5 [Inferior 1 (process 17031) exited normally] Breakpoint 1, main () at tst.c:16 16 f(); Num Type Disp Enb Address What 1 breakpoint keep y 0x0000000000400535 in main at tst.c:16 breakpoint already hit 1 time 2 breakpoint keep y 0x0000000000400518 in f at tst.c:9 Dump of assembler code for function f: 0x000000000040050c <+0>: 55 push rbp 0x000000000040050d <+1>: 48 89 e5 mov rbp,rsp 0x0000000000400510 <+4>: 48 83 ec 10 sub rsp,0x10 0x0000000000400514 <+8>: c7 45 fc 05 00 00 00 mov DWORD PTR [rbp-0x4],0x5 0x000000000040051b <+15>: 8b 45 fc mov eax,DWORD PTR [rbp-0x4] 0x000000000040051e <+18>: 89 c6 mov esi,eax 0x0000000000400520 <+20>: bf fc 05 40 00 mov edi,0x4005fc 0x0000000000400525 <+25>: b8 00 00 00 00 mov eax,0x0 0x000000000040052a <+30>: e8 b1 fe ff ff call 0x4003e0 <printf@plt> 0x000000000040052f <+35>: c9 leave 0x0000000000400530 <+36>: c3 ret End of assembler dump. 0xcc05 [Inferior 1 (process 17039) exited normally] ============================== Note that the breakpoint is at 0x400518 in BOTH executables, and the "a" variable ends up being 0xCC05 instead of 5. This is extremely perplexing to the unsuspecting user, since the output of "disass /r" doesn't show the 0xCC. So the user steps through the instruction "mov DWORD PTR [rbp-0x4],0x5", but observes something completely different happening! gdb appears to have some safeguards against this. In the above script the breakpoint was set with a simple "b" command when gdb was stopped at the particular location. If it was set with "b 9" instead (breaking on line 9, which should be the same) then when loading the new executable, the breakpoint is moved to 0x400514, which is at the start of an instruction, and produces more predictable behavior. I think it would be great if the breakpoint reinterpretation was either fixed, or documented more clearly to indicate when the breakpoint should be moved and when not. "help b" doesn't make clear that "b" and "b 9" produce very different behaviors. Also, it would be great if "disass /r" had some sort of indication that a particular instruction has been overwritten by a breakpoint; this would make the observed failure much less baffling. Thanks
This is a similar issue to PR11273, since 'b' without arguments is used here, which sets the breakpoint on the current address, no matter what.