This is the mail archive of the gdb-cvs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]