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