Introduce PTRACE_GET_SYSCALL_INFO support
When PTRACE_GET_SYSCALL_INFO API works, use it instead of traditional upeek/get_regs API. Tested on x86_64 and x86. * get_personality.c: New file. * get_personality.h: Likewise. * Makefile.am (strace_SOURCES): Add them. * linux/aarch64/arch_get_personality.c: New file. * linux/powerpc64/arch_get_personality.c: Likewise. * linux/riscv/arch_get_personality.c: Likewise. * linux/s390x/arch_get_personality.c: Likewise. * linux/sparc64/arch_get_personality.c: Likewise. * linux/tile/arch_get_personality.c: Likewise. * linux/x32/arch_get_personality.c: Likewise. * linux/x86_64/arch_get_personality.c: Likewise. * linux/check_scno.c: Likewise. * linux/x32/check_scno.c: Likewise. * Makefile.am (EXTRA_DIST): Add them. * linux/ia64/arch_getrval2.c (getrval2): Invoke get_regs() if ptrace_syscall_info is in use. * linux/mips/arch_getrval2.c: Likewise. * linux/sparc/arch_getrval2.c: Likewise. * defs.h (get_personality_from_syscall_info): New prototype. * syscall.c: Include "get_personality.h" and "ptrace_syscall_info.h". (get_regs_error): Define unconditionally. (ptrace_sci): New static variable. (clear_regs): Reset ptrace_sci.op. (ptrace_syscall_info_is_valid, ptrace_get_syscall_info, get_syscall_regs): New functions. (get_syscall_result_regs): Change to get_syscall_regs. (get_instruction_pointer, get_stack_pointer, get_scno, get_syscall_args, get_error, set_error, set_success): Add ptrace_syscall_info support. * tests/int_0x80.test: New test. * tests/Makefile.am (DECODER_TESTS): Add int_0x80.test. (XFAIL_TESTS_x86_64, XFAIL_TESTS_x32): Remove. * tests/gen_tests.in (int_0x80): Remove.
This commit is contained in:
parent
7488ce9e23
commit
e3b80cb65f
14
Makefile.am
14
Makefile.am
@ -134,6 +134,8 @@ strace_SOURCES = \
|
||||
fs_x_ioctl.c \
|
||||
futex.c \
|
||||
gcc_compat.h \
|
||||
get_personality.c \
|
||||
get_personality.h \
|
||||
get_robust_list.c \
|
||||
getcpu.c \
|
||||
getcwd.c \
|
||||
@ -417,6 +419,7 @@ EXTRA_DIST = \
|
||||
linux/64/ioctls_inc.h \
|
||||
linux/64/syscallent.h \
|
||||
linux/aarch64/arch_defs_.h \
|
||||
linux/aarch64/arch_get_personality.c \
|
||||
linux/aarch64/arch_regs.c \
|
||||
linux/aarch64/arch_sigreturn.c \
|
||||
linux/aarch64/get_error.c \
|
||||
@ -505,6 +508,7 @@ EXTRA_DIST = \
|
||||
linux/bfin/set_scno.c \
|
||||
linux/bfin/syscallent.h \
|
||||
linux/bfin/userent.h \
|
||||
linux/check_scno.c \
|
||||
linux/dummy.h \
|
||||
linux/errnoent.h \
|
||||
linux/getregs_old.h \
|
||||
@ -524,8 +528,8 @@ EXTRA_DIST = \
|
||||
linux/hppa/set_scno.c \
|
||||
linux/hppa/signalent.h \
|
||||
linux/hppa/syscallent.h \
|
||||
linux/i386/arch_kvm.c \
|
||||
linux/i386/arch_defs_.h \
|
||||
linux/i386/arch_kvm.c \
|
||||
linux/i386/arch_regs.c \
|
||||
linux/i386/arch_rt_sigframe.c \
|
||||
linux/i386/arch_sigreturn.c \
|
||||
@ -663,6 +667,7 @@ EXTRA_DIST = \
|
||||
linux/powerpc/syscallent.h \
|
||||
linux/powerpc/userent.h \
|
||||
linux/powerpc64/arch_defs_.h \
|
||||
linux/powerpc64/arch_get_personality.c \
|
||||
linux/powerpc64/arch_regs.c \
|
||||
linux/powerpc64/arch_rt_sigframe.c \
|
||||
linux/powerpc64/arch_sigreturn.c \
|
||||
@ -686,6 +691,7 @@ EXTRA_DIST = \
|
||||
linux/ptrace_pokeuser.c \
|
||||
linux/raw_syscall.h \
|
||||
linux/riscv/arch_defs_.h \
|
||||
linux/riscv/arch_get_personality.c \
|
||||
linux/riscv/arch_regs.c \
|
||||
linux/riscv/get_error.c \
|
||||
linux/riscv/get_scno.c \
|
||||
@ -717,6 +723,7 @@ EXTRA_DIST = \
|
||||
linux/s390/userent0.h \
|
||||
linux/s390/userent1.h \
|
||||
linux/s390x/arch_defs_.h \
|
||||
linux/s390x/arch_get_personality.c \
|
||||
linux/s390x/arch_regs.c \
|
||||
linux/s390x/arch_sigreturn.c \
|
||||
linux/s390x/get_error.c \
|
||||
@ -786,6 +793,7 @@ EXTRA_DIST = \
|
||||
linux/sparc/syscallent.h \
|
||||
linux/sparc/userent.h \
|
||||
linux/sparc64/arch_defs_.h \
|
||||
linux/sparc64/arch_get_personality.c \
|
||||
linux/sparc64/arch_getrval2.c \
|
||||
linux/sparc64/arch_regs.c \
|
||||
linux/sparc64/arch_rt_sigframe.c \
|
||||
@ -809,6 +817,7 @@ EXTRA_DIST = \
|
||||
linux/subcall.h \
|
||||
linux/syscall.h \
|
||||
linux/tile/arch_defs_.h \
|
||||
linux/tile/arch_get_personality.c \
|
||||
linux/tile/arch_regs.c \
|
||||
linux/tile/arch_sigreturn.c \
|
||||
linux/tile/get_error.c \
|
||||
@ -829,11 +838,13 @@ EXTRA_DIST = \
|
||||
linux/userent.h \
|
||||
linux/userent0.h \
|
||||
linux/x32/arch_defs_.h \
|
||||
linux/x32/arch_get_personality.c \
|
||||
linux/x32/arch_kvm.c \
|
||||
linux/x32/arch_regs.c \
|
||||
linux/x32/arch_regs.h \
|
||||
linux/x32/arch_rt_sigframe.c \
|
||||
linux/x32/arch_sigreturn.c \
|
||||
linux/x32/check_scno.c \
|
||||
linux/x32/get_error.c \
|
||||
linux/x32/get_scno.c \
|
||||
linux/x32/get_syscall_args.c \
|
||||
@ -851,6 +862,7 @@ EXTRA_DIST = \
|
||||
linux/x32/syscallent1.h \
|
||||
linux/x32/userent.h \
|
||||
linux/x86_64/arch_defs_.h \
|
||||
linux/x86_64/arch_get_personality.c \
|
||||
linux/x86_64/arch_kvm.c \
|
||||
linux/x86_64/arch_regs.c \
|
||||
linux/x86_64/arch_regs.h \
|
||||
|
14
get_personality.c
Normal file
14
get_personality.c
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
#if SUPPORTED_PERSONALITIES > 1
|
||||
# include "get_personality.h"
|
||||
# include <linux/audit.h>
|
||||
# include "arch_get_personality.c"
|
||||
#endif
|
16
get_personality.h
Normal file
16
get_personality.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#ifndef STRACE_GET_PERSONALITY_H
|
||||
#define STRACE_GET_PERSONALITY_H
|
||||
|
||||
#include "ptrace.h"
|
||||
|
||||
extern int
|
||||
get_personality_from_syscall_info(const struct ptrace_syscall_info *);
|
||||
|
||||
#endif /* !STRACE_GET_PERSONALITY_H */
|
16
linux/aarch64/arch_get_personality.c
Normal file
16
linux/aarch64/arch_get_personality.c
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#ifndef AUDIT_ARCH_ARM
|
||||
# define AUDIT_ARCH_ARM 0x40000028
|
||||
#endif
|
||||
|
||||
int
|
||||
get_personality_from_syscall_info(const struct ptrace_syscall_info *sci)
|
||||
{
|
||||
return sci->arch == AUDIT_ARCH_ARM;
|
||||
}
|
6
linux/check_scno.c
Normal file
6
linux/check_scno.c
Normal file
@ -0,0 +1,6 @@
|
||||
/* Return codes: 1 - ok, 0 - ignore, other - error. */
|
||||
static int
|
||||
arch_check_scno(struct tcb *tcp)
|
||||
{
|
||||
return 1;
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
long
|
||||
getrval2(struct tcb *tcp)
|
||||
{
|
||||
if (ptrace_syscall_info_is_valid() && get_regs(tcp) < 0)
|
||||
return -1;
|
||||
return ia64_regs.gr[9];
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
long
|
||||
getrval2(struct tcb *tcp)
|
||||
{
|
||||
if (ptrace_syscall_info_is_valid() && get_regs(tcp) < 0)
|
||||
return -1;
|
||||
return mips_regs.uregs[3];
|
||||
}
|
||||
|
16
linux/powerpc64/arch_get_personality.c
Normal file
16
linux/powerpc64/arch_get_personality.c
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#ifndef AUDIT_ARCH_PPC
|
||||
# define AUDIT_ARCH_PPC 0x14
|
||||
#endif
|
||||
|
||||
int
|
||||
get_personality_from_syscall_info(const struct ptrace_syscall_info *sci)
|
||||
{
|
||||
return sci->arch == AUDIT_ARCH_PPC;
|
||||
}
|
16
linux/riscv/arch_get_personality.c
Normal file
16
linux/riscv/arch_get_personality.c
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#ifndef AUDIT_ARCH_RISCV32
|
||||
# define AUDIT_ARCH_RISCV32 0x400000f3
|
||||
#endif
|
||||
|
||||
int
|
||||
get_personality_from_syscall_info(const struct ptrace_syscall_info *sci)
|
||||
{
|
||||
return sci->arch == AUDIT_ARCH_RISCV32;
|
||||
}
|
16
linux/s390x/arch_get_personality.c
Normal file
16
linux/s390x/arch_get_personality.c
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#ifndef AUDIT_ARCH_S390
|
||||
# define AUDIT_ARCH_S390 0x16
|
||||
#endif
|
||||
|
||||
int
|
||||
get_personality_from_syscall_info(const struct ptrace_syscall_info *sci)
|
||||
{
|
||||
return sci->arch == AUDIT_ARCH_S390;
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
long
|
||||
getrval2(struct tcb *tcp)
|
||||
{
|
||||
if (ptrace_syscall_info_is_valid() && get_regs(tcp) < 0)
|
||||
return -1;
|
||||
return sparc_regs.u_regs[U_REG_O1];
|
||||
}
|
||||
|
16
linux/sparc64/arch_get_personality.c
Normal file
16
linux/sparc64/arch_get_personality.c
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#ifndef AUDIT_ARCH_SPARC
|
||||
# define AUDIT_ARCH_SPARC 0x2
|
||||
#endif
|
||||
|
||||
int
|
||||
get_personality_from_syscall_info(const struct ptrace_syscall_info *sci)
|
||||
{
|
||||
return sci->arch == AUDIT_ARCH_SPARC;
|
||||
}
|
20
linux/tile/arch_get_personality.c
Normal file
20
linux/tile/arch_get_personality.c
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#ifndef AUDIT_ARCH_TILEGX32
|
||||
# define AUDIT_ARCH_TILEGX32 0x400000bf
|
||||
#endif
|
||||
#ifndef AUDIT_ARCH_TILEPRO
|
||||
# define AUDIT_ARCH_TILEPRO 0x400000bc
|
||||
#endif
|
||||
|
||||
int
|
||||
get_personality_from_syscall_info(const struct ptrace_syscall_info *sci)
|
||||
{
|
||||
return sci->arch == AUDIT_ARCH_TILEGX32 ||
|
||||
sci->arch == AUDIT_ARCH_TILEPRO;
|
||||
}
|
1
linux/x32/arch_get_personality.c
Normal file
1
linux/x32/arch_get_personality.c
Normal file
@ -0,0 +1 @@
|
||||
#include "x86_64/arch_get_personality.c"
|
22
linux/x32/check_scno.c
Normal file
22
linux/x32/check_scno.c
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2018 The strace developers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
/* Return codes: 1 - ok, 0 - ignore, other - error. */
|
||||
static int
|
||||
arch_check_scno(struct tcb *tcp)
|
||||
{
|
||||
|
||||
const kernel_ulong_t scno = ptrace_sci.entry.nr;
|
||||
|
||||
if (tcp->currpers == 0 && !(scno & __X32_SYSCALL_BIT)) {
|
||||
error_msg("syscall_%" PRI_klu "(...) in unsupported "
|
||||
"64-bit mode of process PID=%d", scno, tcp->pid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
47
linux/x86_64/arch_get_personality.c
Normal file
47
linux/x86_64/arch_get_personality.c
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2018 The strace developers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#ifndef AUDIT_ARCH_I386
|
||||
# define AUDIT_ARCH_I386 0x40000003
|
||||
#endif
|
||||
|
||||
int
|
||||
get_personality_from_syscall_info(const struct ptrace_syscall_info *sci)
|
||||
{
|
||||
unsigned int pers = sci->arch == AUDIT_ARCH_I386;
|
||||
|
||||
#ifndef X32
|
||||
switch(sci->op) {
|
||||
case PTRACE_SYSCALL_INFO_ENTRY:
|
||||
case PTRACE_SYSCALL_INFO_SECCOMP:
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
kernel_ulong_t scno = sci->entry.nr;
|
||||
|
||||
#ifndef __X32_SYSCALL_BIT
|
||||
# define __X32_SYSCALL_BIT 0x40000000
|
||||
#endif
|
||||
|
||||
if (pers == 0 && (scno & __X32_SYSCALL_BIT)) {
|
||||
/*
|
||||
* Syscall number -1 requires special treatment:
|
||||
* it might be a side effect of SECCOMP_RET_ERRNO
|
||||
* filtering that sets orig_rax to -1
|
||||
* in some versions of linux kernel.
|
||||
* If that is the case, then
|
||||
* __X32_SYSCALL_BIT logic does not apply.
|
||||
*/
|
||||
if (scno != (kernel_ulong_t) -1)
|
||||
pers = 2;
|
||||
}
|
||||
#endif /* !X32 */
|
||||
|
||||
return pers;
|
||||
}
|
155
syscall.c
155
syscall.c
@ -13,9 +13,11 @@
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include "get_personality.h"
|
||||
#include "mmap_notify.h"
|
||||
#include "native_defs.h"
|
||||
#include "ptrace.h"
|
||||
#include "ptrace_syscall_info.h"
|
||||
#include "nsig.h"
|
||||
#include "number_set.h"
|
||||
#include "delay.h"
|
||||
@ -461,6 +463,7 @@ static void get_error(struct tcb *, bool);
|
||||
static void set_error(struct tcb *, unsigned long);
|
||||
static void set_success(struct tcb *, kernel_long_t);
|
||||
static int arch_get_scno(struct tcb *);
|
||||
static int arch_check_scno(struct tcb *);
|
||||
static int arch_set_scno(struct tcb *, kernel_ulong_t);
|
||||
static int arch_get_syscall_args(struct tcb *);
|
||||
static void arch_get_error(struct tcb *, bool);
|
||||
@ -943,11 +946,21 @@ restore_cleared_syserror(struct tcb *tcp)
|
||||
tcp->u_error = saved_u_error;
|
||||
}
|
||||
|
||||
static struct ptrace_syscall_info ptrace_sci;
|
||||
|
||||
static bool
|
||||
ptrace_syscall_info_is_valid(void)
|
||||
{
|
||||
return ptrace_get_syscall_info_supported &&
|
||||
ptrace_sci.op <= PTRACE_SYSCALL_INFO_SECCOMP;
|
||||
}
|
||||
|
||||
#define XLAT_MACROS_ONLY
|
||||
# include "xlat/nt_descriptor_types.h"
|
||||
#undef XLAT_MACROS_ONLY
|
||||
|
||||
#define ARCH_MIGHT_USE_SET_REGS 1
|
||||
|
||||
#include "arch_regs.c"
|
||||
|
||||
#if HAVE_ARCH_GETRVAL2
|
||||
@ -1035,16 +1048,13 @@ ptrace_setregs(pid_t pid)
|
||||
|
||||
#endif /* ARCH_REGS_FOR_GETREGSET || ARCH_REGS_FOR_GETREGS */
|
||||
|
||||
#ifdef ptrace_getregset_or_getregs
|
||||
static long get_regs_error;
|
||||
#endif
|
||||
static long get_regs_error = -1;
|
||||
|
||||
void
|
||||
clear_regs(struct tcb *tcp)
|
||||
{
|
||||
#ifdef ptrace_getregset_or_getregs
|
||||
ptrace_sci.op = 0xff;
|
||||
get_regs_error = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static long
|
||||
@ -1139,9 +1149,59 @@ free_sysent_buf(void *ptr)
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
static bool
|
||||
ptrace_get_syscall_info(struct tcb *tcp)
|
||||
{
|
||||
/*
|
||||
* ptrace_get_syscall_info_supported should have been checked
|
||||
* by the caller.
|
||||
*/
|
||||
if (ptrace_sci.op == 0xff) {
|
||||
const size_t size = sizeof(ptrace_sci);
|
||||
if (ptrace(PTRACE_GET_SYSCALL_INFO, tcp->pid,
|
||||
(void *) size, &ptrace_sci) < 0) {
|
||||
get_regs_error = -2;
|
||||
return false;
|
||||
}
|
||||
#if SUPPORTED_PERSONALITIES > 1
|
||||
int newpers = get_personality_from_syscall_info(&ptrace_sci);
|
||||
if (newpers >= 0)
|
||||
update_personality(tcp, newpers);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (entering(tcp)) {
|
||||
if (ptrace_sci.op == PTRACE_SYSCALL_INFO_EXIT) {
|
||||
error_msg("pid %d: entering"
|
||||
", ptrace_syscall_info.op == %u",
|
||||
tcp->pid, ptrace_sci.op);
|
||||
/* TODO: handle this. */
|
||||
}
|
||||
} else {
|
||||
if (ptrace_sci.op == PTRACE_SYSCALL_INFO_ENTRY) {
|
||||
error_msg("pid %d: exiting"
|
||||
", ptrace_syscall_info.op == %u",
|
||||
tcp->pid, ptrace_sci.op);
|
||||
/* TODO: handle this. */
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
get_instruction_pointer(struct tcb *tcp, kernel_ulong_t *ip)
|
||||
{
|
||||
if (get_regs_error < -1)
|
||||
return false;
|
||||
|
||||
if (ptrace_get_syscall_info_supported) {
|
||||
if (!ptrace_get_syscall_info(tcp))
|
||||
return false;
|
||||
*ip = (kernel_ulong_t) ptrace_sci.instruction_pointer;
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined ARCH_PC_REG
|
||||
if (get_regs(tcp) < 0)
|
||||
return false;
|
||||
@ -1159,6 +1219,16 @@ get_instruction_pointer(struct tcb *tcp, kernel_ulong_t *ip)
|
||||
bool
|
||||
get_stack_pointer(struct tcb *tcp, kernel_ulong_t *sp)
|
||||
{
|
||||
if (get_regs_error < -1)
|
||||
return false;
|
||||
|
||||
if (ptrace_get_syscall_info_supported) {
|
||||
if (!ptrace_get_syscall_info(tcp))
|
||||
return false;
|
||||
*sp = (kernel_ulong_t) ptrace_sci.stack_pointer;
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined ARCH_SP_REG
|
||||
if (get_regs(tcp) < 0)
|
||||
return false;
|
||||
@ -1173,6 +1243,18 @@ get_stack_pointer(struct tcb *tcp, kernel_ulong_t *sp)
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
get_syscall_regs(struct tcb *tcp)
|
||||
{
|
||||
if (get_regs_error != -1)
|
||||
return get_regs_error;
|
||||
|
||||
if (ptrace_get_syscall_info_supported)
|
||||
return ptrace_get_syscall_info(tcp) ? 0 : get_regs_error;
|
||||
|
||||
return get_regs(tcp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* 0: "ignore this ptrace stop", syscall_entering_decode() should return a "bail
|
||||
@ -1184,12 +1266,23 @@ get_stack_pointer(struct tcb *tcp, kernel_ulong_t *sp)
|
||||
int
|
||||
get_scno(struct tcb *tcp)
|
||||
{
|
||||
if (get_regs(tcp) < 0)
|
||||
if (get_syscall_regs(tcp) < 0)
|
||||
return -1;
|
||||
|
||||
if (ptrace_syscall_info_is_valid()) {
|
||||
/*
|
||||
* So far it's just a workaround for x32,
|
||||
* but let's pretend it could be used elsewhere.
|
||||
*/
|
||||
int rc = arch_check_scno(tcp);
|
||||
if (rc != 1)
|
||||
return rc;
|
||||
tcp->scno = ptrace_sci.entry.nr;
|
||||
} else {
|
||||
int rc = arch_get_scno(tcp);
|
||||
if (rc != 1)
|
||||
return rc;
|
||||
}
|
||||
|
||||
tcp->scno = shuffle_scno(tcp->scno);
|
||||
|
||||
@ -1229,11 +1322,22 @@ get_scno(struct tcb *tcp)
|
||||
static int
|
||||
get_syscall_args(struct tcb *tcp)
|
||||
{
|
||||
if (ptrace_syscall_info_is_valid()) {
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(tcp->u_arg); ++i)
|
||||
tcp->u_arg[i] = ptrace_sci.entry.args[i];
|
||||
#if SUPPORTED_PERSONALITIES > 1
|
||||
if (tcp->s_ent->sys_flags & COMPAT_SYSCALL_TYPES) {
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(tcp->u_arg); ++i)
|
||||
tcp->u_arg[i] = (uint32_t) tcp->u_arg[i];
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
return arch_get_syscall_args(tcp);
|
||||
}
|
||||
|
||||
#ifdef ptrace_getregset_or_getregs
|
||||
# define get_syscall_result_regs get_regs
|
||||
# define get_syscall_result_regs get_syscall_regs
|
||||
#else
|
||||
static int get_syscall_result_regs(struct tcb *);
|
||||
#endif
|
||||
@ -1259,8 +1363,18 @@ get_syscall_result(struct tcb *tcp)
|
||||
static void
|
||||
get_error(struct tcb *tcp, const bool check_errno)
|
||||
{
|
||||
if (ptrace_syscall_info_is_valid()) {
|
||||
if (ptrace_sci.exit.is_error) {
|
||||
tcp->u_rval = -1;
|
||||
tcp->u_error = -ptrace_sci.exit.rval;
|
||||
} else {
|
||||
tcp->u_error = 0;
|
||||
tcp->u_rval = ptrace_sci.exit.rval;
|
||||
}
|
||||
} else {
|
||||
tcp->u_error = 0;
|
||||
arch_get_error(tcp, check_errno);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1271,12 +1385,22 @@ set_error(struct tcb *tcp, unsigned long new_error)
|
||||
if (new_error == old_error || new_error > MAX_ERRNO_VALUE)
|
||||
return;
|
||||
|
||||
#ifdef ptrace_setregset_or_setregs
|
||||
/* if we are going to invoke set_regs, call get_regs first */
|
||||
if (get_regs(tcp) < 0)
|
||||
return;
|
||||
#endif
|
||||
|
||||
tcp->u_error = new_error;
|
||||
if (arch_set_error(tcp)) {
|
||||
tcp->u_error = old_error;
|
||||
/* arch_set_error does not update u_rval */
|
||||
} else {
|
||||
get_error(tcp, !(tcp->s_ent->sys_flags & SYSCALL_NEVER_FAILS));
|
||||
if (ptrace_syscall_info_is_valid())
|
||||
tcp->u_rval = -1;
|
||||
else
|
||||
get_error(tcp, !(tcp->s_ent->sys_flags &
|
||||
SYSCALL_NEVER_FAILS));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1285,16 +1409,27 @@ set_success(struct tcb *tcp, kernel_long_t new_rval)
|
||||
{
|
||||
const kernel_long_t old_rval = tcp->u_rval;
|
||||
|
||||
#ifdef ptrace_setregset_or_setregs
|
||||
/* if we are going to invoke set_regs, call get_regs first */
|
||||
if (get_regs(tcp) < 0)
|
||||
return;
|
||||
#endif
|
||||
|
||||
tcp->u_rval = new_rval;
|
||||
if (arch_set_success(tcp)) {
|
||||
tcp->u_rval = old_rval;
|
||||
/* arch_set_error does not update u_error */
|
||||
/* arch_set_success does not update u_error */
|
||||
} else {
|
||||
get_error(tcp, !(tcp->s_ent->sys_flags & SYSCALL_NEVER_FAILS));
|
||||
if (ptrace_syscall_info_is_valid())
|
||||
tcp->u_error = 0;
|
||||
else
|
||||
get_error(tcp, !(tcp->s_ent->sys_flags &
|
||||
SYSCALL_NEVER_FAILS));
|
||||
}
|
||||
}
|
||||
|
||||
#include "get_scno.c"
|
||||
#include "check_scno.c"
|
||||
#include "set_scno.c"
|
||||
#include "get_syscall_args.c"
|
||||
#ifndef ptrace_getregset_or_getregs
|
||||
|
@ -228,6 +228,7 @@ DECODER_TESTS = \
|
||||
fadvise64.test \
|
||||
futex.test \
|
||||
getuid.test \
|
||||
int_0x80.test \
|
||||
ioctl.test \
|
||||
ioctl_evdev-success.test \
|
||||
ioctl_evdev-success-v.test \
|
||||
@ -347,8 +348,6 @@ TESTS = $(GEN_TESTS) $(DECODER_TESTS) $(MISC_TESTS) $(STACKTRACE_TESTS)
|
||||
XFAIL_TESTS_ =
|
||||
XFAIL_TESTS_m32 = $(STACKTRACE_TESTS)
|
||||
XFAIL_TESTS_mx32 = $(STACKTRACE_TESTS)
|
||||
XFAIL_TESTS_x86_64 = int_0x80.gen.test
|
||||
XFAIL_TESTS_x32 = int_0x80.gen.test
|
||||
XFAIL_TESTS = $(XFAIL_TESTS_$(MPERS_NAME)) $(XFAIL_TESTS_$(ARCH))
|
||||
|
||||
TEST_LOG_COMPILER = env
|
||||
|
@ -118,7 +118,6 @@ inet-cmsg -e trace=recvmsg
|
||||
init_module -a27
|
||||
inotify -a23 -e trace=inotify_add_watch,inotify_rm_watch
|
||||
inotify_init1 -a27
|
||||
int_0x80 -a11 -e trace=getgid32
|
||||
ioctl_block +ioctl.test
|
||||
ioctl_dm +ioctl.test -s9
|
||||
ioctl_dm-v +ioctl.test -v -s9
|
||||
|
11
tests/int_0x80.test
Executable file
11
tests/int_0x80.test
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Check decoding of int 0x80 on x86_64, x32, and x86.
|
||||
|
||||
. "${srcdir=.}/init.sh"
|
||||
|
||||
$STRACE -d -enone / > /dev/null 2> "$LOG"
|
||||
grep -x "[^:]*strace: PTRACE_GET_SYSCALL_INFO works" "$LOG" > /dev/null ||
|
||||
skip_ 'PTRACE_GET_SYSCALL_INFO does not work'
|
||||
|
||||
run_strace_match_diff -a11 -e trace=getgid32
|
Loading…
Reference in New Issue
Block a user