new file mode 100644
@@ -0,0 +1,329 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_event_append_filter, tracefs_event_verify_filter - Add and verify event filters
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+int tracefs_event_append_filter(struct tep_event pass:[*]event, char pass:[**] filter,
+ struct tracefs_filter type, const char pass:[*]field,
+ enum tracefs_synth_compare compare, const char pass:[*]val);
+int tracefs_event_verify_filter(struct tep_event pass:[*]event, const char pass:[*]filter, char pass:[**]err);
+
+--
+
+DESCRIPTION
+-----------
+*tracefs_event_append_filter*() is a way to create and verify event filters for
+a given event. It will verify that the _field_ belongs to the event and that
+the _compare_ option that is used is valid for the type of the field, as well
+as _val_. For the _type_ that is not of *TRACEFS_FILTER_COMPARE*, it will build
+the logical string and also make sure that the syntax is correct. For example,
+there are no more close parenthesis than open parenthesis. An AND (&&) or OR
+(||) is not misplaced, etc.
+
+*tracefs_synth_append_start_filter*() creates a filter or appends to it for the
+starting event. Depending on _type_, it will build a string of tokens for
+parenthesis or logic statemens, or it may add a comparison of _field_
+to _val_ based on _compare_.
+
+If _type_ is:
+*TRACEFS_FILTER_COMPARE* - See below
+*TRACEFS_FILTER_AND* - Append "&&" to the filter
+*TRACEFS_FILTER_OR* - Append "||" to the filter
+*TRACEFS_FILTER_NOT* - Append "!" to the filter
+*TRACEFS_FILTER_OPEN_PAREN* - Append "(" to the filter
+*TRACEFS_FILTER_CLOSE_PAREN* - Append ")" to the filter
+
+_field_, _compare_, and _val_ are ignored unless _type_ is equal to
+*TRACEFS_FILTER_COMPARE*, then _compare will be used for the following:
+
+*TRACEFS_COMPARE_EQ* - _field_ == _val_
+
+*TRACEFS_COMPARE_NE* - _field_ != _val_
+
+*TRACEFS_COMPARE_GT* - _field_ > _val_
+
+*TRACEFS_COMPARE_GE* - _field_ >= _val_
+
+*TRACEFS_COMPARE_LT* - _field_ < _val_
+
+*TRACEFS_COMPARE_LE* - _field_ <pass:[=] _val_
+
+*TRACEFS_COMPARE_RE* - _field_ ~ "_val_" : where _field_ is a string.
+
+*TRACEFS_COMPARE_AND* - _field_ & _val_ : where _field_ is a flags field.
+
+*tracefs_event_verify_filter*() will parse _filter_ to make sure that the
+fields are for the _event_, and that the syntax is correct. If there's an
+error in the syntax, and _err_ is not NULL, then it will be allocated with an
+error message stating what was found wrong with the filter. _err_ must be freed
+with *free*().
+
+RETURN VALUE
+------------
+*tracefs_event_append_filter*() returns 0 on success and -1 on error.
+
+*tracefs_event_verify_filter*() returns 0 on success and -1 on error. if there
+is an error, and _errno_ is not *ENOMEM*, then _err_ is allocated and will
+contain a string describing what was found wrong with _filter_. _err_ must be
+freed with *free*().
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <tracefs.h>
+
+static void usage(char **argv)
+{
+ fprintf(stderr, "usage: %s [system] event filter\n", argv[0]);
+ exit(-1);
+}
+
+int main (int argc, char **argv)
+{
+ struct tep_handle *tep;
+ struct tep_event *event;
+ const char *system = NULL;
+ const char *event_name;
+ const char *filter;
+ char *new_filter = NULL;
+ char *err = NULL;
+ int i;
+
+ if (argc < 3)
+ usage(argv);
+
+ if (argc < 4) {
+ event_name = argv[1];
+ filter = argv[2];
+ } else {
+ system = argv[1];
+ event_name = argv[2];
+ filter = argv[3];
+ }
+
+ /* Load all events from the system */
+ tep = tracefs_local_events(NULL);
+ if (!tep) {
+ perror("tep");
+ exit(-1);
+ }
+
+ event = tep_find_event_by_name(tep, system, event_name);
+ if (!event) {
+ fprintf(stderr, "Event %s%s%s not found\n",
+ system ? system : "" , system ? " " : "",
+ event_name);
+ exit(-1);
+ }
+
+ if (tracefs_event_verify_filter(event, filter, &err) < 0) {
+ perror("tracecfs_event_verify_filter");
+ if (err)
+ fprintf(stderr, "%s", err);
+ free(err);
+ exit(-1);
+ }
+
+ for (i = 0; filter[i]; i++) {
+ char buf[strlen(filter)];
+ char *field = NULL;
+ char *val = NULL;
+ enum tracefs_filter type;
+ enum tracefs_compare compare = 0;
+ int start_i, n;
+ int quote;
+ bool backslash;
+
+ while (isspace(filter[i]))
+ i++;
+
+ switch(filter[i]) {
+ case '(':
+ type = TRACEFS_FILTER_OPEN_PAREN;
+ break;
+ case ')':
+ type = TRACEFS_FILTER_CLOSE_PAREN;
+ break;
+ case '!':
+ type = TRACEFS_FILTER_NOT;
+ break;
+ case '&':
+ type = TRACEFS_FILTER_AND;
+ i++;
+ break;
+ case '|':
+ type = TRACEFS_FILTER_OR;
+ i++;
+ break;
+ default:
+ type = TRACEFS_FILTER_COMPARE;
+
+ while (isspace(filter[i]))
+ i++;
+
+ start_i = i;
+ for (; filter[i]; i++) {
+ switch(filter[i]) {
+ case 'a' ... 'z':
+ case 'A' ... 'Z':
+ case '0' ... '9':
+ case '_':
+ continue;
+ }
+ break;
+ }
+
+ n = i - start_i;
+ field = buf;
+ strncpy(field, filter + start_i, n);
+ field[n++] = '\0';
+
+ val = buf + n;
+
+ while (isspace(filter[i]))
+ i++;
+
+ start_i = i;
+ switch(filter[i++]) {
+ case '>':
+ compare = TRACEFS_COMPARE_GT;
+ if (filter[i] == '=') {
+ i++;
+ compare = TRACEFS_COMPARE_GE;
+ }
+ break;
+ case '<':
+ compare = TRACEFS_COMPARE_LT;
+ if (filter[i] == '=') {
+ i++;
+ compare = TRACEFS_COMPARE_LE;
+ }
+ break;
+ case '=':
+ compare = TRACEFS_COMPARE_EQ;
+ i++;
+ break;
+ case '!':
+ compare = TRACEFS_COMPARE_NE;
+ i++;
+ break;
+ case '~':
+ compare = TRACEFS_COMPARE_RE;
+ break;
+ case '&':
+ compare = TRACEFS_COMPARE_AND;
+ break;
+ }
+
+ while (isspace(filter[i]))
+ i++;
+
+ quote = 0;
+ backslash = false;
+ start_i = i;
+ for (; filter[i]; i++) {
+ if (quote) {
+ if (backslash)
+ backslash = false;
+ else if (filter[i] == '\\')
+ backslash = true;
+ else if (filter[i] == quote)
+ quote = 0;
+ continue;
+ }
+ switch(filter[i]) {
+ case '"': case '\'':
+ quote = filter[i];
+ continue;
+ case 'a' ... 'z':
+ case 'A' ... 'Z':
+ case '0' ... '9':
+ case '_':
+ continue;
+ }
+ break;
+ }
+ n = i - start_i;
+ strncpy(val, filter + start_i, n);
+ val[n] = '\0';
+ break;
+ }
+ n = tracefs_event_append_filter(event, &new_filter, type,
+ field, compare, val);
+ if (n < 0) {
+ fprintf(stderr, "Failed making new filter:\n'%s'\n",
+ new_filter ? new_filter : "(null)");
+ exit(-1);
+ }
+ }
+
+ tep_free(tep);
+
+ printf("Created new filter: '%s'\n", new_filter);
+ free(new_filter);
+
+ exit(0);
+}
+--
+
+FILES
+-----
+[verse]
+--
+*tracefs.h*
+ Header file to include in order to have access to the library APIs.
+*-ltracefs*
+ Linker switch to add when building a program that uses the library.
+--
+
+SEE ALSO
+--------
+_libtracefs(3)_,
+_libtraceevent(3)_,
+_trace-cmd(1)_,
+_tracefs_hist_alloc(3)_,
+_tracefs_hist_free(3)_,
+_tracefs_hist_add_key(3)_,
+_tracefs_hist_add_value(3)_,
+_tracefs_hist_add_name(3)_,
+_tracefs_hist_start(3)_,
+_tracefs_hist_destory(3)_,
+_tracefs_hist_add_sort_key(3)_,
+_tracefs_hist_sort_key_direction(3)_
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>
+*sameeruddin shaik* <sameeruddin.shaik8@gmail.com>
+--
+REPORTING BUGS
+--------------
+Report bugs to <linux-trace-devel@vger.kernel.org>
+
+LICENSE
+-------
+libtracefs is Free Software licensed under the GNU LGPL 2.1
+
+RESOURCES
+---------
+https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/
+
+COPYING
+-------
+Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).