x32: gdb: Fix 'call' insn relocation with qRelocInsn
authorPedro Alves <palves@redhat.com>
Fri, 19 Aug 2016 11:07:46 +0000 (12:07 +0100)
committerPedro Alves <palves@redhat.com>
Fri, 19 Aug 2016 11:12:51 +0000 (12:12 +0100)
commitf077e978deccac00fea013c4f120122bf6726834
tree1af4224d4171e7c93b552379d4396b623bf316ae
parented036b4052193ba6790ba7ee94a33a364ace3b55
x32: gdb: Fix 'call' insn relocation with qRelocInsn

Running the fast tracepoints tests against x32 gdbserver exposes a
latent bug.  E.g.,:

 (gdb)
 continue
 Continuing.
 Reading /media/sf_host-pedro/gdb/mygit/build-ubuntu-x32/gdb/testsuite/outputs/gdb.trace/change-loc/change-loc-2.sl from remote target...

 Thread 1 "change-loc" received signal SIGSEGV, Segmentation fault.
 func4 () at /home/pedro/gdb/src/gdb/testsuite/gdb.trace/change-loc.h:24
 24      }
 (gdb) FAIL: gdb.trace/change-loc.exp: 1 ftrace: continue to marker 2

The test sets a fast tracepoint on a shared library.  On x32, shared
libraries end up loaded somewhere in the upper 2GB of the 4GB address
space x32 has access to.  When gdbserver needs to copy an instruction
to execute it in the jump pad, it asks gdb to relocate/adjust it, with
the qRelocInsn packet.  gdb converts "call" instructions into a "push
$<2GB-4GB addr> + jmp" sequence, however, the "pushq" instruction sign
extends its operand, so later when the called function returns, it
returns to an incorrectly sign-extended address.  E.g.,
0xfffffffffabc0000 instead of 0xfabc0000, resulting in the
segmentation fault.

Fix this by converting calls at such addresses to "sub + mov + jmp"
sequences instead.

gdb/ChangeLog:
2016-08-19  Pedro Alves  <palves@redhat.com>

* amd64-tdep.c (amd64_relocate_instruction) <callq>: Handle return
addresses over 0x7fffffff.
gdb/ChangeLog
gdb/amd64-tdep.c