]> granicus.if.org Git - strace/blob - basic_filters.c
mem: decode hugetlb page size in mmap flags
[strace] / basic_filters.c
1 /*
2  * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
3  * Copyright (c) 2016-2017 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         unsigned int p;
42         bool done = false;
43
44         for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
45                 if ((unsigned) n >= nsyscall_vec[p]) {
46                         continue;
47                 }
48                 add_number_to_set_array(n, set, p);
49                 done = true;
50         }
51
52         return done;
53 }
54
55 static void
56 regerror_msg_and_die(int errcode, const regex_t *preg,
57                      const char *str, const char *pattern)
58 {
59         char buf[512];
60
61         regerror(errcode, preg, buf, sizeof(buf));
62         error_msg_and_die("%s: %s: %s", str, pattern, buf);
63 }
64
65 static bool
66 qualify_syscall_regex(const char *s, struct number_set *set)
67 {
68         regex_t preg;
69         int rc;
70
71         if ((rc = regcomp(&preg, s, REG_EXTENDED | REG_NOSUB)) != 0)
72                 regerror_msg_and_die(rc, &preg, "regcomp", s);
73
74         unsigned int p;
75         bool found = false;
76         for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
77                 unsigned int i;
78
79                 for (i = 0; i < nsyscall_vec[p]; ++i) {
80                         if (!sysent_vec[p][i].sys_name)
81                                 continue;
82                         rc = regexec(&preg, sysent_vec[p][i].sys_name,
83                                      0, NULL, 0);
84                         if (rc == REG_NOMATCH)
85                                 continue;
86                         else if (rc)
87                                 regerror_msg_and_die(rc, &preg, "regexec", s);
88                         add_number_to_set_array(i, set, p);
89                         found = true;
90                 }
91         }
92
93         regfree(&preg);
94         return found;
95 }
96
97 static unsigned int
98 lookup_class(const char *s)
99 {
100         static const struct {
101                 const char *name;
102                 unsigned int value;
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       },
125         };
126
127         unsigned int i;
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;
131                 }
132         }
133
134         return 0;
135 }
136
137 static bool
138 qualify_syscall_class(const char *s, struct number_set *set)
139 {
140         const unsigned int n = lookup_class(s);
141         if (!n)
142                 return false;
143
144         unsigned int p;
145         for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
146                 unsigned int i;
147
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) {
151                                 continue;
152                         }
153                         add_number_to_set_array(i, set, p);
154                 }
155         }
156
157         return true;
158 }
159
160 static bool
161 qualify_syscall_name(const char *s, struct number_set *set)
162 {
163         unsigned int p;
164         bool found = false;
165
166         for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
167                 unsigned int i;
168
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)) {
172                                 continue;
173                         }
174                         add_number_to_set_array(i, set, p);
175                         found = true;
176                 }
177         }
178
179         return found;
180 }
181
182 static bool
183 qualify_syscall(const char *token, struct number_set *set)
184 {
185         bool ignore_fail = false;
186
187         while (*token == '?') {
188                 token++;
189                 ignore_fail = true;
190         }
191         if (*token >= '0' && *token <= '9')
192                 return qualify_syscall_number(token, set) || ignore_fail;
193         if (*token == '/')
194                 return qualify_syscall_regex(token + 1, set) || ignore_fail;
195         return qualify_syscall_class(token, set)
196                || qualify_syscall_name(token, set)
197                || ignore_fail;
198 }
199
200 /*
201  * Add syscall numbers to SETs for each supported personality
202  * according to STR specification.
203  */
204 void
205 qualify_syscall_tokens(const char *const str, struct number_set *const set,
206                        const char *const name)
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 handle_inversion:
217         while (*s == '!') {
218                 invert_number_set_array(set, SUPPORTED_PERSONALITIES);
219                 ++s;
220         }
221
222         if (strcmp(s, "none") == 0) {
223                 /*
224                  * No syscall numbers are added to sets.
225                  * Subsequent is_number_in_set* invocations
226                  * will return set[p]->not.
227                  */
228                 return;
229         } else if (strcmp(s, "all") == 0) {
230                 s = "!none";
231                 goto handle_inversion;
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         const char *token;
244         bool done = false;
245
246         for (token = strtok_r(copy, ",", &saveptr); token;
247              token = strtok_r(NULL, ",", &saveptr)) {
248                 done = qualify_syscall(token, set);
249                 if (!done) {
250                         error_msg_and_die("invalid %s '%s'", name, token);
251                 }
252         }
253
254         free(copy);
255
256         if (!done) {
257                 error_msg_and_die("invalid %s '%s'", name, str);
258         }
259 }
260
261 /*
262  * Add numbers to SET according to STR specification.
263  */
264 void
265 qualify_tokens(const char *const str, struct number_set *const set,
266                string_to_uint_func func, const char *const name)
267 {
268         /* Clear the set. */
269         clear_number_set_array(set, 1);
270
271         /*
272          * Each leading ! character means inversion
273          * of the remaining specification.
274          */
275         const char *s = str;
276 handle_inversion:
277         while (*s == '!') {
278                 invert_number_set_array(set, 1);
279                 ++s;
280         }
281
282         if (strcmp(s, "none") == 0) {
283                 /*
284                  * No numbers are added to the set.
285                  * Subsequent is_number_in_set* invocations
286                  * will return set->not.
287                  */
288                 return;
289         } else if (strcmp(s, "all") == 0) {
290                 s = "!none";
291                 goto handle_inversion;
292         }
293
294         /*
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.
300          */
301         char *copy = xstrdup(s);
302         char *saveptr = NULL;
303         const char *token;
304         int number = -1;
305
306         for (token = strtok_r(copy, ",", &saveptr); token;
307              token = strtok_r(NULL, ",", &saveptr)) {
308                 number = func(token);
309                 if (number < 0) {
310                         error_msg_and_die("invalid %s '%s'", name, token);
311                 }
312
313                 add_number_to_set(number, set);
314         }
315
316         free(copy);
317
318         if (number < 0) {
319                 error_msg_and_die("invalid %s '%s'", name, str);
320         }
321 }