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 30void 31filter_init(struct filter *filt) 32{ 33 filt->rules = NULL; 34 filt->next = NULL; 35} 36 37void 38filter_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 48void 49filter_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 59void 60filter_rule_destroy(struct filter_rule *rule) 61{ 62 filter_lib_matcher_destroy(rule->lib_matcher); 63 regfree(&rule->symbol_re); 64} 65 66void 67filter_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 75void 76filter_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 92void 93filter_lib_matcher_main_init(struct filter_lib_matcher *matcher) 94{ 95 matcher->type = FLM_MAIN; 96} 97 98void 99filter_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 111static int 112re_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 127static int 128matcher_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 144int 145filter_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 164int 165filter_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