add packaging
[platform/upstream/ltrace.git] / filter.c
1 /*
2  * This file is part of ltrace.
3  * Copyright (C) 2012 Petr Machata, Red Hat Inc.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18  * 02110-1301 USA
19  */
20
21 #include <stdlib.h>
22 #include <assert.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 #include "filter.h"
27 #include "library.h"
28 #include "callback.h"
29
30 void
31 filter_init(struct filter *filt)
32 {
33         filt->rules = NULL;
34         filt->next = NULL;
35 }
36
37 void
38 filter_destroy(struct filter *filt)
39 {
40         struct filter_rule *it;
41         for (it = filt->rules; it != NULL; ) {
42                 struct filter_rule *next = it->next;
43                 filter_rule_destroy(it);
44                 it = next;
45         }
46 }
47
48 void
49 filter_rule_init(struct filter_rule *rule, enum filter_rule_type type,
50                  struct filter_lib_matcher *matcher,
51                  regex_t symbol_re)
52 {
53         rule->type = type;
54         rule->lib_matcher = matcher;
55         rule->symbol_re = symbol_re;
56         rule->next = NULL;
57 }
58
59 void
60 filter_rule_destroy(struct filter_rule *rule)
61 {
62         filter_lib_matcher_destroy(rule->lib_matcher);
63         regfree(&rule->symbol_re);
64 }
65
66 void
67 filter_add_rule(struct filter *filt, struct filter_rule *rule)
68 {
69         struct filter_rule **rulep;
70         for (rulep = &filt->rules; *rulep != NULL; rulep = &(*rulep)->next)
71                 ;
72         *rulep = rule;
73 }
74
75 void
76 filter_lib_matcher_name_init(struct filter_lib_matcher *matcher,
77                              enum filter_lib_matcher_type type,
78                              regex_t libname_re)
79 {
80         switch (type) {
81         case FLM_MAIN:
82                 assert(type != type);
83                 abort();
84
85         case FLM_SONAME:
86         case FLM_PATHNAME:
87                 matcher->type = type;
88                 matcher->libname_re = libname_re;
89         }
90 }
91
92 void
93 filter_lib_matcher_main_init(struct filter_lib_matcher *matcher)
94 {
95         matcher->type = FLM_MAIN;
96 }
97
98 void
99 filter_lib_matcher_destroy(struct filter_lib_matcher *matcher)
100 {
101         switch (matcher->type) {
102         case FLM_SONAME:
103         case FLM_PATHNAME:
104                 regfree(&matcher->libname_re);
105                 break;
106         case FLM_MAIN:
107                 break;
108         }
109 }
110
111 static int
112 re_match_or_error(regex_t *re, const char *name, const char *what)
113 {
114         int status = regexec(re, name, 0, NULL, 0);
115         if (status == 0)
116                 return 1;
117         if (status == REG_NOMATCH)
118                 return 0;
119
120         char buf[200];
121         regerror(status, re, buf, sizeof buf);
122         fprintf(stderr, "Error when matching %s: %s\n", name, buf);
123
124         return 0;
125 }
126
127 static int
128 matcher_matches_library(struct filter_lib_matcher *matcher, struct library *lib)
129 {
130         switch (matcher->type) {
131         case FLM_SONAME:
132                 return re_match_or_error(&matcher->libname_re, lib->soname,
133                                          "library soname");
134         case FLM_PATHNAME:
135                 return re_match_or_error(&matcher->libname_re, lib->pathname,
136                                          "library pathname");
137         case FLM_MAIN:
138                 return lib->type == LT_LIBTYPE_MAIN;
139         }
140         assert(matcher->type != matcher->type);
141         abort();
142 }
143
144 int
145 filter_matches_library(struct filter *filt, struct library *lib)
146 {
147         if (filt == NULL)
148                 return 0;
149
150         for (; filt != NULL; filt = filt->next) {
151                 struct filter_rule *it;
152                 for (it = filt->rules; it != NULL; it = it->next)
153                         switch (it->type) {
154                         case FR_ADD:
155                                 if (matcher_matches_library(it->lib_matcher, lib))
156                                         return 1;
157                         case FR_SUBTRACT:
158                                 continue;
159                         };
160         }
161         return 0;
162 }
163
164 int
165 filter_matches_symbol(struct filter *filt,
166                       const char *sym_name, struct library *lib)
167 {
168         for (; filt != NULL; filt = filt->next) {
169                 int matches = 0;
170                 struct filter_rule *it;
171                 for (it = filt->rules; it != NULL; it = it->next) {
172                         switch (it->type) {
173                         case FR_ADD:
174                                 if (matches)
175                                         continue;
176                                 break;
177                         case FR_SUBTRACT:
178                                 if (!matches)
179                                         continue;
180                         }
181
182                         if (matcher_matches_library(it->lib_matcher, lib)
183                             && re_match_or_error(&it->symbol_re, sym_name,
184                                                  "symbol name"))
185                                 matches = !matches;
186                 }
187                 if (matches)
188                         return 1;
189         }
190         return 0;
191 }