This is the mail archive of the
gdb-cvs@sourceware.org
mailing list for the GDB project.
[binutils-gdb] infinite loop stopping at "pop" insn on x64-windows
- From: Joel Brobecker <brobecke at sourceware dot org>
- To: gdb-cvs at sourceware dot org
- Date: 23 Nov 2015 17:53:56 -0000
- Subject: [binutils-gdb] infinite loop stopping at "pop" insn on x64-windows
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=a6a20ad7a16346e2d630b312a94a4cbae60fca45
commit a6a20ad7a16346e2d630b312a94a4cbae60fca45
Author: Joel Brobecker <brobecker@adacore.com>
Date: Mon Nov 23 09:53:31 2015 -0800
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.
Diff:
---
gdb/ChangeLog | 5 +++++
gdb/amd64-windows-tdep.c | 1 +
2 files changed, 6 insertions(+)
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;