gdb/
Fix disp-step-syscall.exp: fork: single step over fork. * i386-linux-tdep.c (-i386_linux_get_syscall_number): Rename to ... (i386_linux_get_syscall_number_from_regcache): ... here, new function comment, change parameters gdbarch and ptid to regcache. Remove parameter regcache, initialize gdbarch from regcache here. (i386_linux_get_syscall_number, i386_linux_displaced_step_copy_insn): New functions. (i386_linux_init_abi): Install i386_linux_displaced_step_copy_insn instead. * i386-tdep.c (i386_syscall_p): Check also for 'sysenter' and 'syscall'. Make the 'int' check more strict. gdb/testsuite/ Fix disp-step-syscall.exp: fork: single step over fork. * gdb.base/disp-step-syscall.exp (syscall_insn): Anchor it by whitespaces. (single step over $syscall): Remove its check. (single step over $syscall final pc): New check.
This commit is contained in:
parent
ffdf6de517
commit
9a7f938f93
5 changed files with 104 additions and 7 deletions
|
@ -1,3 +1,17 @@
|
|||
2012-02-29 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
Fix disp-step-syscall.exp: fork: single step over fork.
|
||||
* i386-linux-tdep.c (-i386_linux_get_syscall_number): Rename to ...
|
||||
(i386_linux_get_syscall_number_from_regcache): ... here, new function
|
||||
comment, change parameters gdbarch and ptid to regcache. Remove
|
||||
parameter regcache, initialize gdbarch from regcache here.
|
||||
(i386_linux_get_syscall_number, i386_linux_displaced_step_copy_insn):
|
||||
New functions.
|
||||
(i386_linux_init_abi): Install i386_linux_displaced_step_copy_insn
|
||||
instead.
|
||||
* i386-tdep.c (i386_syscall_p): Check also for 'sysenter' and
|
||||
'syscall'. Make the 'int' check more strict.
|
||||
|
||||
2012-02-29 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
Fix reverse mode for syscall on AMD CPUs in 32-bit mode.
|
||||
|
|
|
@ -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. */
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -891,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);
|
||||
|
|
|
@ -521,7 +521,12 @@ i386_call_p (const gdb_byte *insn)
|
|||
static int
|
||||
i386_syscall_p (const gdb_byte *insn, int *lengthp)
|
||||
{
|
||||
if (insn[0] == 0xcd)
|
||||
/* Is it 'int $0x80'? */
|
||||
if ((insn[0] == 0xcd && insn[1] == 0x80)
|
||||
/* Or is it 'sysenter'? */
|
||||
|| (insn[0] == 0x0f && insn[1] == 0x34)
|
||||
/* Or is it 'syscall'? */
|
||||
|| (insn[0] == 0x0f && insn[1] == 0x05))
|
||||
{
|
||||
*lengthp = 2;
|
||||
return 1;
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
2012-02-29 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
Fix disp-step-syscall.exp: fork: single step over fork.
|
||||
* gdb.base/disp-step-syscall.exp (syscall_insn): Anchor it by
|
||||
whitespaces.
|
||||
(single step over $syscall): Remove its check.
|
||||
(single step over $syscall final pc): New check.
|
||||
|
||||
2012-02-29 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
Support processors without SSSE3.
|
||||
|
|
|
@ -25,7 +25,7 @@ set syscall_insn ""
|
|||
# Define the syscall instruction for each target.
|
||||
|
||||
if { [istarget "i\[34567\]86-*-linux*"] || [istarget "x86_64-*-linux*"] } {
|
||||
set syscall_insn "(int|syscall|sysenter)"
|
||||
set syscall_insn "\[ \t\](int|syscall|sysenter)\[ \t\]"
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
|
@ -118,7 +118,16 @@ proc disp_step_cross_syscall { syscall } { with_test_prefix "$syscall" {
|
|||
gdb_test_no_output "set displaced-stepping on"
|
||||
|
||||
# Check the address of next instruction of syscall.
|
||||
gdb_test "stepi" ".*$syscall_insn_next_addr.*" "single step over $syscall"
|
||||
gdb_test "stepi" ".*" "single step over $syscall"
|
||||
set syscall_insn_next_addr_found [get_hexadecimal_valueof "\$pc" "0"]
|
||||
|
||||
set test "single step over $syscall final pc"
|
||||
if {$syscall_insn_next_addr != 0
|
||||
&& $syscall_insn_next_addr == $syscall_insn_next_addr_found} {
|
||||
pass $test
|
||||
} else {
|
||||
fail $test
|
||||
}
|
||||
|
||||
# Delete breakpoint syscall insns to avoid interference to other syscalls.
|
||||
gdb_test_no_output "delete $syscall_insn_bp" "delete break $syscall insn"
|
||||
|
|
Loading…
Add table
Reference in a new issue