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.
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.
cache->prev_reg_addr[amd64_windows_w2gdb_regnum[reg]] = cur_sp;
cur_sp += 8;
+ pc += rex ? 2 : 1;
}
else
break;