| Index: gdb/i386-linux-tdep.c
|
| diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c
|
| index eb114ef18c20d7d065c7cfdb35304b0164a7dea9..8475d7a8e1062e36064e84a1023edc38f7c9d74a 100644
|
| --- a/gdb/i386-linux-tdep.c
|
| +++ b/gdb/i386-linux-tdep.c
|
| @@ -254,7 +254,7 @@ static int
|
| i386_linux_sigtramp_p (struct frame_info *this_frame)
|
| {
|
| CORE_ADDR pc = get_frame_pc (this_frame);
|
| - char *name;
|
| + const char *name;
|
|
|
| find_pc_partial_function (pc, &name, NULL, NULL);
|
|
|
| @@ -279,7 +279,7 @@ i386_linux_dwarf_signal_frame_p (struct gdbarch *gdbarch,
|
| struct frame_info *this_frame)
|
| {
|
| CORE_ADDR pc = get_frame_pc (this_frame);
|
| - char *name;
|
| + const char *name;
|
|
|
| find_pc_partial_function (pc, &name, NULL, NULL);
|
|
|
| @@ -418,7 +418,7 @@ i386_canonicalize_syscall (int syscall)
|
| static struct linux_record_tdep i386_linux_record_tdep;
|
|
|
| static int
|
| -i386_linux_intx80_sysenter_record (struct regcache *regcache)
|
| +i386_linux_intx80_sysenter_syscall_record (struct regcache *regcache)
|
| {
|
| int ret;
|
| LONGEST syscall_native;
|
| @@ -459,10 +459,10 @@ i386_linux_intx80_sysenter_record (struct regcache *regcache)
|
| #define I386_LINUX_xstate 270
|
| #define I386_LINUX_frame_size 732
|
|
|
| -int
|
| +static int
|
| i386_linux_record_signal (struct gdbarch *gdbarch,
|
| struct regcache *regcache,
|
| - enum target_signal signal)
|
| + enum gdb_signal signal)
|
| {
|
| ULONGEST esp;
|
|
|
| @@ -491,11 +491,17 @@ i386_linux_record_signal (struct gdbarch *gdbarch,
|
| }
|
|
|
|
|
| +/* Core of the implementation for gdbarch get_syscall_number. Get pending
|
| + syscall number from REGCACHE. If there is no pending syscall -1 will be
|
| + returned. Pending syscall means ptrace has stepped into the syscall but
|
| + another ptrace call will step out. PC is right after the int $0x80
|
| + / syscall / sysenter instruction in both cases, PC does not change during
|
| + the second ptrace step. */
|
| +
|
| static LONGEST
|
| -i386_linux_get_syscall_number (struct gdbarch *gdbarch,
|
| - ptid_t ptid)
|
| +i386_linux_get_syscall_number_from_regcache (struct regcache *regcache)
|
| {
|
| - struct regcache *regcache = get_thread_regcache (ptid);
|
| + struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
| /* The content of a register. */
|
| gdb_byte buf[4];
|
| @@ -512,6 +518,18 @@ i386_linux_get_syscall_number (struct gdbarch *gdbarch,
|
| return ret;
|
| }
|
|
|
| +/* Wrapper for i386_linux_get_syscall_number_from_regcache to make it
|
| + compatible with gdbarch get_syscall_number method prototype. */
|
| +
|
| +static LONGEST
|
| +i386_linux_get_syscall_number (struct gdbarch *gdbarch,
|
| + ptid_t ptid)
|
| +{
|
| + struct regcache *regcache = get_thread_regcache (ptid);
|
| +
|
| + return i386_linux_get_syscall_number_from_regcache (regcache);
|
| +}
|
| +
|
| /* The register sets used in GNU/Linux ELF core-dumps are identical to
|
| the register sets in `struct user' that are used for a.out
|
| core-dumps. These are also used by ptrace(2). The corresponding
|
| @@ -643,6 +661,49 @@ i386_linux_core_read_description (struct gdbarch *gdbarch,
|
| return tdesc_i386_mmx_linux;
|
| }
|
|
|
| +/* Linux kernel shows PC value after the 'int $0x80' instruction even if
|
| + inferior is still inside the syscall. On next PTRACE_SINGLESTEP it will
|
| + finish the syscall but PC will not change.
|
| +
|
| + Some vDSOs contain 'int $0x80; ret' and during stepping out of the syscall
|
| + i386_displaced_step_fixup would keep PC at the displaced pad location.
|
| + As PC is pointing to the 'ret' instruction before the step
|
| + i386_displaced_step_fixup would expect inferior has just executed that 'ret'
|
| + and PC should not be adjusted. In reality it finished syscall instead and
|
| + PC should get relocated back to its vDSO address. Hide the 'ret'
|
| + instruction by 'nop' so that i386_displaced_step_fixup is not confused.
|
| +
|
| + It is not fully correct as the bytes in struct displaced_step_closure will
|
| + not match the inferior code. But we would need some new flag in
|
| + displaced_step_closure otherwise to keep the state that syscall is finishing
|
| + for the later i386_displaced_step_fixup execution as the syscall execution
|
| + is already no longer detectable there. The new flag field would mean
|
| + i386-linux-tdep.c needs to wrap all the displacement methods of i386-tdep.c
|
| + which does not seem worth it. The same effect is achieved by patching that
|
| + 'nop' instruction there instead. */
|
| +
|
| +static struct displaced_step_closure *
|
| +i386_linux_displaced_step_copy_insn (struct gdbarch *gdbarch,
|
| + CORE_ADDR from, CORE_ADDR to,
|
| + struct regcache *regs)
|
| +{
|
| + struct displaced_step_closure *closure;
|
| +
|
| + closure = i386_displaced_step_copy_insn (gdbarch, from, to, regs);
|
| +
|
| + if (i386_linux_get_syscall_number_from_regcache (regs) != -1)
|
| + {
|
| + /* Since we use simple_displaced_step_copy_insn, our closure is a
|
| + copy of the instruction. */
|
| + gdb_byte *insn = (gdb_byte *) closure;
|
| +
|
| + /* Fake nop. */
|
| + insn[0] = 0x90;
|
| + }
|
| +
|
| + return closure;
|
| +}
|
| +
|
| static void
|
| i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
| {
|
| @@ -856,8 +917,9 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
| i386_linux_record_tdep.arg5 = I386_EDI_REGNUM;
|
| i386_linux_record_tdep.arg6 = I386_EBP_REGNUM;
|
|
|
| - tdep->i386_intx80_record = i386_linux_intx80_sysenter_record;
|
| - tdep->i386_sysenter_record = i386_linux_intx80_sysenter_record;
|
| + tdep->i386_intx80_record = i386_linux_intx80_sysenter_syscall_record;
|
| + tdep->i386_sysenter_record = i386_linux_intx80_sysenter_syscall_record;
|
| + tdep->i386_syscall_record = i386_linux_intx80_sysenter_syscall_record;
|
|
|
| /* N_FUN symbols in shared libaries have 0 for their values and need
|
| to be relocated. */
|
| @@ -890,7 +952,7 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
|
|
| /* Displaced stepping. */
|
| set_gdbarch_displaced_step_copy_insn (gdbarch,
|
| - i386_displaced_step_copy_insn);
|
| + i386_linux_displaced_step_copy_insn);
|
| set_gdbarch_displaced_step_fixup (gdbarch, i386_displaced_step_fixup);
|
| set_gdbarch_displaced_step_free_closure (gdbarch,
|
| simple_displaced_step_free_closure);
|
|
|