filter.c revision 0e44da35a9d783318f936cce8a4f81f18193ab23
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 <error.h>
23#include <assert.h>
24
25#include "filter.h"
26#include "library.h"
27
28void
29filter_init(struct filter *filt)
30{
31	filt->rules = NULL;
32	filt->next = NULL;
33}
34
35void
36filter_destroy(struct filter *filt)
37{
38	struct filter_rule *it;
39	for (it = filt->rules; it != NULL; ) {
40		struct filter_rule *next = it->next;
41		filter_rule_destroy(it);
42		it = next;
43	}
44}
45
46void
47filter_rule_init(struct filter_rule *rule, enum filter_rule_type type,
48		 struct filter_lib_matcher *matcher,
49		 regex_t symbol_re)
50{
51	rule->type = type;
52	rule->lib_matcher = matcher;
53	rule->symbol_re = symbol_re;
54	rule->next = NULL;
55}
56
57void
58filter_rule_destroy(struct filter_rule *rule)
59{
60	filter_lib_matcher_destroy(rule->lib_matcher);
61	regfree(&rule->symbol_re);
62}
63
64void
65filter_add_rule(struct filter *filt, struct filter_rule *rule)
66{
67	struct filter_rule **rulep;
68	for (rulep = &filt->rules; *rulep != NULL; rulep = &(*rulep)->next)
69		;
70	*rulep = rule;
71}
72
73void
74filter_lib_matcher_name_init(struct filter_lib_matcher *matcher,
75			     enum filter_lib_matcher_type type,
76			     regex_t libname_re)
77{
78	switch (type) {
79	case FLM_MAIN:
80		assert(type != type);
81		abort();
82
83	case FLM_SONAME:
84	case FLM_PATHNAME:
85		matcher->type = type;
86		matcher->libname_re = libname_re;
87	}
88}
89
90void
91filter_lib_matcher_main_init(struct filter_lib_matcher *matcher)
92{
93	matcher->type = FLM_MAIN;
94}
95
96void
97filter_lib_matcher_destroy(struct filter_lib_matcher *matcher)
98{
99	switch (matcher->type) {
100	case FLM_SONAME:
101	case FLM_PATHNAME:
102		regfree(&matcher->libname_re);
103		break;
104	case FLM_MAIN:
105		break;
106	}
107}
108
109static int
110re_match_or_error(regex_t *re, const char *name, const char *what)
111{
112	int status = regexec(re, name, 0, NULL, 0);
113	if (status == 0)
114		return 1;
115	if (status == REG_NOMATCH)
116		return 0;
117
118	char buf[200];
119	regerror(status, re, buf, sizeof buf);
120	error(0, 0, "Error when matching %s: %s", name, buf);
121
122	return 0;
123}
124
125static int
126matcher_matches_library(struct filter_lib_matcher *matcher, struct library *lib)
127{
128	switch (matcher->type) {
129	case FLM_SONAME:
130		return re_match_or_error(&matcher->libname_re, lib->soname,
131					 "library soname");
132	case FLM_PATHNAME:
133		return re_match_or_error(&matcher->libname_re, lib->pathname,
134					 "library pathname");
135	case FLM_MAIN:
136		return lib->type == LT_LIBTYPE_MAIN;
137	}
138	assert(matcher->type != matcher->type);
139	abort();
140}
141
142int
143filter_matches_library(struct filter *filt, struct library *lib)
144{
145	if (filt == NULL)
146		return 0;
147
148	struct filter_rule *it;
149	for (it = filt->rules; it != NULL; it = it->next)
150		switch (it->type) {
151		case FR_ADD:
152			if (matcher_matches_library(it->lib_matcher, lib))
153				return 1;
154		case FR_SUBTRACT:
155			continue;
156		};
157	return 0;
158}
159
160int
161filter_matches_symbol(struct filter *filt,
162		      const char *sym_name, struct library *lib)
163{
164	int matches = 0;
165	for (; filt != NULL; filt = filt->next) {
166		struct filter_rule *it;
167		for (it = filt->rules; it != NULL; it = it->next) {
168			switch (it->type) {
169			case FR_ADD:
170				if (matches)
171					continue;
172				break;
173			case FR_SUBTRACT:
174				if (!matches)
175					continue;
176			}
177
178			if (matcher_matches_library(it->lib_matcher, lib)
179			    && re_match_or_error(&it->symbol_re, sym_name,
180						 "symbol name"))
181				matches = !matches;
182		}
183	}
184	return matches;
185}
186