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