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