[RFA/commit] infinite loop stopping at "pop" insn on x64-windows

Message ID 1447092746-21120-1-git-send-email-brobecker@adacore.com
State New, archived
Headers

Commit Message

Joel Brobecker Nov. 9, 2015, 6:12 p.m. UTC
  Hello,

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.

Tested on x86_64-windows, using AdaCore's testsuite.

Thanks!
  

Comments

Pedro Alves Nov. 20, 2015, 4:06 p.m. UTC | #1
On 11/09/2015 06:12 PM, Joel Brobecker wrote:

> gdb/ChangeLog:
> 
>         * amd64-windows-tdep.c (amd64_windows_frame_decode_epilogue):
>         Increment PC in while loop skipping "pop reg" instructions.
> 
> Tested on x86_64-windows, using AdaCore's testsuite.
> 

LGTM.

Thanks,
Pedro Alves
  
Joel Brobecker Nov. 23, 2015, 5:54 p.m. UTC | #2
> > gdb/ChangeLog:
> > 
> >         * amd64-windows-tdep.c (amd64_windows_frame_decode_epilogue):
> >         Increment PC in while loop skipping "pop reg" instructions.
> > 
> > Tested on x86_64-windows, using AdaCore's testsuite.
> 
> LGTM.

Thanks, Pedro. Patch is now in.
  

Patch

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;