Implement success injection
This extends fault injection syntax with :retval= option. When :retval=VALUE is specified, the syscall number is replaced by -1 and a bogus success VALUE is returned to the callee. * defs.h (fault_opts): Remove err field, add rval field. (MAX_ERRNO_VALUE, FAULT_OPTS_RVAL_DEFAULT, FAULT_OPTS_RVAL_DISABLE): New macros. * qualify.c (parse_fault_token): Handle retval= token. (qualify_fault): Update fault_opts initialization after the move from struct fault_opts.err to struct fault_opts.rval. * syscall.c (arch_set_success): New prototype. (inject_syscall_fault_entering): Check opts->rval instead of opts->err. (update_syscall_fault_exiting): Implement retval injection. * strace.1: Update the section on fault injection. * NEWS: Mention retval= option. * linux/aarch64/set_error.c (arch_set_success): New function. * linux/alpha/set_error.c: Likewise. * linux/arc/set_error.c: Likewise. * linux/arm/set_error.c: Likewise. * linux/avr32/set_error.c: Likewise. * linux/bfin/set_error.c: Likewise. * linux/crisv10/set_error.c: Likewise. * linux/hppa/set_error.c: Likewise. * linux/i386/set_error.c: Likewise. * linux/ia64/set_error.c: Likewise. * linux/m68k/set_error.c: Likewise. * linux/metag/set_error.c: Likewise. * linux/microblaze/set_error.c: Likewise. * linux/mips/set_error.c: Likewise. * linux/nios2/set_error.c: Likewise. * linux/or1k/set_error.c: Likewise. * linux/powerpc/set_error.c: Likewise. * linux/riscv/set_error.c: Likewise. * linux/s390/set_error.c: Likewise. * linux/sh/set_error.c: Likewise. * linux/sh64/set_error.c: Likewise. * linux/sparc/set_error.c: Likewise. * linux/sparc64/set_error.c: Likewise. * linux/tile/set_error.c: Likewise. * linux/x86_64/set_error.c: Likewise. * linux/xtensa/set_error.c: Likewise. Closes: https://github.com/strace/strace/issues/3
This commit is contained in:
parent
a0795c594a
commit
41d647ce67
2
NEWS
2
NEWS
@ -2,7 +2,7 @@ Noteworthy changes in release ?.?? (????-??-??)
|
||||
===============================================
|
||||
|
||||
* Improvements
|
||||
* Implemented signal injection as an extension to syscall fault injection.
|
||||
* Extended fault injection syntax with signal= and retval= options.
|
||||
|
||||
Noteworthy changes in release 4.15 (2016-12-14)
|
||||
===============================================
|
||||
|
6
defs.h
6
defs.h
@ -200,10 +200,14 @@ typedef struct ioctlent {
|
||||
struct fault_opts {
|
||||
uint16_t first;
|
||||
uint16_t step;
|
||||
int16_t err;
|
||||
uint16_t signo;
|
||||
int rval;
|
||||
};
|
||||
|
||||
#define MAX_ERRNO_VALUE 4095
|
||||
#define FAULT_OPTS_RVAL_DEFAULT (-(MAX_ERRNO_VALUE + 1))
|
||||
#define FAULT_OPTS_RVAL_DISABLE (FAULT_OPTS_RVAL_DEFAULT - 1)
|
||||
|
||||
/* Trace Control Block */
|
||||
struct tcb {
|
||||
int flags; /* See below for TCB_ values */
|
||||
|
@ -1,5 +1,7 @@
|
||||
#define arch_set_error arm_set_error
|
||||
#define arch_set_success arm_set_success
|
||||
#include "arm/set_error.c"
|
||||
#undef arch_set_success
|
||||
#undef arch_set_error
|
||||
|
||||
static int
|
||||
@ -11,3 +13,13 @@ arch_set_error(struct tcb *tcp)
|
||||
aarch64_regs.regs[0] = -tcp->u_error;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
if (aarch64_io.iov_len == sizeof(arm_regs))
|
||||
return arm_set_success(tcp);
|
||||
|
||||
aarch64_regs.regs[0] = tcp->u_rval;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
@ -4,3 +4,10 @@ arch_set_error(struct tcb *tcp)
|
||||
alpha_r0 = tcp->u_error;
|
||||
return upoke(tcp->pid, REG_R0, alpha_r0);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
return upoke(tcp->pid, REG_A3, (alpha_a3 = 0))
|
||||
|| upoke(tcp->pid, REG_R0, (alpha_r0 = tcp->u_rval));
|
||||
}
|
||||
|
@ -4,3 +4,10 @@ arch_set_error(struct tcb *tcp)
|
||||
arc_regs.scratch.r0 = -tcp->u_error;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
arc_regs.scratch.r0 = tcp->u_rval;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
@ -4,3 +4,10 @@ arch_set_error(struct tcb *tcp)
|
||||
arm_regs.ARM_r0 = -tcp->u_error;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
arm_regs.ARM_r0 = tcp->u_rval;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
@ -4,3 +4,10 @@ arch_set_error(struct tcb *tcp)
|
||||
avr32_regs.r12 = -tcp->u_error;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
avr32_regs.r12 = tcp->u_rval;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
@ -4,3 +4,10 @@ arch_set_error(struct tcb *tcp)
|
||||
bfin_r0 = -tcp->u_error;
|
||||
return upoke(tcp->pid, PT_R0, bfin_r0);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
bfin_r0 = tcp->u_rval;
|
||||
return upoke(tcp->pid, PT_R0, bfin_r0);
|
||||
}
|
||||
|
@ -4,3 +4,10 @@ arch_set_error(struct tcb *tcp)
|
||||
cris_r10 = -tcp->u_error;
|
||||
return upoke(tcp->pid, 4 * PT_R10, cris_r10);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
cris_r10 = tcp->u_rval;
|
||||
return upoke(tcp->pid, 4 * PT_R10, cris_r10);
|
||||
}
|
||||
|
@ -4,3 +4,10 @@ arch_set_error(struct tcb *tcp)
|
||||
hppa_r28 = -tcp->u_error;
|
||||
return upoke(tcp->pid, PT_GR28, hppa_r28);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
hppa_r28 = tcp->u_rval;
|
||||
return upoke(tcp->pid, PT_GR28, hppa_r28);
|
||||
}
|
||||
|
@ -8,3 +8,14 @@ arch_set_error(struct tcb *tcp)
|
||||
return set_regs(tcp->pid);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
i386_regs.eax = tcp->u_rval;
|
||||
#ifdef HAVE_GETREGS_OLD
|
||||
return upoke(tcp->pid, 4 * EAX, i386_regs.eax);
|
||||
#else
|
||||
return set_regs(tcp->pid);
|
||||
#endif
|
||||
}
|
||||
|
@ -9,3 +9,13 @@ arch_set_error(struct tcb *tcp)
|
||||
}
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
ia64_regs.gr[8] = tcp->u_rval;
|
||||
if (!ia64_ia32mode) {
|
||||
ia64_regs.gr[10] = 0;
|
||||
}
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
@ -4,3 +4,10 @@ arch_set_error(struct tcb *tcp)
|
||||
m68k_regs.d0 = -tcp->u_error;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
m68k_regs.d0 = tcp->u_rval;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
@ -4,3 +4,10 @@ arch_set_error(struct tcb *tcp)
|
||||
metag_regs.dx[0][0] = -tcp->u_error;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
metag_regs.dx[0][0] = tcp->u_rval;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
@ -4,3 +4,10 @@ arch_set_error(struct tcb *tcp)
|
||||
microblaze_r3 = -tcp->u_error;
|
||||
return upoke(tcp->pid, 3 * 4, microblaze_r3);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
microblaze_r3 = tcp->u_rval;
|
||||
return upoke(tcp->pid, 3 * 4, microblaze_r3);
|
||||
}
|
||||
|
@ -5,3 +5,11 @@ arch_set_error(struct tcb *tcp)
|
||||
mips_REG_A3 = -1;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
mips_REG_V0 = tcp->u_rval;
|
||||
mips_REG_A3 = 0;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
@ -5,3 +5,11 @@ arch_set_error(struct tcb *tcp)
|
||||
nios2_regs.regs[2] = -tcp->u_error;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
nios2_regs.regs[7] = 0;
|
||||
nios2_regs.regs[2] = tcp->u_rval;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
@ -4,3 +4,10 @@ arch_set_error(struct tcb *tcp)
|
||||
or1k_regs.gpr[11] = -tcp->u_error;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_setsuccess(struct tcb *tcp)
|
||||
{
|
||||
or1k_regs.gpr[11] = tcp->u_rval;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
@ -8,3 +8,16 @@ arch_set_error(struct tcb *tcp)
|
||||
return set_regs(tcp->pid);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
ppc_regs.gpr[3] = tcp->u_rval;
|
||||
ppc_regs.ccr &= ~0x10000000;
|
||||
#ifdef HAVE_GETREGS_OLD
|
||||
return upoke(tcp->pid, sizeof(long) * PT_CCR, ppc_regs.ccr) ||
|
||||
upoke(tcp->pid, sizeof(long) * (PT_R0 + 3), ppc_regs.gpr[3]);
|
||||
#else
|
||||
return set_regs(tcp->pid);
|
||||
#endif
|
||||
}
|
||||
|
@ -4,3 +4,10 @@ arch_set_error(struct tcb *tcp)
|
||||
riscv_regs.a0 = -tcp->u_error;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
riscv_regs.a0 = tcp->u_rval;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
@ -4,3 +4,10 @@ arch_set_error(struct tcb *tcp)
|
||||
s390_regset.gprs[2] = -tcp->u_error;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
s390_regset.gprs[2] = tcp->u_rval;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
@ -4,3 +4,10 @@ arch_set_error(struct tcb *tcp)
|
||||
sh_r0 = -tcp->u_error;
|
||||
return upoke(tcp->pid, 4 * REG_REG0, sh_r0);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
sh_r0 = tcp->u_rval;
|
||||
return upoke(tcp->pid, 4 * REG_REG0, sh_r0);
|
||||
}
|
||||
|
@ -4,3 +4,10 @@ arch_set_error(struct tcb *tcp)
|
||||
sh64_r9 = -tcp->u_error;
|
||||
return upoke(tcp->pid, REG_GENERAL(9), sh64_r9);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
sh64_r9 = tcp->u_rval;
|
||||
return upoke(tcp->pid, REG_GENERAL(9), sh64_r9);
|
||||
}
|
||||
|
@ -5,3 +5,11 @@ arch_set_error(struct tcb *tcp)
|
||||
sparc_regs.u_regs[U_REG_O0] = tcp->u_error;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
sparc_regs.psr &= ~PSR_C;
|
||||
sparc_regs.u_regs[U_REG_O0] = tcp->u_rval;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
@ -5,3 +5,11 @@ arch_set_error(struct tcb *tcp)
|
||||
sparc_regs.u_regs[U_REG_O0] = tcp->u_error;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
sparc_regs.tstate &= ~0x1100000000UL;
|
||||
sparc_regs.u_regs[U_REG_O0] = tcp->u_rval;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
@ -4,3 +4,10 @@ arch_set_error(struct tcb *tcp)
|
||||
tile_regs.regs[0] = -tcp->u_error;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
tile_regs.regs[0] = tcp->u_rval;
|
||||
return set_regs(tcp->pid);
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef HAVE_GETREGS_OLD
|
||||
# define arch_set_error i386_set_error
|
||||
# define arch_set_success i386_set_success
|
||||
# include "i386/set_error.c"
|
||||
# undef arch_set_success
|
||||
# undef arch_set_error
|
||||
#endif /* !HAVE_GETREGS_OLD */
|
||||
|
||||
@ -18,3 +20,18 @@ arch_set_error(struct tcb *tcp)
|
||||
return set_regs(tcp->pid);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
#ifdef HAVE_GETREGS_OLD
|
||||
x86_64_regs.rax = (long long) tcp->u_rval;
|
||||
return upoke(tcp->pid, 8 * RAX, x86_64_regs.rax);
|
||||
#else
|
||||
if (x86_io.iov_len == sizeof(i386_regs))
|
||||
return i386_set_success(tcp);
|
||||
|
||||
x86_64_regs.rax = (long long) tcp->u_rval;
|
||||
return set_regs(tcp->pid);
|
||||
#endif
|
||||
}
|
||||
|
@ -4,3 +4,10 @@ arch_set_error(struct tcb *tcp)
|
||||
xtensa_a2 = -tcp->u_error;
|
||||
return upoke(tcp->pid, REG_A_BASE + 2, xtensa_a2);
|
||||
}
|
||||
|
||||
static int
|
||||
arch_set_success(struct tcb *tcp)
|
||||
{
|
||||
xtensa_a2 = tcp->u_rval;
|
||||
return upoke(tcp->pid, REG_A_BASE + 2, xtensa_a2);
|
||||
}
|
||||
|
24
qualify.c
24
qualify.c
@ -409,12 +409,21 @@ parse_fault_token(const char *const token, struct fault_opts *const fopts)
|
||||
fopts->step = 0;
|
||||
}
|
||||
} else if ((val = strip_prefix("error=", token))) {
|
||||
intval = string_to_uint_upto(val, 4095);
|
||||
if (fopts->rval != FAULT_OPTS_RVAL_DEFAULT)
|
||||
return false;
|
||||
intval = string_to_uint_upto(val, MAX_ERRNO_VALUE);
|
||||
if (intval < 0)
|
||||
intval = find_errno_by_name(val);
|
||||
if (intval < 1)
|
||||
return false;
|
||||
fopts->err = intval;
|
||||
fopts->rval = -intval;
|
||||
} else if ((val = strip_prefix("retval=", token))) {
|
||||
if (fopts->rval != FAULT_OPTS_RVAL_DEFAULT)
|
||||
return false;
|
||||
intval = string_to_uint(val);
|
||||
if (intval < 0)
|
||||
return false;
|
||||
fopts->rval = intval;
|
||||
} else if ((val = strip_prefix("signal=", token))) {
|
||||
intval = sigstr_to_uint(val);
|
||||
if (intval < 1 || intval > NSIG_BYTES * 8)
|
||||
@ -500,7 +509,7 @@ qualify_fault(const char *const str)
|
||||
struct fault_opts opts = {
|
||||
.first = 1,
|
||||
.step = 1,
|
||||
.err = -1,
|
||||
.rval = FAULT_OPTS_RVAL_DEFAULT,
|
||||
.signo = 0
|
||||
};
|
||||
char *buf = NULL;
|
||||
@ -510,11 +519,12 @@ qualify_fault(const char *const str)
|
||||
}
|
||||
|
||||
/*
|
||||
* If neither error nor signal is specified,
|
||||
* fallback to the default platform error code.
|
||||
* If signal is specified but neither retval nor error are specified,
|
||||
* disable syscall fault injection.
|
||||
*/
|
||||
if (opts.signo == 0 && opts.err == -1)
|
||||
opts.err = 0;
|
||||
if (opts.signo && opts.rval == FAULT_OPTS_RVAL_DEFAULT) {
|
||||
opts.rval = FAULT_OPTS_RVAL_DISABLE;
|
||||
}
|
||||
|
||||
struct number_set tmp_set[SUPPORTED_PERSONALITIES];
|
||||
memset(tmp_set, 0, sizeof(tmp_set));
|
||||
|
46
strace.1
46
strace.1
@ -469,10 +469,12 @@ Note that this is independent from the normal tracing of the
|
||||
system call which is controlled by the option
|
||||
.BR -e "\ " trace = write .
|
||||
.TP
|
||||
\fB\-e\ fault\fR=\,\fIset\/\fR[:\fBerror\fR=\,\fIerrno\/\fR][:\fBsignal\fR=\,\fIsig\/\fR][:\fBwhen\fR=\,\fIexpr\/\fR]
|
||||
Perform a syscall fault injection for the specified set of syscalls.
|
||||
When a fault is injected into a syscall invocation, the syscall number
|
||||
is replaced by -1 which corresponds to an invalid syscall.
|
||||
\fB\-e\ fault\fR=\,\fIset\/\fR[:\fBerror\fR=\,\fIerrno\/\fR|:\fBretval\fR=\,\fIvalue\/\fR][:\fBsignal\fR=\,\fIsig\/\fR][:\fBwhen\fR=\,\fIexpr\/\fR]
|
||||
Perform syscall tampering for the specified set of syscalls.
|
||||
|
||||
When no options are specified or :\fBerror\fR=\,\fIerrno\/\fR
|
||||
option is specified, a fault is injected into a syscall invocation:
|
||||
the syscall number is replaced by -1 which corresponds to an invalid syscall.
|
||||
|
||||
If an error code is specified using a symbolic
|
||||
.I errno
|
||||
@ -483,26 +485,34 @@ the default error code returned by the kernel, which is traditionally
|
||||
.B ENOSYS
|
||||
for invalid syscall numbers on most architectures.
|
||||
|
||||
If a signal is specified using either a symbolic value like
|
||||
If :\fBretval\fR=\,\fIvalue\/\fR option is specified,
|
||||
success injection is performed: the syscall number is replaced by -1,
|
||||
but a bogus success value is returned to the callee.
|
||||
|
||||
.B error
|
||||
and
|
||||
.B retval
|
||||
are mutually exclusive.
|
||||
|
||||
If :\fBsignal\fR=\,\fIsig\/\fR option is specified with either a symbolic value
|
||||
like
|
||||
.B SIGSEGV
|
||||
or a numeric value within 1..\fBSIGRTMAX\fR range,
|
||||
that signal is delivered on entering every syscall specified by the
|
||||
.IR set .
|
||||
|
||||
If :\fBsignal\fR=\,\fIsig\/\fR option is specified without
|
||||
:\fBerror\fR=\,\fIerrno\/\fR option, then only a signal
|
||||
:\fBerror\fR=\,\fIerrno\/\fR or :\fBretval\fR=\,\fIvalue\/\fR options,
|
||||
then only a signal
|
||||
.I sig
|
||||
is delivered without a syscall fault injection.
|
||||
Conversely, :\fBerror\fR=\,\fIerrno\/\fR option without
|
||||
Conversely, :\fBerror\fR=\,\fIerrno\/\fR or
|
||||
:\fBretval\fR=\,\fIvalue\/\fR option without
|
||||
:\fBsignal\fR=\,\fIsig\/\fR option injects a fault without delivering a signal.
|
||||
|
||||
If both :\fBerror\fR=\,\fIerrno\/\fR and :\fBsignal\fR=\,\fIsig\/\fR
|
||||
options are specified, then both a fault is injected with the specified
|
||||
error code
|
||||
.I errno
|
||||
and a signal
|
||||
.I sig
|
||||
is delivered.
|
||||
If both :\fBerror\fR=\,\fIerrno\/\fR or :\fBretval\fR=\,\fIvalue\/\fR
|
||||
and :\fBsignal\fR=\,\fIsig\/\fR options are specified, then both
|
||||
a fault or success is injected and a signal is delivered.
|
||||
|
||||
Unless a :\fBwhen\fR=\,\fIexpr\fR subexpression is specified,
|
||||
an injection is being made into every invocation of each syscall from the
|
||||
@ -552,10 +562,12 @@ and
|
||||
.I step
|
||||
is 1..65535.
|
||||
|
||||
If a fault expression contains multiple
|
||||
A fault expression can contain only one
|
||||
.BR error =
|
||||
specifications, the last one takes precedence.
|
||||
Likewise, if a fault expression contains multiple
|
||||
or
|
||||
.BR retval =
|
||||
specification.
|
||||
If a fault expression contains multiple
|
||||
.BR when =
|
||||
specifications, the last one takes precedence.
|
||||
|
||||
|
37
syscall.c
37
syscall.c
@ -559,6 +559,7 @@ static int arch_get_scno(struct tcb *tcp);
|
||||
static int arch_set_scno(struct tcb *, kernel_ulong_t);
|
||||
static void get_error(struct tcb *, const bool);
|
||||
static int arch_set_error(struct tcb *);
|
||||
static int arch_set_success(struct tcb *);
|
||||
|
||||
struct fault_opts *fault_vec[SUPPORTED_PERSONALITIES];
|
||||
|
||||
@ -595,7 +596,7 @@ inject_syscall_fault_entering(struct tcb *tcp, unsigned int *signo)
|
||||
|
||||
if (opts->signo > 0)
|
||||
*signo = opts->signo;
|
||||
if (opts->err != -1 && !arch_set_scno(tcp, -1))
|
||||
if (opts->rval != FAULT_OPTS_RVAL_DISABLE && !arch_set_scno(tcp, -1))
|
||||
tcp->flags |= TCB_FAULT_INJ;
|
||||
|
||||
return 0;
|
||||
@ -606,11 +607,29 @@ update_syscall_fault_exiting(struct tcb *tcp)
|
||||
{
|
||||
struct fault_opts *opts = tcb_fault_opts(tcp);
|
||||
|
||||
if (opts && opts->err > 0 && tcp->u_error != (uint16_t) opts->err) {
|
||||
unsigned long u_error = tcp->u_error;
|
||||
tcp->u_error = opts->err;
|
||||
if (arch_set_error(tcp))
|
||||
tcp->u_error = u_error;
|
||||
if (!opts)
|
||||
return 0;
|
||||
|
||||
if (opts->rval >= 0) {
|
||||
kernel_long_t u_rval = tcp->u_rval;
|
||||
|
||||
tcp->u_rval = opts->rval;
|
||||
if (arch_set_success(tcp)) {
|
||||
tcp->u_rval = u_rval;
|
||||
} else {
|
||||
tcp->u_error = 0;
|
||||
}
|
||||
} else {
|
||||
unsigned long new_error = -opts->rval;
|
||||
|
||||
if (new_error != tcp->u_error && new_error <= MAX_ERRNO_VALUE) {
|
||||
unsigned long u_error = tcp->u_error;
|
||||
|
||||
tcp->u_error = new_error;
|
||||
if (arch_set_error(tcp)) {
|
||||
tcp->u_error = u_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -819,11 +838,11 @@ trace_syscall_exiting(struct tcb *tcp)
|
||||
if (tcp->qual_flg & QUAL_RAW) {
|
||||
if (u_error) {
|
||||
tprintf("= -1 (errno %lu)", u_error);
|
||||
if (syscall_fault_injected(tcp))
|
||||
tprints(" (INJECTED)");
|
||||
} else {
|
||||
tprintf("= %#" PRI_klx, tcp->u_rval);
|
||||
}
|
||||
if (syscall_fault_injected(tcp))
|
||||
tprints(" (INJECTED)");
|
||||
}
|
||||
else if (!(sys_res & RVAL_NONE) && u_error) {
|
||||
switch (u_error) {
|
||||
@ -944,6 +963,8 @@ trace_syscall_exiting(struct tcb *tcp)
|
||||
}
|
||||
if ((sys_res & RVAL_STR) && tcp->auxstr)
|
||||
tprintf(" (%s)", tcp->auxstr);
|
||||
if (syscall_fault_injected(tcp))
|
||||
tprints(" (INJECTED)");
|
||||
}
|
||||
if (Tflag) {
|
||||
tv_sub(&tv, &tv, &tcp->etime);
|
||||
|
Loading…
Reference in New Issue
Block a user