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