This extends the fault injection capability with :signal=SIG option which injects a signal on entering each syscall from the specified set.
:signal and :error options are complementary, if they are both specified the syscall will be fault injected as usual and the specified signal will be delivered to the tracee. Signed-off-by: Seraphime Kirkovski <kirkser...@gmail.com> --- This * changes the commit message as requested. * uses nsig.h rather than <signal.h> * tidies up checks * fixes some whitespace issues defs.h | 5 +++-- qualify.c | 15 ++++++++++++++- strace.c | 4 +++- syscall.c | 16 +++++++++------- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/defs.h b/defs.h index 81d26d5..9591e17 100644 --- a/defs.h +++ b/defs.h @@ -217,7 +217,8 @@ typedef struct ioctlent { struct fault_opts { uint16_t first; uint16_t step; - uint16_t err; + int16_t err; + uint16_t signo; }; /* Trace Control Block */ @@ -439,7 +440,7 @@ extern int read_int_from_file(const char *, int *); extern void set_sortby(const char *); extern void set_overhead(int); extern void print_pc(struct tcb *); -extern int trace_syscall(struct tcb *); +extern int trace_syscall(struct tcb *, unsigned int *); extern void count_syscall(struct tcb *, const struct timeval *); extern void call_summary(FILE *); diff --git a/qualify.c b/qualify.c index a7d276c..e052d39 100644 --- a/qualify.c +++ b/qualify.c @@ -26,6 +26,7 @@ */ #include "defs.h" +#include "nsig.h" typedef unsigned int number_slot_t; #define BITS_PER_SLOT (sizeof(number_slot_t) * 8) @@ -414,6 +415,11 @@ parse_fault_token(const char *const token, struct fault_opts *const fopts) if (intval < 1) return false; fopts->err = intval; + } else if ((val = strip_prefix("signal=", token))) { + intval = sigstr_to_uint(val); + if (intval < 1 || intval > NSIG_BYTES * 8) + return false; + fopts->signo = intval; } else { return false; } @@ -494,13 +500,20 @@ qualify_fault(const char *const str) struct fault_opts opts = { .first = 1, .step = 1, - .err = 0 + .err = -1, + .signo = 0 }; char *buf = NULL; char *name = parse_fault_expression(str, &buf, &opts); if (!name) { error_msg_and_die("invalid %s '%s'", "fault argument", str); } + /* + * If no error, nor signal is specified, + * fallback to the default platform error + */ + if (opts.signo == 0 && opts.err == -1) + opts.err = 0; struct number_set tmp_set[SUPPORTED_PERSONALITIES]; diff --git a/strace.c b/strace.c index 4659ddb..23ca108 100644 --- a/strace.c +++ b/strace.c @@ -2447,7 +2447,8 @@ show_stopsig: * This should be syscall entry or exit. * Handle it. */ - if (trace_syscall(tcp) < 0) { + sig = 0; + if (trace_syscall(tcp, &sig) < 0) { /* * ptrace() failed in trace_syscall(). * Likely a result of process disappearing mid-flight. @@ -2461,6 +2462,7 @@ show_stopsig: */ return true; } + goto restart_tracee; restart_tracee_with_sig_0: sig = 0; diff --git a/syscall.c b/syscall.c index 6613a1e..c821d7e 100644 --- a/syscall.c +++ b/syscall.c @@ -568,7 +568,7 @@ tcb_fault_opts(struct tcb *tcp) static long -inject_syscall_fault_entering(struct tcb *tcp) +inject_syscall_fault_entering(struct tcb *tcp, unsigned int *signo) { if (!tcp->fault_vec[current_personality]) { tcp->fault_vec[current_personality] = @@ -590,7 +590,9 @@ inject_syscall_fault_entering(struct tcb *tcp) opts->first = opts->step; - if (!arch_set_scno(tcp, -1)) + if (opts->signo > 0) + *signo = opts->signo; + if (opts->err != -1 && !arch_set_scno(tcp, -1)) tcp->flags |= TCB_FAULT_INJ; return 0; @@ -601,7 +603,7 @@ update_syscall_fault_exiting(struct tcb *tcp) { struct fault_opts *opts = tcb_fault_opts(tcp); - if (opts && opts->err && tcp->u_error != opts->err) { + 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)) @@ -612,7 +614,7 @@ update_syscall_fault_exiting(struct tcb *tcp) } static int -trace_syscall_entering(struct tcb *tcp) +trace_syscall_entering(struct tcb *tcp, unsigned int *sig) { int res, scno_good; @@ -683,7 +685,7 @@ trace_syscall_entering(struct tcb *tcp) } if (tcp->qual_flg & QUAL_FAULT) - inject_syscall_fault_entering(tcp); + inject_syscall_fault_entering(tcp, sig); if (cflag == CFLAG_ONLY_STATS) { res = 0; @@ -962,10 +964,10 @@ trace_syscall_exiting(struct tcb *tcp) } int -trace_syscall(struct tcb *tcp) +trace_syscall(struct tcb *tcp, unsigned int *signo) { return exiting(tcp) ? - trace_syscall_exiting(tcp) : trace_syscall_entering(tcp); + trace_syscall_exiting(tcp) : trace_syscall_entering(tcp, signo); } bool -- 2.10.2 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, SlashDot.org! http://sdm.link/slashdot _______________________________________________ Strace-devel mailing list Strace-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/strace-devel