]> granicus.if.org Git - strace/blob - basic_filters.c
tests: add variants of IPC tests with different xlat verbosity levels
[strace] / basic_filters.c
1 /*
2  * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
3  * Copyright (c) 2016-2018 The strace developers.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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.
16  *
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.
27  */
28
29 #include "defs.h"
30 #include "number_set.h"
31 #include "filter.h"
32 #include <regex.h>
33
34 static bool
35 qualify_syscall_number(const char *s, struct number_set *set)
36 {
37         int n = string_to_uint(s);
38         if (n < 0)
39                 return false;
40
41         bool done = false;
42
43         for (unsigned int p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
44                 if ((unsigned) n >= nsyscall_vec[p])
45                         continue;
46                 add_number_to_set_array(n, set, p);
47                 done = true;
48         }
49
50         return done;
51 }
52
53 static void
54 regerror_msg_and_die(int errcode, const regex_t *preg,
55                      const char *str, const char *pattern)
56 {
57         char buf[512];
58
59         regerror(errcode, preg, buf, sizeof(buf));
60         error_msg_and_die("%s: %s: %s", str, pattern, buf);
61 }
62
63 static bool
64 qualify_syscall_regex(const char *s, struct number_set *set)
65 {
66         regex_t preg;
67         int rc;
68
69         if ((rc = regcomp(&preg, s, REG_EXTENDED | REG_NOSUB)) != 0)
70                 regerror_msg_and_die(rc, &preg, "regcomp", s);
71
72         bool found = false;
73
74         for (unsigned int p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
75                 for (unsigned int i = 0; i < nsyscall_vec[p]; ++i) {
76                         if (!sysent_vec[p][i].sys_name)
77                                 continue;
78                         rc = regexec(&preg, sysent_vec[p][i].sys_name,
79                                      0, NULL, 0);
80                         if (rc == REG_NOMATCH)
81                                 continue;
82                         else if (rc)
83                                 regerror_msg_and_die(rc, &preg, "regexec", s);
84                         add_number_to_set_array(i, set, p);
85                         found = true;
86                 }
87         }
88
89         regfree(&preg);
90         return found;
91 }
92
93 static unsigned int
94 lookup_class(const char *s)
95 {
96         static const struct {
97                 const char *name;
98                 unsigned int value;
99         } syscall_class[] = {
100                 { "%desc",      TRACE_DESC      },
101                 { "%file",      TRACE_FILE      },
102                 { "%memory",    TRACE_MEMORY    },
103                 { "%process",   TRACE_PROCESS   },
104                 { "%signal",    TRACE_SIGNAL    },
105                 { "%ipc",       TRACE_IPC       },
106                 { "%network",   TRACE_NETWORK   },
107                 { "%stat",      TRACE_STAT      },
108                 { "%lstat",     TRACE_LSTAT     },
109                 { "%fstat",     TRACE_FSTAT     },
110                 { "%%stat",     TRACE_STAT_LIKE },
111                 { "%statfs",    TRACE_STATFS    },
112                 { "%fstatfs",   TRACE_FSTATFS   },
113                 { "%%statfs",   TRACE_STATFS_LIKE       },
114                 { "%pure",      TRACE_PURE      },
115                 /* legacy class names */
116                 { "desc",       TRACE_DESC      },
117                 { "file",       TRACE_FILE      },
118                 { "memory",     TRACE_MEMORY    },
119                 { "process",    TRACE_PROCESS   },
120                 { "signal",     TRACE_SIGNAL    },
121                 { "ipc",        TRACE_IPC       },
122                 { "network",    TRACE_NETWORK   },
123         };
124
125         for (unsigned int i = 0; i < ARRAY_SIZE(syscall_class); ++i) {
126                 if (strcmp(s, syscall_class[i].name) == 0)
127                         return syscall_class[i].value;
128         }
129
130         return 0;
131 }
132
133 static bool
134 qualify_syscall_class(const char *s, struct number_set *set)
135 {
136         const unsigned int n = lookup_class(s);
137         if (!n)
138                 return false;
139
140         for (unsigned int p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
141                 for (unsigned int i = 0; i < nsyscall_vec[p]; ++i) {
142                         if (sysent_vec[p][i].sys_name &&
143                             (sysent_vec[p][i].sys_flags & n) == n)
144                                 add_number_to_set_array(i, set, p);
145                 }
146         }
147
148         return true;
149 }
150
151 kernel_long_t
152 scno_by_name(const char *s, unsigned int p, kernel_long_t start)
153 {
154         if (p >= SUPPORTED_PERSONALITIES)
155                 return -1;
156
157         for (kernel_ulong_t i = start; i < nsyscall_vec[p]; ++i) {
158                 if (sysent_vec[p][i].sys_name &&
159                     strcmp(s, sysent_vec[p][i].sys_name) == 0)
160                         return i;
161         }
162
163         return -1;
164 }
165
166 static bool
167 qualify_syscall_name(const char *s, struct number_set *set)
168 {
169         bool found = false;
170
171         for (unsigned int p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
172                 for (kernel_long_t scno = 0;
173                      (scno = scno_by_name(s, p, scno)) >= 0;
174                      ++scno) {
175                         add_number_to_set_array(scno, set, p);
176                         found = true;
177                 }
178         }
179
180         return found;
181 }
182
183 static bool
184 qualify_syscall(const char *token, struct number_set *set)
185 {
186         bool ignore_fail = false;
187
188         while (*token == '?') {
189                 token++;
190                 ignore_fail = true;
191         }
192         if (*token >= '0' && *token <= '9')
193                 return qualify_syscall_number(token, set) || ignore_fail;
194         if (*token == '/')
195                 return qualify_syscall_regex(token + 1, set) || ignore_fail;
196         return qualify_syscall_class(token, set)
197                || qualify_syscall_name(token, set)
198                || ignore_fail;
199 }
200
201 /*
202  * Add syscall numbers to SETs for each supported personality
203  * according to STR specification.
204  */
205 void
206 qualify_syscall_tokens(const char *const str, struct number_set *const set)
207 {
208         /* Clear all sets. */
209         clear_number_set_array(set, SUPPORTED_PERSONALITIES);
210
211         /*
212          * Each leading ! character means inversion
213          * of the remaining specification.
214          */
215         const char *s = str;
216         while (*s == '!') {
217                 invert_number_set_array(set, SUPPORTED_PERSONALITIES);
218                 ++s;
219         }
220
221         if (strcmp(s, "none") == 0) {
222                 /*
223                  * No syscall numbers are added to sets.
224                  * Subsequent is_number_in_set* invocations
225                  * will return set[p]->not.
226                  */
227                 return;
228         } else if (strcmp(s, "all") == 0) {
229                 /* "all" == "!none" */
230                 invert_number_set_array(set, SUPPORTED_PERSONALITIES);
231                 return;
232         }
233
234         /*
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.
240          */
241         char *copy = xstrdup(s);
242         char *saveptr = NULL;
243         bool done = false;
244
245         for (const char *token = strtok_r(copy, ",", &saveptr);
246              token; token = strtok_r(NULL, ",", &saveptr)) {
247                 done = qualify_syscall(token, set);
248                 if (!done)
249                         error_msg_and_die("invalid system call '%s'", token);
250         }
251
252         free(copy);
253
254         if (!done)
255                 error_msg_and_die("invalid system call '%s'", str);
256 }
257
258 /*
259  * Add numbers to SET according to STR specification.
260  */
261 void
262 qualify_tokens(const char *const str, struct number_set *const set,
263                string_to_uint_func func, const char *const name)
264 {
265         /* Clear the set. */
266         clear_number_set_array(set, 1);
267
268         /*
269          * Each leading ! character means inversion
270          * of the remaining specification.
271          */
272         const char *s = str;
273         while (*s == '!') {
274                 invert_number_set_array(set, 1);
275                 ++s;
276         }
277
278         if (strcmp(s, "none") == 0) {
279                 /*
280                  * No numbers are added to the set.
281                  * Subsequent is_number_in_set* invocations
282                  * will return set->not.
283                  */
284                 return;
285         } else if (strcmp(s, "all") == 0) {
286                 /* "all" == "!none" */
287                 invert_number_set_array(set, 1);
288                 return;
289         }
290
291         /*
292          * Split the string into comma separated tokens.
293          * For each token, find out the corresponding number
294          * by calling FUNC, and add that number to the set.
295          * The absence of tokens or a negative answer
296          * from FUNC is a fatal error.
297          */
298         char *copy = xstrdup(s);
299         char *saveptr = NULL;
300         int number = -1;
301
302         for (const char *token = strtok_r(copy, ",", &saveptr);
303              token; token = strtok_r(NULL, ",", &saveptr)) {
304                 number = func(token);
305                 if (number < 0)
306                         error_msg_and_die("invalid %s '%s'", name, token);
307
308                 add_number_to_set(number, set);
309         }
310
311         free(copy);
312
313         if (number < 0)
314                 error_msg_and_die("invalid %s '%s'", name, str);
315 }