All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* libtracefs: Implement tracefs_filter_functions()
@ 2021-06-15 18:15 Steven Rostedt
  0 siblings, 0 replies; only message in thread
From: Steven Rostedt @ 2021-06-15 18:15 UTC (permalink / raw)
  To: Linux Trace Devel

From: Steven Rostedt (VMware) <rostedt@goodmis.org>

Add a new function that allows the user to get a list of functions that are
available to be filtered. This is useful to see if a function is available
before trying to add a kprobe to it. It can also be used to see what
architecture the code is being run on.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
diff --git a/Documentation/libtracefs-function-filter.txt b/Documentation/libtracefs-function-filter.txt
index 746be37..ac43d9b 100644
--- a/Documentation/libtracefs-function-filter.txt
+++ b/Documentation/libtracefs-function-filter.txt
@@ -5,6 +5,7 @@ NAME
 ----
 tracefs_function_filter - Function to limit kernel functions that are traced
 tracefs_function_notrace - Function to filter kernel functions that not to be traced
+tracefs_filter_functions - Function to list the functions that are available for filtering
 
 SYNOPSIS
 --------
@@ -14,6 +15,7 @@ SYNOPSIS
 
 int *tracefs_function_filter*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_filter_, const char pass:[*]_module_, int _flags_);
 int *tracefs_function_notrace*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_filter_, const char pass:[*]_module_, int _flags_);
+int *tracefs_filter_functions*(const char pass:[*]_filter_, const char pass:[*]_module_, char pass:[*]pass:[*]pass:[*]_list_);
 --
 
 DESCRIPTION
