2 * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
3 * Copyright (c) 2016-2017 The strace developers.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "number_set.h"
35 qualify_syscall_number(const char *s, struct number_set *set)
37 int n = string_to_uint(s);
44 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
45 if ((unsigned) n >= nsyscall_vec[p]) {
48 add_number_to_set(n, &set[p]);
56 regerror_msg_and_die(int errcode, const regex_t *preg,
57 const char *str, const char *pattern)
61 regerror(errcode, preg, buf, sizeof(buf));
62 error_msg_and_die("%s: %s: %s", str, pattern, buf);
66 qualify_syscall_regex(const char *s, struct number_set *set)
71 if ((rc = regcomp(&preg, s, REG_EXTENDED | REG_NOSUB)) != 0)
72 regerror_msg_and_die(rc, &preg, "regcomp", s);
76 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
79 for (i = 0; i < nsyscall_vec[p]; ++i) {
80 if (!sysent_vec[p][i].sys_name)
82 rc = regexec(&preg, sysent_vec[p][i].sys_name,
84 if (rc == REG_NOMATCH)
87 regerror_msg_and_die(rc, &preg, "regexec", s);
88 add_number_to_set(i, &set[p]);
98 lookup_class(const char *s)
100 static const struct {
103 } syscall_class[] = {
104 { "desc", TRACE_DESC },
105 { "file", TRACE_FILE },
106 { "memory", TRACE_MEMORY },
107 { "process", TRACE_PROCESS },
108 { "signal", TRACE_SIGNAL },
109 { "ipc", TRACE_IPC },
110 { "network", TRACE_NETWORK },
111 { "%desc", TRACE_DESC },
112 { "%file", TRACE_FILE },
113 { "%memory", TRACE_MEMORY },
114 { "%process", TRACE_PROCESS },
115 { "%signal", TRACE_SIGNAL },
116 { "%ipc", TRACE_IPC },
117 { "%network", TRACE_NETWORK },
118 { "%stat", TRACE_STAT },
119 { "%lstat", TRACE_LSTAT },
120 { "%fstat", TRACE_FSTAT },
121 { "%%stat", TRACE_STAT_LIKE },
122 { "%statfs", TRACE_STATFS },
123 { "%fstatfs", TRACE_FSTATFS },
124 { "%%statfs", TRACE_STATFS_LIKE },
128 for (i = 0; i < ARRAY_SIZE(syscall_class); ++i) {
129 if (strcmp(s, syscall_class[i].name) == 0) {
130 return syscall_class[i].value;
138 qualify_syscall_class(const char *s, struct number_set *set)
140 const unsigned int n = lookup_class(s);
145 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
148 for (i = 0; i < nsyscall_vec[p]; ++i) {
149 if (!sysent_vec[p][i].sys_name
150 || (sysent_vec[p][i].sys_flags & n) != n) {
153 add_number_to_set(i, &set[p]);
161 qualify_syscall_name(const char *s, struct number_set *set)
166 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
169 for (i = 0; i < nsyscall_vec[p]; ++i) {
170 if (!sysent_vec[p][i].sys_name
171 || strcmp(s, sysent_vec[p][i].sys_name)) {
174 add_number_to_set(i, &set[p]);
183 qualify_syscall(const char *token, struct number_set *set)
185 bool ignore_fail = false;
187 while (*token == '?') {
191 if (*token >= '0' && *token <= '9')
192 return qualify_syscall_number(token, set) || ignore_fail;
194 return qualify_syscall_regex(token + 1, set) || ignore_fail;
195 return qualify_syscall_class(token, set)
196 || qualify_syscall_name(token, set)
201 * Add syscall numbers to SETs for each supported personality
202 * according to STR specification.
205 qualify_syscall_tokens(const char *const str, struct number_set *const set,
206 const char *const name)
208 /* Clear all sets. */
210 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
212 memset(set[p].vec, 0,
213 sizeof(*set[p].vec) * set[p].nslots);
218 * Each leading ! character means inversion
219 * of the remaining specification.
224 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
225 set[p].not = !set[p].not;
230 if (strcmp(s, "none") == 0) {
232 * No syscall numbers are added to sets.
233 * Subsequent is_number_in_set invocations
234 * will return set[p]->not.
237 } else if (strcmp(s, "all") == 0) {
239 goto handle_inversion;
243 * Split the string into comma separated tokens.
244 * For each token, call qualify_syscall that will take care
245 * if adding appropriate syscall numbers to sets.
246 * The absence of tokens or a negative return code
247 * from qualify_syscall is a fatal error.
249 char *copy = xstrdup(s);
250 char *saveptr = NULL;
254 for (token = strtok_r(copy, ",", &saveptr); token;
255 token = strtok_r(NULL, ",", &saveptr)) {
256 done = qualify_syscall(token, set);
258 error_msg_and_die("invalid %s '%s'", name, token);
265 error_msg_and_die("invalid %s '%s'", name, str);
270 * Add numbers to SET according to STR specification.
273 qualify_tokens(const char *const str, struct number_set *const set,
274 string_to_uint_func func, const char *const name)
278 memset(set->vec, 0, sizeof(*set->vec) * set->nslots);
282 * Each leading ! character means inversion
283 * of the remaining specification.
288 set->not = !set->not;
292 if (strcmp(s, "none") == 0) {
294 * No numbers are added to the set.
295 * Subsequent is_number_in_set invocations will return set->not.
298 } else if (strcmp(s, "all") == 0) {
300 goto handle_inversion;
304 * Split the string into comma separated tokens.
305 * For each token, find out the corresponding number
306 * by calling FUNC, and add that number to the set.
307 * The absence of tokens or a negative answer
308 * from FUNC is a fatal error.
310 char *copy = xstrdup(s);
311 char *saveptr = NULL;
315 for (token = strtok_r(copy, ",", &saveptr); token;
316 token = strtok_r(NULL, ",", &saveptr)) {
317 number = func(token);
319 error_msg_and_die("invalid %s '%s'", name, token);
322 add_number_to_set(number, set);
328 error_msg_and_die("invalid %s '%s'", name, str);