aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorJoel Brobecker <brobecker@adacore.com>2015-11-23 09:53:31 -0800
committerJoel Brobecker <brobecker@adacore.com>2015-11-23 09:53:31 -0800
commita6a20ad7a16346e2d630b312a94a4cbae60fca45 (patch)
tree3a8c4fff81d4c5ce67a1d25206375c081320901e /gdb
parent416dc9c6e9acd57255015d255799ac031a262182 (diff)
downloadgdb-a6a20ad7a16346e2d630b312a94a4cbae60fca45.zip
gdb-a6a20ad7a16346e2d630b312a94a4cbae60fca45.tar.gz
gdb-a6a20ad7a16346e2d630b312a94a4cbae60fca45.tar.bz2
infinite loop stopping at "pop" insn on x64-windows
We noticed the following hang trying to run a program where one of the subroutines we built without debugging info (opaque_routine): $ gdb my_program (gdb) break opaque_routine (gdb) run [...hangs...] The problem comes from the fact that, at the breakpoint's address, we have the following code: => 0x0000000000401994 <+4>: pop %rbp At some point after hitting the breakpoint and stopping, GDB calls amd64_windows_frame_decode_epilogue, which then gets stuck in the following infinite loop: | /* We don't care about the instruction deallocating the frame: | if it hasn't been executed, the pc is still in the body, | if it has been executed, the following epilog decoding will work. */ | | /* First decode: | - pop reg [41 58-5f] or [58-5f]. */ | | while (1) | { | /* Read opcode. */ | if (target_read_memory (pc, &op, 1) != 0) | return -1; | | if (op >= 0x40 && op <= 0x4f) | { | /* REX prefix. */ | rex = op; | | /* Read opcode. */ | if (target_read_memory (pc + 1, &op, 1) != 0) | return -1; | } | else | rex = 0; | | if (op >= 0x58 && op <= 0x5f) | { | /* pop reg */ | gdb_byte reg = (op & 0x0f) | ((rex & 1) << 3); | | cache->prev_reg_addr[amd64_windows_w2gdb_regnum[reg]] = cur_sp; | cur_sp += 8; | } | else | break; | | /* Allow the user to break this loop. This shouldn't happen as the | number of consecutive pop should be small. */ | QUIT; | } Nothing in that loop updates PC, and therefore, because the instruction we stopped at is a "pop", we keep looping forever doing the same thing over and over! This patch fixes the issue by advancing PC to the beginning of the next instruction if the current one is a "pop reg" instruction. gdb/ChangeLog: * amd64-windows-tdep.c (amd64_windows_frame_decode_epilogue): Increment PC in while loop skipping "pop reg" instructions.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog5
-rw-r--r--gdb/amd64-windows-tdep.c1
2 files changed, 6 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 5655ccb..ffcac03 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,10 @@
2015-11-23 Joel Brobecker <brobecker@adacore.com>
+ * amd64-windows-tdep.c (amd64_windows_frame_decode_epilogue):
+ Increment PC in while loop skipping "pop reg" instructions.
+
+2015-11-23 Joel Brobecker <brobecker@adacore.com>
+
* arm-tdep.c (arm_exidx_unwind_sniffer): Do not check for a frame
stuck on a system call if the given frame is the innermost frame.
diff --git a/gdb/amd64-windows-tdep.c b/gdb/amd64-windows-tdep.c
index 296bdb2..c04b730 100644
--- a/gdb/amd64-windows-tdep.c
+++ b/gdb/amd64-windows-tdep.c
@@ -488,6 +488,7 @@ amd64_windows_frame_decode_epilogue (struct frame_info *this_frame,
cache->prev_reg_addr[amd64_windows_w2gdb_regnum[reg]] = cur_sp;
cur_sp += 8;
+ pc += rex ? 2 : 1;
}
else
break;