@@ -31,7 +33,12 @@ _module_, to limit the filtering on a specific module (or NULL to filter on all
 _flags_ which holds control knobs on how the filters will be handled (see *FLAGS*)
 section below.
 
-The _filter may be either a straight match of a
+The *tracefs_filter_functions* returns a list of functions that can be filtered on
+via the _filter_ and _module_ that are supplied. If both _filter_ and _module_ are
+NULL then, all available functions that can be filtered is returned.
+On success, _list_ must be freed with *tracefs_list_free()*(3).
+
+The _filter_ may be either a straight match of a
 function, a glob or regex(3). A glob is where 'pass:[*]' matches zero or more
 characters, '?' will match zero or one character, and '.' only matches a
 period. If the _filter_ is determined to be a regex (where it contains
@@ -86,7 +93,9 @@ regular expression.
 
 RETURN VALUE
 ------------
-Returns 0 on success. If the there is an error but the filtering was not
+
+For _tracefs_function_filter_() and _tracefs_function_notrace()_ a
+return of 0 means success. If the there is an error but the filtering was not
 started, then 1 is returned. If filtering was started but an error occurs,
 then -1 is returned. The state of the filtering may be in an unknown state.
 
@@ -94,6 +103,12 @@ If *TRACEFS_FL_CONTINUE* was set, and 0 or -1 was returned, then another call
 to tracefs_function_filter() must be done without *TRACEFS_FL_CONTINUE* set
 in order to commit (and close) the filtering.
 
+For _tracefs_filter_functions_(), a return of 0 means success, and the _list_
+parameter is filled with a list of function names that matched _filter_ and
+_module_. _list_ is a string array, where the last string pointer in the
+array is NULL. The _list_ must be freed with _tracefs_list_free()_.
+On failure, a negative is returned, and _list_ is ignored.
+
 ERRORS
 ------
 
@@ -122,6 +137,7 @@ static const char *filters[] = { "run_init_process", "try_to_run_init_process",
 int main(int argc, char *argv[])
 {
 	struct tracefs_instance *inst = tracefs_instance_create(INST);
+	char **func_list;
 	int ret;
 	int i;
 
@@ -129,6 +145,15 @@ int main(int argc, char *argv[])
 		/* Error creating new trace instance */
 	}
 
+	if (tracefs_filter_functions("*lock*", NULL, &func_list) < 0) {
+		printf("Failed to read filter functions\n");
+		goto out;
+	}
+	printf("Ignoring the following functions:\n");
+	for (i = 0; func_list[i]; i++)
+		printf("  %s\n", func_list[i]);
+	tracefs_free_list(func_list);
+
 	/* Do not trace any function with the word "lock" in it */
 	ret = tracefs_function_notrace(inst, "*lock*", NULL, TRACEFS_FL_RESET);
 	if (ret) {
diff --git a/include/tracefs.h b/include/tracefs.h
index e29b550..44a41d5 100644
--- a/include/tracefs.h
+++ b/include/tracefs.h
@@ -179,6 +179,7 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char *filte
 			    const char *module, unsigned int flags);
 int tracefs_function_notrace(struct tracefs_instance *instance, const char *filter,
 			     const char *module, unsigned int flags);
+int tracefs_filter_functions(const char *filter, const char *module, char ***list);
 
 
 /* Control library logs */
diff --git a/src/tracefs-tools.c b/src/tracefs-tools.c
index 0cbb56d..cb23b68 100644
--- a/src/tracefs-tools.c
+++ b/src/tracefs-tools.c
@@ -378,6 +378,7 @@ bool tracefs_option_mask_is_set(const struct tracefs_options_mask *options,
 
 struct func_list {
 	struct func_list	*next;
+	char			*func;
 	unsigned int		start;
 	unsigned int		end;
 };
@@ -521,6 +522,25 @@ static int add_func(struct func_list ***next_func_ptr, unsigned int index)
 	return add_func(next_func_ptr, index);
 }
 
+static int add_func_str(struct func_list ***next_func_ptr, const char *func)
+{
+	struct func_list **next_func = *next_func_ptr;
+	struct func_list *func_list = *next_func;
+
+	if (!func_list) {
+		func_list = calloc(1, sizeof(*func_list));
+		if (!func_list)
+			return -1;
+		func_list->func = strdup(func);
+		if (!func_list->func)
+			return -1;
+		*next_func = func_list;
+		return 0;
+	}
+	*next_func_ptr = &func_list->next;
+	return add_func_str(next_func_ptr, func);
+}
+
 static void free_func_list(struct func_list *func_list)
 {
 	struct func_list *f;
@@ -528,6 +548,7 @@ static void free_func_list(struct func_list *func_list)
 	while (func_list) {
 		f = func_list;
 		func_list = f->next;
+		free(f->func);
 		free(f);
 	}
 }
@@ -536,6 +557,7 @@ enum match_type {
 	FILTER_CHECK	= (1 << 0),
 	FILTER_WRITE	= (1 << 1),
 	FILTER_FUTURE	= (1 << 2),
+	SAVE_STRING	= (1 << 2),
 };
 
 static int match_filters(int fd, struct func_filter *func_filter,
@@ -543,6 +565,7 @@ static int match_filters(int fd, struct func_filter *func_filter,
 			 int flags)
 {
 	enum match_type type = flags & (FILTER_CHECK | FILTER_WRITE);
+	bool save_str = flags & SAVE_STRING;
 	bool future = flags & FILTER_FUTURE;
 	bool mod_match = false;
 	char *line = NULL;
@@ -593,7 +616,10 @@ static int match_filters(int fd, struct func_filter *func_filter,
 		case FILTER_CHECK:
 			if (match(tok, func_filter)) {
 				func_filter->set = true;
-				ret = add_func(&func_list, index);
+				if (save_str)
+					ret = add_func_str(&func_list, tok);
+				else
+					ret = add_func(&func_list, index);
 				if (ret)
 					goto out;
 			}
@@ -638,6 +664,16 @@ static int check_available_filters(struct func_filter *func_filter,
 	return match_filters(-1, func_filter, module, func_list, flags);
 }
 
+
+static int list_available_filters(struct func_filter *func_filter,
+				   const char *module,
+				   struct func_list **func_list)
+{
+	int flags = FILTER_CHECK | SAVE_STRING;
+
+	return match_filters(-1, func_filter, module, func_list, flags);
+}
+
 static int set_regex_filter(int fd, struct func_filter *func_filter,
 			    const char *module)
 {
@@ -912,3 +948,60 @@ int tracefs_function_notrace(struct tracefs_instance *instance, const char *filt
 	tracefs_put_tracing_file(filter_path);
 	return ret;
 }
+
+/**
+ * tracefs_filter_functions - return a list of available functons that can be filtered
+ * @filter: The filter to filter what functions to list (can be NULL for all)
+ * @module: Module to be traced or NULL if all functions are to be examined.
+ * @list: The list to return the list from (freed by tracefs_list_free() on success)
+ *
+ * Returns a list of function names that match @filter and @module. If both
+ * @filter and @module is NULL, then all available functions that can be filtered
+ * will be returned. (Note, there can be duplicates, if there are more than
+ * one function with the same name.
+ *
+ * On success, zero is returned, and @list contains a list of functions that were
+ * found, and must be freed with tracefs_list_free().
+ * On failure, a negative number is returned, and @list is ignored.
+ */
+int tracefs_filter_functions(const char *filter, const char *module, char ***list)
+{
+	struct func_filter func_filter;
+	struct func_list *func_list, *f;
+	char **funcs = NULL;
+	int cnt = 0;
+	int ret;
+
+	if (!filter)
+		filter = ".*";
+
+	ret = init_func_filter(&func_filter, filter);
+	if (ret < 0)
+		return ret;
+
+	ret = list_available_filters(&func_filter, module, &func_list);
+	if (ret < 0)
+		goto out;
+
+	ret = -1;
+	for (f = func_list; f; f = f->next) {
+		char **tmp;
+
+		tmp = realloc(funcs, sizeof(*funcs) * (cnt + 2));
+		if (!tmp) {
+			tracefs_list_free(funcs);
+			goto out;
+		}
+		tmp[cnt++] = f->func;
+		tmp[cnt] = NULL;
+		f->func = NULL;
+		funcs = tmp;
+	}
+
+	*list = funcs;
+	ret = 0;
+out:
+	regfree(&func_filter.re);
+	free_func_list(func_list);
+	return ret;
+}

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2021-06-15 18:15 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-15 18:15 libtracefs: Implement tracefs_filter_functions() Steven Rostedt

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.