This extends the -e fault capability with a :signal option which delivers a signal on entry of the specified syscall.
:signal and :error are complementary, if they are both specified the syscall will be injected as per normal and a signal will be sent to the process. Signed-off-by: Seraphime Kirkovski <kirkser...@gmail.com> --- This fixes the problems discussed in the last patch: * fault_opts.signo becomes unsigned * fault.opts.err becomes signed * use 0 as default value for signal * remove unneccessary casts * don't enforce ENOSYS * Add a hardlimit for signals - SIGRTMAX strace crashes when :signal is greater than the biggest signal defs.h | 6 ++++-- qualify.c | 12 +++++++++++- strace.c | 4 +++- syscall.c | 16 +++++++++------- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/defs.h b/defs.h index 0a4c616..a766808 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; }; #if defined LINUX_MIPSN32 || defined X32 @@ -457,13 +458,14 @@ 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 *); extern void clear_regs(void); extern void get_regs(pid_t pid); extern int get_scno(struct tcb *tcp); + /** * Convert syscall number to syscall name. * diff --git a/qualify.c b/qualify.c index a7d276c..b698c4f 100644 --- a/qualify.c +++ b/qualify.c @@ -26,6 +26,7 @@ */ #include "defs.h" +#include <signal.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 < 0 || intval > SIGRTMAX) + return false; + fopts->signo = intval; } else { return false; } @@ -494,13 +500,17 @@ 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 63d3b00..c86d55c 100644 --- a/syscall.c +++ b/syscall.c @@ -573,7 +573,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] = @@ -595,7 +595,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; @@ -606,7 +608,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 && tcp->u_error != (uint16_t)opts->err) { unsigned long u_error = tcp->u_error; tcp->u_error = opts->err; if (arch_set_error(tcp)) @@ -617,7 +619,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; @@ -688,7 +690,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; @@ -981,10 +983,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