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_array(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_array(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_array(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_array(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. */
209 clear_number_set_array(set, SUPPORTED_PERSONALITIES);
212 * Each leading ! character means inversion
213 * of the remaining specification.
218 invert_number_set_array(set, SUPPORTED_PERSONALITIES);
222 if (strcmp(s, "none") == 0) {
224 * No syscall numbers are added to sets.
225 * Subsequent is_number_in_set* invocations
226 * will return set[p]->not.
229 } else if (strcmp(s, "all") == 0) {
231 goto handle_inversion;
235 * Split the string into comma separated tokens.
236 * For each token, call qualify_syscall that will take care
237 * if adding appropriate syscall numbers to sets.
238 * The absence of tokens or a negative return code
239 * from qualify_syscall is a fatal error.
241 char *copy = xstrdup(s);
242 char *saveptr = NULL;
246 for (token = strtok_r(copy, ",", &saveptr); token;
247 token = strtok_r(NULL, ",", &saveptr)) {
248 done = qualify_syscall(token, set);
250 error_msg_and_die("invalid %s '%s'", name, token);
257 error_msg_and_die("invalid %s '%s'", name, str);
262 * Add numbers to SET according to STR specification.
265 qualify_tokens(const char *const str, struct number_set *const set,
266 string_to_uint_func func, const char *const name)
269 clear_number_set_array(set, 1);
272 * Each leading ! character means inversion
273 * of the remaining specification.
278 invert_number_set_array(set, 1);
282 if (strcmp(s, "none") == 0) {
284 * No numbers are added to the set.
285 * Subsequent is_number_in_set* invocations
286 * will return set->not.
289 } else if (strcmp(s, "all") == 0) {
291 goto handle_inversion;
295 * Split the string into comma separated tokens.
296 * For each token, find out the corresponding number
297 * by calling FUNC, and add that number to the set.
298 * The absence of tokens or a negative answer
299 * from FUNC is a fatal error.
301 char *copy = xstrdup(s);
302 char *saveptr = NULL;
306 for (token = strtok_r(copy, ",", &saveptr); token;
307 token = strtok_r(NULL, ",", &saveptr)) {
308 number = func(token);
310 error_msg_and_die("invalid %s '%s'", name, token);
313 add_number_to_set(number, set);
319 error_msg_and_die("invalid %s '%s'", name, str);