filter.c revision 391318fb9b1f0f0f67b642309f5c9e94557f8568
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 rule->next = filt->rules; 68 filt->rules = rule; 69} 70 71void 72filter_lib_matcher_name_init(struct filter_lib_matcher *matcher, 73 enum filter_lib_matcher_type type, 74 regex_t libname_re) 75{ 76 switch (type) { 77 case FLM_MAIN: 78 assert(type != type); 79 abort(); 80 81 case FLM_SONAME: 82 case FLM_PATHNAME: 83 matcher->type = type; 84 matcher->libname_re = libname_re; 85 } 86} 87 88void 89filter_lib_matcher_main_init(struct filter_lib_matcher *matcher) 90{ 91 matcher->type = FLM_MAIN; 92} 93 94void 95filter_lib_matcher_destroy(struct filter_lib_matcher *matcher) 96{ 97 switch (matcher->type) { 98 case FLM_SONAME: 99 case FLM_PATHNAME: 100 regfree(&matcher->libname_re); 101 break; 102 case FLM_MAIN: 103 break; 104 } 105} 106 107static int 108re_match_or_error(regex_t *re, const char *name, const char *what) 109{ 110 int status = regexec(re, name, 0, NULL, 0); 111 if (status == 0) 112 return 1; 113 if (status == REG_NOMATCH) 114 return 0; 115 116 char buf[200]; 117 regerror(status, re, buf, sizeof buf); 118 error(0, 0, "Error when matching %s: %s", name, buf); 119 120 return 0; 121} 122 123static int 124matcher_matches_library(struct filter_lib_matcher *matcher, struct library *lib) 125{ 126 switch (matcher->type) { 127 case FLM_SONAME: 128 return re_match_or_error(&matcher->libname_re, lib->soname, 129 "library soname"); 130 case FLM_PATHNAME: 131 return re_match_or_error(&matcher->libname_re, lib->pathname, 132 "library pathname"); 133 case FLM_MAIN: 134 return lib->type == LT_LIBTYPE_MAIN; 135 } 136 assert(matcher->type != matcher->type); 137 abort(); 138} 139 140int 141filter_matches_library(struct filter *filt, struct library *lib) 142{ 143 if (filt == NULL) 144 return 0; 145 146 struct filter_rule *it; 147 for (it = filt->rules; it != NULL; it = it->next) 148 switch (it->type) { 149 case FR_ADD: 150 if (matcher_matches_library(it->lib_matcher, lib)) 151 return 1; 152 case FR_SUBTRACT: 153 continue; 154 }; 155 return 0; 156} 157 158int 159filter_matches_symbol(struct filter *filt, 160 const char *sym_name, struct library *lib) 161{ 162 int matches = 0; 163 for (; filt != NULL; filt = filt->next) { 164 struct filter_rule *it; 165 for (it = filt->rules; it != NULL; it = it->next) { 166 switch (it->type) { 167 case FR_ADD: 168 if (matches) 169 continue; 170 break; 171 case FR_SUBTRACT: 172 if (!matches) 173 continue; 174 } 175 176 if (matcher_matches_library(it->lib_matcher, lib) 177 && re_match_or_error(&it->symbol_re, sym_name, 178 "symbol name")) 179 matches = !matches; 180 } 181 } 182 return matches; 183} 184