diff options
author | Joel Brobecker <brobecker@adacore.com> | 2015-11-23 09:53:31 -0800 |
---|---|---|
committer | Joel Brobecker <brobecker@adacore.com> | 2015-11-23 09:53:31 -0800 |
commit | a6a20ad7a16346e2d630b312a94a4cbae60fca45 (patch) | |
tree | 3a8c4fff81d4c5ce67a1d25206375c081320901e /gdb | |
parent | 416dc9c6e9acd57255015d255799ac031a262182 (diff) | |
download | gdb-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/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/amd64-windows-tdep.c | 1 |
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; |