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.
33 typedef unsigned int number_slot_t;
34 #define BITS_PER_SLOT (sizeof(number_slot_t) * 8)
43 number_setbit(const unsigned int i, number_slot_t *const vec)
45 vec[i / BITS_PER_SLOT] |= (number_slot_t) 1 << (i % BITS_PER_SLOT);
49 number_isset(const unsigned int i, const number_slot_t *const vec)
51 return vec[i / BITS_PER_SLOT] & ((number_slot_t) 1 << (i % BITS_PER_SLOT));
55 reallocate_number_set(struct number_set *const set, const unsigned int new_nslots)
57 if (new_nslots <= set->nslots)
59 set->vec = xreallocarray(set->vec, new_nslots, sizeof(*set->vec));
60 memset(set->vec + set->nslots, 0,
61 sizeof(*set->vec) * (new_nslots - set->nslots));
62 set->nslots = new_nslots;
66 add_number_to_set(const unsigned int number, struct number_set *const set)
68 reallocate_number_set(set, number / BITS_PER_SLOT + 1);
69 number_setbit(number, set->vec);
73 is_number_in_set(const unsigned int number, const struct number_set *const set)
75 return ((number / BITS_PER_SLOT < set->nslots)
76 && number_isset(number, set->vec)) ^ set->not;
80 qualify_syscall_number(const char *s, struct number_set *set)
82 int n = string_to_uint(s);
89 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
90 if ((unsigned) n >= nsyscall_vec[p]) {
93 add_number_to_set(n, &set[p]);
101 regerror_msg_and_die(int errcode, const regex_t *preg,
102 const char *str, const char *pattern)
106 regerror(errcode, preg, buf, sizeof(buf));
107 error_msg_and_die("%s: %s: %s", str, pattern, buf);
111 qualify_syscall_regex(const char *s, struct number_set *set)
116 if ((rc = regcomp(&preg, s, REG_EXTENDED | REG_NOSUB)) != 0)
117 regerror_msg_and_die(rc, &preg, "regcomp", s);
121 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
124 for (i = 0; i < nsyscall_vec[p]; ++i) {
125 if (!sysent_vec[p][i].sys_name)
127 rc = regexec(&preg, sysent_vec[p][i].sys_name,
129 if (rc == REG_NOMATCH)
132 regerror_msg_and_die(rc, &preg, "regexec", s);
133 add_number_to_set(i, &set[p]);
143 lookup_class(const char *s)
145 static const struct {
148 } syscall_class[] = {
149 { "desc", TRACE_DESC },
150 { "file", TRACE_FILE },
151 { "memory", TRACE_MEMORY },
152 { "process", TRACE_PROCESS },
153 { "signal", TRACE_SIGNAL },
154 { "ipc", TRACE_IPC },
155 { "network", TRACE_NETWORK },
156 { "%desc", TRACE_DESC },
157 { "%file", TRACE_FILE },
158 { "%memory", TRACE_MEMORY },
159 { "%process", TRACE_PROCESS },
160 { "%signal", TRACE_SIGNAL },
161 { "%ipc", TRACE_IPC },
162 { "%network", TRACE_NETWORK },
163 { "%stat", TRACE_STAT },
164 { "%lstat", TRACE_LSTAT },
165 { "%fstat", TRACE_FSTAT },
166 { "%%stat", TRACE_STAT_LIKE },
167 { "%statfs", TRACE_STATFS },
168 { "%fstatfs", TRACE_FSTATFS },
169 { "%%statfs", TRACE_STATFS_LIKE },
173 for (i = 0; i < ARRAY_SIZE(syscall_class); ++i) {
174 if (strcmp(s, syscall_class[i].name) == 0) {
175 return syscall_class[i].value;
183 qualify_syscall_class(const char *s, struct number_set *set)
185 const unsigned int n = lookup_class(s);
190 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
193 for (i = 0; i < nsyscall_vec[p]; ++i) {
194 if (!sysent_vec[p][i].sys_name
195 || (sysent_vec[p][i].sys_flags & n) != n) {
198 add_number_to_set(i, &set[p]);
206 qualify_syscall_name(const char *s, struct number_set *set)
211 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
214 for (i = 0; i < nsyscall_vec[p]; ++i) {
215 if (!sysent_vec[p][i].sys_name
216 || strcmp(s, sysent_vec[p][i].sys_name)) {
219 add_number_to_set(i, &set[p]);
228 qualify_syscall(const char *token, struct number_set *set)
230 bool ignore_fail = false;
232 while (*token == '?') {
236 if (*token >= '0' && *token <= '9')
237 return qualify_syscall_number(token, set) || ignore_fail;
239 return qualify_syscall_regex(token + 1, set) || ignore_fail;
240 return qualify_syscall_class(token, set)
241 || qualify_syscall_name(token, set)
246 * Add syscall numbers to SETs for each supported personality
247 * according to STR specification.
250 qualify_syscall_tokens(const char *const str, struct number_set *const set,
251 const char *const name)
253 /* Clear all sets. */
255 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
257 memset(set[p].vec, 0,
258 sizeof(*set[p].vec) * set[p].nslots);
263 * Each leading ! character means inversion
264 * of the remaining specification.
269 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
270 set[p].not = !set[p].not;
275 if (strcmp(s, "none") == 0) {
277 * No syscall numbers are added to sets.
278 * Subsequent is_number_in_set invocations
279 * will return set[p]->not.
282 } else if (strcmp(s, "all") == 0) {
284 goto handle_inversion;
288 * Split the string into comma separated tokens.
289 * For each token, call qualify_syscall that will take care
290 * if adding appropriate syscall numbers to sets.
291 * The absence of tokens or a negative return code
292 * from qualify_syscall is a fatal error.
294 char *copy = xstrdup(s);
295 char *saveptr = NULL;
299 for (token = strtok_r(copy, ",", &saveptr); token;
300 token = strtok_r(NULL, ",", &saveptr)) {
301 done = qualify_syscall(token, set);
303 error_msg_and_die("invalid %s '%s'", name, token);
310 error_msg_and_die("invalid %s '%s'", name, str);
315 * Add numbers to SET according to STR specification.
318 qualify_tokens(const char *const str, struct number_set *const set,
319 string_to_uint_func func, const char *const name)
323 memset(set->vec, 0, sizeof(*set->vec) * set->nslots);
327 * Each leading ! character means inversion
328 * of the remaining specification.
333 set->not = !set->not;
337 if (strcmp(s, "none") == 0) {
339 * No numbers are added to the set.
340 * Subsequent is_number_in_set invocations will return set->not.
343 } else if (strcmp(s, "all") == 0) {
345 goto handle_inversion;
349 * Split the string into comma separated tokens.
350 * For each token, find out the corresponding number
351 * by calling FUNC, and add that number to the set.
352 * The absence of tokens or a negative answer
353 * from FUNC is a fatal error.
355 char *copy = xstrdup(s);
356 char *saveptr = NULL;
360 for (token = strtok_r(copy, ",", &saveptr); token;
361 token = strtok_r(NULL, ",", &saveptr)) {
362 number = func(token);
364 error_msg_and_die("invalid %s '%s'", name, token);
367 add_number_to_set(number, set);
373 error_msg_and_die("invalid %s '%s'", name, str);