From: Joel Brobecker Date: Mon, 23 Nov 2015 17:53:31 +0000 (-0800) Subject: infinite loop stopping at "pop" insn on x64-windows X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a6a20ad7a16346e2d630b312a94a4cbae60fca45;p=binutils-gdb.git 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 --git a/gdb/ChangeLog b/gdb/ChangeLog index 5655ccbd782..ffcac03902a 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,8 @@ +2015-11-23 Joel Brobecker + + * amd64-windows-tdep.c (amd64_windows_frame_decode_epilogue): + Increment PC in while loop skipping "pop reg" instructions. + 2015-11-23 Joel Brobecker * arm-tdep.c (arm_exidx_unwind_sniffer): Do not check for a frame diff --git a/gdb/amd64-windows-tdep.c b/gdb/amd64-windows-tdep.c index 296bdb2710e..c04b730f2f2 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;