2 * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
3 * Copyright (c) 2016-2018 The strace developers.
6 * SPDX-License-Identifier: LGPL-2.1-or-later
14 #include "number_set.h"
19 * Checks whether a @-separated personality specification suffix is present.
20 * Personality suffix is a one of strings stored in personality_designators
23 * @param[in] s Specification string to check.
24 * @param[out] p Where to store personality number if it is found.
25 * @return If personality is found, the provided string is copied without
26 * suffix and returned as a result (callee should de-alllocate it
27 * with free() after use), and personality number is written to p.
28 * Otherwise, NULL is returned and p is untouched.
31 qualify_syscall_separate_personality(const char *s, unsigned int *p)
33 char *pos = strchr(s, '@');
38 for (unsigned int i = 0; i < SUPPORTED_PERSONALITIES; i++) {
39 if (!strcmp(pos + 1, personality_designators[i])) {
41 return xstrndup(s, pos - s);
45 error_msg_and_help("incorrect personality designator '%s'"
46 " in qualification '%s'", pos + 1, s);
50 qualify_syscall_number_personality(int n, unsigned int p,
51 struct number_set *set)
53 if ((unsigned int) n >= nsyscall_vec[p])
56 add_number_to_set_array(n, set, p);
62 qualify_syscall_number(const char *s, struct number_set *set)
65 char *num_str = qualify_syscall_separate_personality(s, &p);
69 n = string_to_uint(num_str);
75 return qualify_syscall_number_personality(n, p, set);
78 n = string_to_uint(s);
84 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p)
85 done |= qualify_syscall_number_personality(n, p, set);
91 regerror_msg_and_die(int errcode, const regex_t *preg,
92 const char *str, const char *pattern)
96 regerror(errcode, preg, buf, sizeof(buf));
97 error_msg_and_die("%s: %s: %s", str, pattern, buf);
101 qualify_syscall_regex(const char *s, struct number_set *set)
106 if ((rc = regcomp(&preg, s, REG_EXTENDED | REG_NOSUB)) != 0)
107 regerror_msg_and_die(rc, &preg, "regcomp", s);
111 for (unsigned int p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
112 for (unsigned int i = 0; i < nsyscall_vec[p]; ++i) {
113 if (!sysent_vec[p][i].sys_name)
116 rc = regexec(&preg, sysent_vec[p][i].sys_name,
119 if (rc == REG_NOMATCH) {
121 char *pos = stpcpy(name_buf,
122 sysent_vec[p][i].sys_name);
124 (void) xappendstr(name_buf, pos, "@%s",
125 personality_designators[p]);
127 rc = regexec(&preg, name_buf, 0, NULL, 0);
130 if (rc == REG_NOMATCH)
133 regerror_msg_and_die(rc, &preg, "regexec", s);
135 add_number_to_set_array(i, set, p);
145 lookup_class(const char *s)
147 static const struct {
150 } syscall_class[] = {
151 { "%desc", TRACE_DESC },
152 { "%file", TRACE_FILE },
153 { "%memory", TRACE_MEMORY },
154 { "%process", TRACE_PROCESS },
155 { "%signal", TRACE_SIGNAL },
156 { "%ipc", TRACE_IPC },
157 { "%net", TRACE_NETWORK },
158 { "%network", TRACE_NETWORK },
159 { "%stat", TRACE_STAT },
160 { "%lstat", TRACE_LSTAT },
161 { "%fstat", TRACE_FSTAT },
162 { "%%stat", TRACE_STAT_LIKE },
163 { "%statfs", TRACE_STATFS },
164 { "%fstatfs", TRACE_FSTATFS },
165 { "%%statfs", TRACE_STATFS_LIKE },
166 { "%pure", TRACE_PURE },
167 /* legacy class names */
168 { "desc", TRACE_DESC },
169 { "file", TRACE_FILE },
170 { "memory", TRACE_MEMORY },
171 { "process", TRACE_PROCESS },
172 { "signal", TRACE_SIGNAL },
173 { "ipc", TRACE_IPC },
174 { "network", TRACE_NETWORK },
177 for (unsigned int i = 0; i < ARRAY_SIZE(syscall_class); ++i) {
178 if (strcmp(s, syscall_class[i].name) == 0)
179 return syscall_class[i].value;
186 qualify_syscall_class(const char *s, struct number_set *set)
188 const unsigned int n = lookup_class(s);
192 for (unsigned int p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
193 for (unsigned int i = 0; i < nsyscall_vec[p]; ++i) {
194 if (sysent_vec[p][i].sys_name &&
195 (sysent_vec[p][i].sys_flags & n) == n)
196 add_number_to_set_array(i, set, p);
204 scno_by_name(const char *s, unsigned int p, kernel_long_t start)
206 if (p >= SUPPORTED_PERSONALITIES)
209 for (kernel_ulong_t i = start; i < nsyscall_vec[p]; ++i) {
210 if (sysent_vec[p][i].sys_name &&
211 strcmp(s, sysent_vec[p][i].sys_name) == 0)
219 qualify_syscall_name_personality(const char *s, unsigned int p,
220 struct number_set *set)
224 for (kernel_long_t scno = 0; (scno = scno_by_name(s, p, scno)) >= 0;
226 add_number_to_set_array(scno, set, p);
234 qualify_syscall_name(const char *s, struct number_set *set)
237 char *name_str = qualify_syscall_separate_personality(s, &p);
241 found = qualify_syscall_name_personality(name_str, p, set);
247 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p)
248 found |= qualify_syscall_name_personality(s, p, set);
254 qualify_syscall(const char *token, struct number_set *set)
256 bool ignore_fail = false;
258 while (*token == '?') {
262 if (*token >= '0' && *token <= '9')
263 return qualify_syscall_number(token, set) || ignore_fail;
265 return qualify_syscall_regex(token + 1, set) || ignore_fail;
266 return qualify_syscall_class(token, set)
267 || qualify_syscall_name(token, set)
272 * Add syscall numbers to SETs for each supported personality
273 * according to STR specification.
276 qualify_syscall_tokens(const char *const str, struct number_set *const set)
278 /* Clear all sets. */
279 clear_number_set_array(set, SUPPORTED_PERSONALITIES);
282 * Each leading ! character means inversion
283 * of the remaining specification.
287 invert_number_set_array(set, SUPPORTED_PERSONALITIES);
291 if (strcmp(s, "none") == 0) {
293 * No syscall numbers are added to sets.
294 * Subsequent is_number_in_set* invocations
295 * will return set[p]->not.
298 } else if (strcmp(s, "all") == 0) {
299 /* "all" == "!none" */
300 invert_number_set_array(set, SUPPORTED_PERSONALITIES);
305 * Split the string into comma separated tokens.
306 * For each token, call qualify_syscall that will take care
307 * if adding appropriate syscall numbers to sets.
308 * The absence of tokens or a negative return code
309 * from qualify_syscall is a fatal error.
311 char *copy = xstrdup(s);
312 char *saveptr = NULL;
315 for (const char *token = strtok_r(copy, ",", &saveptr);
316 token; token = strtok_r(NULL, ",", &saveptr)) {
317 done = qualify_syscall(token, set);
319 error_msg_and_die("invalid system call '%s'", token);
325 error_msg_and_die("invalid system call '%s'", str);
329 * Add numbers to SET according to STR specification.
332 qualify_tokens(const char *const str, struct number_set *const set,
333 string_to_uint_func func, const char *const name)
336 clear_number_set_array(set, 1);
339 * Each leading ! character means inversion
340 * of the remaining specification.
344 invert_number_set_array(set, 1);
348 if (strcmp(s, "none") == 0) {
350 * No numbers are added to the set.
351 * Subsequent is_number_in_set* invocations
352 * will return set->not.
355 } else if (strcmp(s, "all") == 0) {
356 /* "all" == "!none" */
357 invert_number_set_array(set, 1);
362 * Split the string into comma separated tokens.
363 * For each token, find out the corresponding number
364 * by calling FUNC, and add that number to the set.
365 * The absence of tokens or a negative answer
366 * from FUNC is a fatal error.
368 char *copy = xstrdup(s);
369 char *saveptr = NULL;
372 for (const char *token = strtok_r(copy, ",", &saveptr);
373 token; token = strtok_r(NULL, ",", &saveptr)) {
374 number = func(token);
376 error_msg_and_die("invalid %s '%s'", name, token);
378 add_number_to_set(number, set);
384 error_msg_and_die("invalid %s '%s'", name, str);