Home | History | Annotate | Download | only in ltrace
      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