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:
Jan Kratochvil 2012-02-29 14:59:41 +00:00
parent ffdf6de517
commit 9a7f938f93
5 changed files with 104 additions and 7 deletions

View File

@ -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.

View File

@ -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);

View File

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

View File

@ -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.

View File

@ -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"