unsigned int code;
} struct_ioctlent;
+struct fault_opts {
+ uint16_t first;
+ uint16_t step;
+ uint16_t err;
+};
+
#if defined LINUX_MIPSN32 || defined X32
# define HAVE_STRUCT_TCB_EXT_ARG 1
#else
# define HAVE_STRUCT_TCB_EXT_ARG 0
#endif
-struct fault_opts;
-
/* Trace Control Block */
struct tcb {
int flags; /* See below for TCB_ values */
#define QUAL_SIGNAL 0x100 /* report events with this signal */
#define QUAL_READ 0x200 /* dump data read from this file descriptor */
#define QUAL_WRITE 0x400 /* dump data written to this file descriptor */
-typedef uint8_t qualbits_t;
#define DEFAULT_QUAL_FLAGS (QUAL_TRACE | QUAL_ABBREV | QUAL_VERBOSE)
extern void set_sortby(const char *);
extern void set_overhead(int);
-extern void qualify(const char *);
extern void print_pc(struct tcb *);
extern int trace_syscall(struct tcb *);
extern void count_syscall(struct tcb *, const struct timeval *);
extern struct number_set signal_set;
extern bool is_number_in_set(unsigned int number, const struct number_set *);
-extern void qualify_read(const char *);
-extern void qualify_write(const char *);
-extern void qualify_signals(const char *);
+extern void qualify(const char *);
+extern unsigned int qual_flags(const unsigned int);
extern int dm_ioctl(struct tcb *, const unsigned int, long);
extern int file_ioctl(struct tcb *, const unsigned int, long);
extern unsigned nsignals;
extern unsigned nioctlents;
+extern const unsigned int nsyscall_vec[SUPPORTED_PERSONALITIES];
+extern const struct_sysent *const sysent_vec[SUPPORTED_PERSONALITIES];
+extern struct fault_opts *fault_vec[SUPPORTED_PERSONALITIES];
+
#ifdef IN_MPERS_BOOTSTRAP
/* Transform multi-line MPERS_PRINTER_DECL statements to one-liners. */
# define MPERS_PRINTER_DECL(type, name, ...) MPERS_PRINTER_DECL(type, name, __VA_ARGS__)
struct number_set write_set;
struct number_set signal_set;
+static struct number_set abbrev_set[SUPPORTED_PERSONALITIES];
+static struct number_set fault_set[SUPPORTED_PERSONALITIES];
+static struct number_set raw_set[SUPPORTED_PERSONALITIES];
+static struct number_set trace_set[SUPPORTED_PERSONALITIES];
+static struct number_set verbose_set[SUPPORTED_PERSONALITIES];
+
static void
number_setbit(const unsigned int i, number_slot_t *const vec)
{
}
}
-void
-qualify_read(const char *const str)
-{
- qualify_tokens(str, &read_set, string_to_uint, "descriptor");
-}
-
-void
-qualify_write(const char *const str)
-{
- qualify_tokens(str, &write_set, string_to_uint, "descriptor");
-}
-
static int
sigstr_to_uint(const char *s)
{
return -1;
}
-void
+static bool
+qualify_syscall_number(const char *s, struct number_set *set)
+{
+ int n = string_to_uint(s);
+ if (n < 0)
+ return false;
+
+ unsigned int p;
+ bool done = false;
+
+ for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
+ if ((unsigned) n >= nsyscall_vec[p]) {
+ continue;
+ }
+ add_number_to_set(n, &set[p]);
+ done = true;
+ }
+
+ return done;
+}
+
+static unsigned int
+lookup_class(const char *s)
+{
+ static const struct {
+ const char *name;
+ unsigned int value;
+ } syscall_class[] = {
+ { "desc", TRACE_DESC },
+ { "file", TRACE_FILE },
+ { "memory", TRACE_MEMORY },
+ { "process", TRACE_PROCESS },
+ { "signal", TRACE_SIGNAL },
+ { "ipc", TRACE_IPC },
+ { "network", TRACE_NETWORK },
+ };
+
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(syscall_class); ++i) {
+ if (strcmp(s, syscall_class[i].name) == 0) {
+ return syscall_class[i].value;
+ }
+ }
+
+ return 0;
+}
+
+static bool
+qualify_syscall_class(const char *s, struct number_set *set)
+{
+ const unsigned int n = lookup_class(s);
+ if (!n)
+ return false;
+
+ unsigned int p;
+ for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
+ unsigned int i;
+
+ for (i = 0; i < nsyscall_vec[p]; ++i) {
+ if (!sysent_vec[p][i].sys_name
+ || (sysent_vec[p][i].sys_flags & n) != n) {
+ continue;
+ }
+ add_number_to_set(i, &set[p]);
+ }
+ }
+
+ return true;
+}
+
+static bool
+qualify_syscall_name(const char *s, struct number_set *set)
+{
+ unsigned int p;
+ bool found = false;
+
+ for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
+ unsigned int i;
+
+ for (i = 0; i < nsyscall_vec[p]; ++i) {
+ if (!sysent_vec[p][i].sys_name
+ || strcmp(s, sysent_vec[p][i].sys_name)) {
+ continue;
+ }
+ add_number_to_set(i, &set[p]);
+ found = true;
+ }
+ }
+
+ return found;
+}
+
+static bool
+qualify_syscall(const char *token, struct number_set *set)
+{
+ if (*token >= '0' && *token <= '9')
+ return qualify_syscall_number(token, set);
+ return qualify_syscall_class(token, set)
+ || qualify_syscall_name(token, set);
+}
+
+/*
+ * Add syscall numbers to SETs for each supported personality
+ * according to STR specification.
+ */
+static void
+qualify_syscall_tokens(const char *const str, struct number_set *const set,
+ const char *const name)
+{
+ /* Clear all sets. */
+ unsigned int p;
+ for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
+ if (set[p].nslots)
+ memset(set[p].vec, 0,
+ sizeof(*set[p].vec) * set[p].nslots);
+ set[p].not = false;
+ }
+
+ /*
+ * Each leading ! character means inversion
+ * of the remaining specification.
+ */
+ const char *s = str;
+handle_inversion:
+ while (*s == '!') {
+ for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
+ set[p].not = !set[p].not;
+ }
+ ++s;
+ }
+
+ if (strcmp(s, "none") == 0) {
+ /*
+ * No syscall numbers are added to sets.
+ * Subsequent is_number_in_set invocations
+ * will return set[p]->not.
+ */
+ return;
+ } else if (strcmp(s, "all") == 0) {
+ s = "!none";
+ goto handle_inversion;
+ }
+
+ /*
+ * Split the string into comma separated tokens.
+ * For each token, call qualify_syscall that will take care
+ * if adding appropriate syscall numbers to sets.
+ * The absence of tokens or a negative return code
+ * from qualify_syscall is a fatal error.
+ */
+ char *copy = xstrdup(s);
+ char *saveptr = NULL;
+ const char *token;
+ bool done = false;
+
+ for (token = strtok_r(copy, ",", &saveptr); token;
+ token = strtok_r(NULL, ",", &saveptr)) {
+ done = qualify_syscall(token, set);
+ if (!done) {
+ error_msg_and_die("invalid %s '%s'", name, token);
+ }
+ }
+
+ free(copy);
+
+ if (!done) {
+ error_msg_and_die("invalid %s '%s'", name, str);
+ }
+}
+
+/*
+ * Returns NULL if STR does not start with PREFIX,
+ * or a pointer to the first char in STR after PREFIX.
+ */
+static const char *
+strip_prefix(const char *prefix, const char *str)
+{
+ size_t len = strlen(prefix);
+
+ return strncmp(prefix, str, len) ? NULL : str + len;
+}
+
+static int
+find_errno_by_name(const char *name)
+{
+ unsigned int i;
+
+ for (i = 1; i < nerrnos; ++i) {
+ if (errnoent[i] && (strcmp(name, errnoent[i]) == 0))
+ return i;
+ }
+
+ return -1;
+}
+
+static bool
+parse_fault_token(const char *const token, struct fault_opts *const fopts)
+{
+ const char *val;
+ int intval;
+
+ if ((val = strip_prefix("when=", token))) {
+ /*
+ * == 1+1
+ * F == F+0
+ * F+ == F+1
+ * F+S
+ */
+ char *end;
+ intval = string_to_uint_ex(val, &end, 0xffff, "+");
+ if (intval < 1)
+ return false;
+
+ fopts->first = intval;
+
+ if (*end) {
+ val = end + 1;
+ if (*val) {
+ /* F+S */
+ intval = string_to_uint_upto(val, 0xffff);
+ if (intval < 1)
+ return false;
+ fopts->step = intval;
+ } else {
+ /* F+ == F+1 */
+ fopts->step = 1;
+ }
+ } else {
+ /* F == F+0 */
+ fopts->step = 0;
+ }
+ } else if ((val = strip_prefix("error=", token))) {
+ intval = string_to_uint_upto(val, 4095);
+ if (intval < 0)
+ intval = find_errno_by_name(val);
+ if (intval < 1)
+ return false;
+ fopts->err = intval;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+static char *
+parse_fault_expression(const char *const s, char **buf,
+ struct fault_opts *const fopts)
+{
+ char *saveptr = NULL;
+ char *name = NULL;
+ char *token;
+
+ *buf = xstrdup(s);
+ for (token = strtok_r(*buf, ":", &saveptr); token;
+ token = strtok_r(NULL, ":", &saveptr)) {
+ if (!name)
+ name = token;
+ else if (!parse_fault_token(token, fopts))
+ goto parse_error;
+ }
+
+ if (name)
+ return name;
+
+parse_error:
+ free(*buf);
+ return *buf = NULL;
+}
+
+static void
+qualify_read(const char *const str)
+{
+ qualify_tokens(str, &read_set, string_to_uint, "descriptor");
+}
+
+static void
+qualify_write(const char *const str)
+{
+ qualify_tokens(str, &write_set, string_to_uint, "descriptor");
+}
+
+static void
qualify_signals(const char *const str)
{
qualify_tokens(str, &signal_set, sigstr_to_uint, "signal");
}
+
+static void
+qualify_trace(const char *const str)
+{
+ qualify_syscall_tokens(str, trace_set, "system call");
+}
+
+static void
+qualify_abbrev(const char *const str)
+{
+ qualify_syscall_tokens(str, abbrev_set, "system call");
+}
+
+static void
+qualify_verbose(const char *const str)
+{
+ qualify_syscall_tokens(str, verbose_set, "system call");
+}
+
+static void
+qualify_raw(const char *const str)
+{
+ qualify_syscall_tokens(str, raw_set, "system call");
+}
+
+static void
+qualify_fault(const char *const str)
+{
+ struct fault_opts opts = {
+ .first = 1,
+ .step = 1,
+ .err = 0
+ };
+ char *buf = NULL;
+ char *name = parse_fault_expression(str, &buf, &opts);
+ if (!name) {
+ error_msg_and_die("invalid %s '%s'", "fault argument", str);
+ }
+
+
+ struct number_set tmp_set[SUPPORTED_PERSONALITIES];
+ memset(tmp_set, 0, sizeof(tmp_set));
+ qualify_syscall_tokens(name, tmp_set, "fault argument");
+
+ free(buf);
+
+ /*
+ * Initialize fault_vec accourding to tmp_set.
+ * Merge tmp_set into fault_set.
+ */
+ unsigned int p;
+ for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
+ if (!tmp_set[p].nslots && !tmp_set[p].not) {
+ continue;
+ }
+
+ if (!fault_vec[p]) {
+ fault_vec[p] = xcalloc(nsyscall_vec[p],
+ sizeof(*fault_vec[p]));
+ }
+
+ unsigned int i;
+ for (i = 0; i < nsyscall_vec[p]; ++i) {
+ if (is_number_in_set(i, &tmp_set[p])) {
+ add_number_to_set(i, &fault_set[p]);
+ fault_vec[p][i] = opts;
+ }
+ }
+
+ free(tmp_set[p].vec);
+ }
+}
+
+static const struct qual_options {
+ const char *name;
+ void (*qualify)(const char *);
+} qual_options[] = {
+ { "trace", qualify_trace },
+ { "t", qualify_trace },
+ { "abbrev", qualify_abbrev },
+ { "a", qualify_abbrev },
+ { "verbose", qualify_verbose },
+ { "v", qualify_verbose },
+ { "raw", qualify_raw },
+ { "x", qualify_raw },
+ { "signal", qualify_signals },
+ { "signals", qualify_signals },
+ { "s", qualify_signals },
+ { "read", qualify_read },
+ { "reads", qualify_read },
+ { "r", qualify_read },
+ { "write", qualify_write },
+ { "writes", qualify_write },
+ { "w", qualify_write },
+ { "fault", qualify_fault },
+};
+
+void
+qualify(const char *str)
+{
+ const struct qual_options *opt = qual_options;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(qual_options); ++i) {
+ const char *p = qual_options[i].name;
+ unsigned int len = strlen(p);
+
+ if (strncmp(str, p, len) || str[len] != '=')
+ continue;
+
+ opt = &qual_options[i];
+ str += len + 1;
+ break;
+ }
+
+ opt->qualify(str);
+}
+
+unsigned int
+qual_flags(const unsigned int scno)
+{
+ return (is_number_in_set(scno, &trace_set[current_personality])
+ ? QUAL_TRACE : 0)
+ | (is_number_in_set(scno, &abbrev_set[current_personality])
+ ? QUAL_ABBREV : 0)
+ | (is_number_in_set(scno, &verbose_set[current_personality])
+ ? QUAL_VERBOSE : 0)
+ | (is_number_in_set(scno, &raw_set[current_personality])
+ ? QUAL_RAW : 0)
+ | (is_number_in_set(scno, &fault_set[current_personality])
+ ? QUAL_FAULT : 0);
+}
unsigned nsignals = nsignals0;
unsigned nioctlents = nioctlents0;
-static const unsigned nsyscall_vec[SUPPORTED_PERSONALITIES] = {
+const unsigned int nsyscall_vec[SUPPORTED_PERSONALITIES] = {
nsyscalls0,
#if SUPPORTED_PERSONALITIES > 1
nsyscalls1,
nsyscalls2,
#endif
};
-static const struct_sysent *const sysent_vec[SUPPORTED_PERSONALITIES] = {
+const struct_sysent *const sysent_vec[SUPPORTED_PERSONALITIES] = {
sysent0,
#if SUPPORTED_PERSONALITIES > 1
sysent1,
#endif
};
-enum {
- MAX_NSYSCALLS1 = (nsyscalls0
-#if SUPPORTED_PERSONALITIES > 1
- > nsyscalls1 ? nsyscalls0 : nsyscalls1
-#endif
- ),
- MAX_NSYSCALLS2 = (MAX_NSYSCALLS1
-#if SUPPORTED_PERSONALITIES > 2
- > nsyscalls2 ? MAX_NSYSCALLS1 : nsyscalls2
-#endif
- ),
- MAX_NSYSCALLS = MAX_NSYSCALLS2
-};
-
-static qualbits_t qual_vec[SUPPORTED_PERSONALITIES][MAX_NSYSCALLS];
-#define qual_flags (qual_vec[current_personality])
-
#if SUPPORTED_PERSONALITIES > 1
unsigned current_personality;
}
#endif
-static int qual_fault(const char *, unsigned int, int);
-static int qual_syscall(const char *, unsigned int, int);
-
-static const struct qual_options {
- unsigned int bitflag;
- const char *option_name;
- int (*qualify)(const char *, unsigned int, int);
- const char *argument_name;
-} qual_options[] = {
- { QUAL_TRACE, "trace", qual_syscall, "system call" },
- { QUAL_TRACE, "t", qual_syscall, "system call" },
- { QUAL_ABBREV, "abbrev", qual_syscall, "system call" },
- { QUAL_ABBREV, "a", qual_syscall, "system call" },
- { QUAL_VERBOSE, "verbose", qual_syscall, "system call" },
- { QUAL_VERBOSE, "v", qual_syscall, "system call" },
- { QUAL_RAW, "raw", qual_syscall, "system call" },
- { QUAL_RAW, "x", qual_syscall, "system call" },
- { QUAL_SIGNAL, "signal", NULL, "signal" },
- { QUAL_SIGNAL, "signals", NULL, "signal" },
- { QUAL_SIGNAL, "s", NULL, "signal" },
- { QUAL_READ, "read", NULL, "descriptor" },
- { QUAL_READ, "reads", NULL, "descriptor" },
- { QUAL_READ, "r", NULL, "descriptor" },
- { QUAL_WRITE, "write", NULL, "descriptor" },
- { QUAL_WRITE, "writes", NULL, "descriptor" },
- { QUAL_WRITE, "w", NULL, "descriptor" },
- { QUAL_FAULT, "fault", qual_fault, "fault argument"},
- { 0, NULL, NULL, NULL },
-};
-
-struct fault_opts {
- uint16_t first;
- uint16_t step;
- uint16_t err;
-};
-
-static struct fault_opts fault_vec[SUPPORTED_PERSONALITIES][MAX_NSYSCALLS];
-
-static void
-qualify_one(const unsigned int n, unsigned int bitflag, const int not,
- const int pers, const struct fault_opts *fopts)
-{
- int p;
-
- for (p = 0; p < SUPPORTED_PERSONALITIES; p++) {
- if (pers == p || pers < 0) {
- if (not)
- qual_vec[p][n] &= ~bitflag;
- else {
- qual_vec[p][n] |= bitflag;
- if (fopts)
- memcpy(&fault_vec[p][n], fopts,
- sizeof(*fopts));
- }
- }
- }
-}
-
-static bool
-qualify_scno(const char *const s, const unsigned int bitflag,
- const int not, const struct fault_opts *const fopts)
-{
- int n = string_to_uint_upto(s, MAX_NSYSCALLS - 1);
- if (n < 0)
- return false;
-
- if (not && fopts) {
- /* set bitflag for all syscall numbers except n */
- unsigned int p;
- for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
- unsigned int i;
-
- for (i = 0; i < nsyscall_vec[p]; ++i) {
- if (i != (unsigned int) n
- && sysent_vec[p][i].sys_name) {
- qualify_one(i, bitflag, 0, p, fopts);
- }
- }
- }
- } else {
- qualify_one(n, bitflag, not, -1, fopts);
- }
-
- return true;
-}
-
-static int
-lookup_class(const char *s)
-{
- if (strcmp(s, "all") == 0)
- return 0;
- if (strcmp(s, "file") == 0)
- return TRACE_FILE;
- if (strcmp(s, "ipc") == 0)
- return TRACE_IPC;
- if (strcmp(s, "network") == 0)
- return TRACE_NETWORK;
- if (strcmp(s, "process") == 0)
- return TRACE_PROCESS;
- if (strcmp(s, "signal") == 0)
- return TRACE_SIGNAL;
- if (strcmp(s, "desc") == 0)
- return TRACE_DESC;
- if (strcmp(s, "memory") == 0)
- return TRACE_MEMORY;
- return -1;
-}
-
-static bool
-qualify_syscall_class(const char *const s, const unsigned int bitflag,
- const int not, const struct fault_opts *const fopts)
-{
- unsigned int p;
- const int n = lookup_class(s);
-
- if (n < 0)
- return false;
-
- for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
- unsigned int i;
-
- for (i = 0; i < nsyscall_vec[p]; ++i) {
- if (!sysent_vec[p][i].sys_name)
- continue;
- const bool match = (sysent_vec[p][i].sys_flags & n) == n;
- if (match ^ (not && fopts)) {
- qualify_one(i, bitflag, not && !fopts, p, fopts);
- }
- }
- }
-
- return true;
-}
-
-static bool
-qualify_syscall_name(const char *const s, const unsigned int bitflag,
- const int not, const struct fault_opts *const fopts)
-{
- bool found = false;
- unsigned int p;
-
- for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
- unsigned int i;
-
- for (i = 0; i < nsyscall_vec[p]; ++i) {
- if (!sysent_vec[p][i].sys_name)
- continue;
- const bool match = !strcmp(s, sysent_vec[p][i].sys_name);
- found = found || match;
- if (match ^ (not && fopts)) {
- qualify_one(i, bitflag, not && !fopts, p, fopts);
- }
- }
- }
-
- return found;
-}
-
-static int
-qual_syscall_ex(const char *const s, const unsigned int bitflag,
- const int not, const struct fault_opts *const fopts)
-{
- if (qualify_scno(s, bitflag, not, fopts)
- || qualify_syscall_class(s, bitflag, not, fopts)
- || qualify_syscall_name(s, bitflag, not, fopts)) {
- return 0;
- }
-
- return -1;
-}
-
-static int
-qual_syscall(const char *const s, const unsigned int bitflag, const int not)
-{
- return qual_syscall_ex(s, bitflag, not, NULL);
-}
-
-/*
- * Returns NULL if STR does not start with PREFIX,
- * or a pointer to the first char in STR after PREFIX.
- */
-static const char *
-strip_prefix(const char *prefix, const char *str)
-{
- size_t len = strlen(prefix);
-
- return strncmp(prefix, str, len) ? NULL : str + len;
-}
-
-static int
-find_errno_by_name(const char *name)
-{
- unsigned int i;
-
- for (i = 1; i < nerrnos; ++i) {
- if (errnoent[i] && (strcmp(name, errnoent[i]) == 0))
- return i;
- }
-
- return -1;
-}
-
-static bool
-parse_fault_token(const char *const token, struct fault_opts *const fopts)
-{
- const char *val;
- int intval;
-
- if ((val = strip_prefix("when=", token))) {
- /*
- * == 1+1
- * F == F+0
- * F+ == F+1
- * F+S
- */
- char *end;
- intval = string_to_uint_ex(val, &end, 0xffff, "+");
- if (intval < 1)
- return false;
-
- fopts->first = intval;
-
- if (*end) {
- val = end + 1;
- if (*val) {
- /* F+S */
- intval = string_to_uint_upto(val, 0xffff);
- if (intval < 1)
- return false;
- fopts->step = intval;
- } else {
- /* F+ == F+1 */
- fopts->step = 1;
- }
- } else {
- /* F == F+0 */
- fopts->step = 0;
- }
- } else if ((val = strip_prefix("error=", token))) {
- intval = string_to_uint_upto(val, 4095);
- if (intval < 0)
- intval = find_errno_by_name(val);
- if (intval < 1)
- return false;
- fopts->err = intval;
- } else {
- return false;
- }
-
- return true;
-}
-
-static char *
-parse_fault_expression(const char *const s, char **buf,
- struct fault_opts *const fopts)
-{
- char *saveptr = NULL;
- char *name = NULL;
- char *token;
-
- *buf = xstrdup(s);
- for (token = strtok_r(*buf, ":", &saveptr); token;
- token = strtok_r(NULL, ":", &saveptr)) {
- if (!name)
- name = token;
- else if (!parse_fault_token(token, fopts))
- goto parse_error;
- }
-
- if (name)
- return name;
-
-parse_error:
- free(*buf);
- return *buf = NULL;
-}
-
-static int
-qual_fault(const char *const s, const unsigned int bitflag, const int not)
-{
- struct fault_opts opts = {
- .first = 1,
- .step = 1,
- .err = 0
- };
-
- char *buf = NULL;
- char *name = parse_fault_expression(s, &buf, &opts);
- char *saveptr = NULL;
- const char *token;
- int rc = -1;
-
- if (!name)
- return -1;
-
- for (token = strtok_r(name, ",", &saveptr); token;
- token = strtok_r(NULL, ",", &saveptr)) {
- rc = qual_syscall_ex(token, bitflag, not, &opts);
- if (rc)
- break;
- }
-
- free(buf);
- return rc;
-}
-
-void
-qualify(const char *s)
-{
- const struct qual_options *opt;
- char *copy;
- const char *p;
- int not;
- int i;
-
- opt = &qual_options[0];
- for (i = 0; (p = qual_options[i].option_name); i++) {
- unsigned int len = strlen(p);
- if (strncmp(s, p, len) == 0 && s[len] == '=') {
- opt = &qual_options[i];
- s += len + 1;
- break;
- }
- }
-
- switch (opt->bitflag) {
- case QUAL_SIGNAL:
- qualify_signals(s);
- return;
- case QUAL_READ:
- qualify_read(s);
- return;
- case QUAL_WRITE:
- qualify_write(s);
- return;
- }
-
- not = 0;
- if (*s == '!') {
- not = 1;
- s++;
- }
- if (strcmp(s, "none") == 0) {
- not = 1 - not;
- s = "all";
- }
- if (opt->bitflag == QUAL_FAULT) {
- if (opt->qualify(s, opt->bitflag, not)) {
- error_msg_and_die("invalid %s '%s'",
- opt->argument_name, s);
- }
- return;
- }
- if (strcmp(s, "all") == 0) {
- for (i = 0; i < MAX_NSYSCALLS; ++i) {
- qualify_one(i, opt->bitflag, not, -1, NULL);
- }
- return;
- }
- for (i = 0; i < MAX_NSYSCALLS; ++i) {
- qualify_one(i, opt->bitflag, !not, -1, NULL);
- }
- copy = xstrdup(s);
- for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
- if (opt->qualify(p, opt->bitflag, not)) {
- error_msg_and_die("invalid %s '%s'",
- opt->argument_name, p);
- }
- }
- free(copy);
- return;
-}
-
#ifdef SYS_socket_subcall
static void
decode_socket_subcall(struct tcb *tcp)
return;
tcp->scno = scno;
- tcp->qual_flg = qual_flags[scno];
+ tcp->qual_flg = qual_flags(scno);
tcp->s_ent = &sysent[scno];
unsigned int i;
}
tcp->scno = SYS_ipc_subcall + call;
- tcp->qual_flg = qual_flags[tcp->scno];
+ tcp->qual_flg = qual_flags(tcp->scno);
tcp->s_ent = &sysent[tcp->scno];
const unsigned int n = tcp->s_ent->nargs;
if (!SCNO_IS_VALID(tcp->u_arg[0]))
return;
tcp->scno = tcp->u_arg[0];
- tcp->qual_flg = qual_flags[tcp->scno];
+ tcp->qual_flg = qual_flags(tcp->scno);
tcp->s_ent = &sysent[tcp->scno];
memmove(&tcp->u_arg[0], &tcp->u_arg[1],
sizeof(tcp->u_arg) - sizeof(tcp->u_arg[0]));
static void get_error(struct tcb *, const bool);
static int arch_set_error(struct tcb *);
+struct fault_opts *fault_vec[SUPPORTED_PERSONALITIES];
+
static struct fault_opts *
tcb_fault_opts(struct tcb *tcp)
{
{
if (!tcp->fault_vec[current_personality]) {
tcp->fault_vec[current_personality] =
- xcalloc(MAX_NSYSCALLS, sizeof(struct fault_opts));
+ xcalloc(nsyscalls, sizeof(**fault_vec));
memcpy(tcp->fault_vec[current_personality],
fault_vec[current_personality],
- MAX_NSYSCALLS * sizeof(struct fault_opts));
+ nsyscalls * sizeof(**fault_vec));
}
struct fault_opts *opts = tcb_fault_opts(tcp);
- if (opts->first == 0)
+ if (!opts || opts->first == 0)
return 0;
--opts->first;
if (SCNO_IS_VALID(tcp->scno)) {
tcp->s_ent = &sysent[tcp->scno];
- tcp->qual_flg = qual_flags[tcp->scno];
+ tcp->qual_flg = qual_flags(tcp->scno);
} else {
struct sysent_buf *s = xcalloc(1, sizeof(*s));
. "${srcdir=.}/init.sh"
-> "$LOG" || fail_ "failed to write $LOG"
-set -- -eexit,exit_group -efault=exit_group:error=ENOSYS ./answer
+test_with()
+{
+ > "$LOG" || fail_ "failed to write $LOG"
-$STRACE -o "$LOG" "$@"
-rc=$?
-[ $rc -eq 42 ] ||
- dump_log_and_fail_with "$STRACE $* failed with code $rc"
+ $STRACE -o "$LOG" "$@"
+ rc=$?
+ [ $rc -eq 42 ] ||
+ dump_log_and_fail_with "$STRACE $* failed with code $rc"
-match_diff
+ match_diff
+}
+
+test_with -eexit,exit_group -efault=exit_group:error=ENOSYS ./answer
+
+test_with -eexit,exit_group -efault=exit_group:error=ENOSYS \
+ -efault=\!process:error=1 ./answer
+
+test_with -eexit,exit_group -efault=all:error=ENOSYS \
+ -efault=exit:error=1:when=2+ ./answer
+
+test_with -eexit,exit_group -efault=exit_group:error=ENOSYS \
+ -efault=\!desc,file,memory,process,signal,network,ipc:error=1 ./answer
for fault in writev desc,51; do
check_fault_injection \
writev $fault "$err" '' '' -efault=chdir
+ check_fault_injection \
+ writev $fault "$err" '' '' -efault=chdir -efault=none
for F in 1 2 3 5 7 11; do
check_fault_injection \
writev $fault "$err" $F ''
check_e "Syscall 'chdir' for -b isn't supported" -b chdir
check_e "Syscall 'chdir' for -b isn't supported" -b execve -b chdir
+check_e "invalid system call '-1'" -e-1
+check_e "invalid system call '-2'" -e -2
+check_e "invalid system call '-3'" -etrace=-3
+check_e "invalid system call '-4'" -e trace=-4
+check_e "invalid system call '-5'" -e trace=1,-5
+check_e "invalid system call '2147483647'" -e 2147483647
+check_e "invalid system call '2147483648'" -e 2147483648
+check_e "invalid system call '4294967295'" -e 4294967295
+check_e "invalid system call '4294967296'" -e 4294967296
+
check_e "invalid descriptor '-1'" -eread=-1
check_e "invalid descriptor '-42'" -ewrite=-42
check_e "invalid descriptor '2147483648'" -eread=2147483648