summaryrefslogtreecommitdiffstats
path: root/Documentation
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 07:26:15 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 07:26:15 +0000
commitc72e01b9ea891fa5cbbbe9876bdfb49079b55be7 (patch)
tree44c55a81a281a6c211745c0abc68352aeaf0180f /Documentation
parentInitial commit. (diff)
downloadlibtracefs-upstream.tar.xz
libtracefs-upstream.zip
Adding upstream version 1.6.4.upstream/1.6.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--Documentation/.gitignore5
-rw-r--r--Documentation/Makefile247
-rw-r--r--Documentation/asciidoc.conf120
-rw-r--r--Documentation/libtracefs-cpu-open.txt100
-rw-r--r--Documentation/libtracefs-cpu.txt240
-rw-r--r--Documentation/libtracefs-dynevents.txt283
-rw-r--r--Documentation/libtracefs-eprobes.txt187
-rw-r--r--Documentation/libtracefs-error.txt137
-rw-r--r--Documentation/libtracefs-events-file.txt217
-rw-r--r--Documentation/libtracefs-events-tep.txt148
-rw-r--r--Documentation/libtracefs-events.txt195
-rw-r--r--Documentation/libtracefs-files.txt131
-rw-r--r--Documentation/libtracefs-filter.txt345
-rw-r--r--Documentation/libtracefs-function-filter.txt237
-rw-r--r--Documentation/libtracefs-hist-cont.txt222
-rw-r--r--Documentation/libtracefs-hist-mod.txt540
-rw-r--r--Documentation/libtracefs-hist.txt531
-rw-r--r--Documentation/libtracefs-instances-affinity.txt200
-rw-r--r--Documentation/libtracefs-instances-file-manip.txt199
-rw-r--r--Documentation/libtracefs-instances-files.txt173
-rw-r--r--Documentation/libtracefs-instances-manage.txt150
-rw-r--r--Documentation/libtracefs-instances-utils.txt141
-rw-r--r--Documentation/libtracefs-iterator.txt229
-rw-r--r--Documentation/libtracefs-kprobes.txt273
-rw-r--r--Documentation/libtracefs-log.txt76
-rw-r--r--Documentation/libtracefs-marker.txt116
-rw-r--r--Documentation/libtracefs-marker_raw.txt102
-rw-r--r--Documentation/libtracefs-option-get.txt141
-rw-r--r--Documentation/libtracefs-option-misc.txt100
-rw-r--r--Documentation/libtracefs-options.txt159
-rw-r--r--Documentation/libtracefs-sql.txt628
-rw-r--r--Documentation/libtracefs-sqlhist.txt.1356
-rw-r--r--Documentation/libtracefs-stream.txt126
-rw-r--r--Documentation/libtracefs-synth-info.txt298
-rw-r--r--Documentation/libtracefs-synth.txt368
-rw-r--r--Documentation/libtracefs-synth2.txt281
-rw-r--r--Documentation/libtracefs-traceon.txt151
-rw-r--r--Documentation/libtracefs-tracer.txt221
-rw-r--r--Documentation/libtracefs-uprobes.txt189
-rw-r--r--Documentation/libtracefs-utils.txt139
-rw-r--r--Documentation/libtracefs.txt344
-rw-r--r--Documentation/manpage-1.72.xsl14
-rw-r--r--Documentation/manpage-base.xsl35
-rw-r--r--Documentation/manpage-bold-literal.xsl17
-rw-r--r--Documentation/manpage-normal.xsl13
-rw-r--r--Documentation/manpage-suppress-sp.xsl21
46 files changed, 9145 insertions, 0 deletions
diff --git a/Documentation/.gitignore b/Documentation/.gitignore
new file mode 100644
index 0000000..4d2414d
--- /dev/null
+++ b/Documentation/.gitignore
@@ -0,0 +1,5 @@
+*.3
+sqlhist.1
+*.m
+*.xml
+*.html
diff --git a/Documentation/Makefile b/Documentation/Makefile
new file mode 100644
index 0000000..afcb6a5
--- /dev/null
+++ b/Documentation/Makefile
@@ -0,0 +1,247 @@
+# SPDX-License-Identifier: LGPL-2.1
+
+include $(src)/scripts/utils.mk
+
+
+# This Makefile and manpage XSL files were taken from libtraceevent
+# and modified for libtracefs.
+
+MAN3_TXT= \
+ $(wildcard libtracefs-*.txt) \
+ libtracefs.txt
+
+MAN1_TEXT= \
+ $(wildcard libtracefs-*.txt.1)
+
+MAN_TXT = $(MAN3_TXT)
+_MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))
+_MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT))
+_DOC_MAN3=$(patsubst %.txt,%.m,$(MAN3_TXT))
+
+MAN_XML=$(addprefix $(OUTPUT),$(_MAN_XML))
+MAN_HTML=$(addprefix $(OUTPUT),$(_MAN_HTML))
+DOC_MAN3=$(addprefix $(OUTPUT),$(_DOC_MAN3))
+
+_MAN1_XML=$(patsubst %.txt.1,%.xml,$(MAN1_TEXT))
+_MAN1_HTML=$(patsubst %.txt.1,%.html,$(MAN1_TEXT))
+_DOC_MAN1=$(patsubst %.txt.1,%.m,$(MAN1_TEXT))
+
+MAN1_XML=$(addprefix $(OUTPUT),$(_MAN1_XML))
+MAN1_HTML=$(addprefix $(OUTPUT),$(_MAN1_HTML))
+DOC_MAN1=$(addprefix $(OUTPUT),$(_DOC_MAN1))
+
+
+# Make the path relative to DESTDIR, not prefix
+ifndef DESTDIR
+prefix?=$(HOME)
+endif
+bindir?=$(prefix)/bin
+htmldir?=$(prefix)/share/doc/libtracefs-doc
+pdfdir?=$(prefix)/share/doc/libtracefs-doc
+mandir?=$(prefix)/share/man
+man3dir=$(mandir)/man3
+man1dir=$(mandir)/man1
+
+ASCIIDOC=asciidoc
+ASCIIDOC_EXTRA = --unsafe -f asciidoc.conf
+ASCIIDOC_HTML = xhtml11
+MANPAGE_XSL = manpage-normal.xsl
+XMLTO_EXTRA =
+INSTALL?=install
+RM ?= rm -f
+
+ifdef USE_ASCIIDOCTOR
+ASCIIDOC = asciidoctor
+ASCIIDOC_EXTRA = -a compat-mode
+ASCIIDOC_EXTRA += -I. -rasciidoctor-extensions
+ASCIIDOC_EXTRA += -a mansource="libtracefs" -a manmanual="libtracefs Manual"
+ASCIIDOC_HTML = xhtml5
+endif
+
+ASCIIDOC_INSTALLED := $(shell command -v $(ASCIIDOC) 2> /dev/null)
+ifndef ASCIIDOC_INSTALLED
+ missing_tools += $(ASCIIDOC)
+endif
+
+XMLTO=xmlto
+XMLTO_INSTALLED := $(shell command -v $(XMLTO) 2> /dev/null)
+ifndef XMLTO_INSTALLED
+ missing_tools += $(XMLTO)
+endif
+
+#
+# For asciidoc ...
+# -7.1.2, no extra settings are needed.
+# 8.0-, set ASCIIDOC8.
+#
+
+#
+# For docbook-xsl ...
+# -1.68.1, set ASCIIDOC_NO_ROFF? (based on changelog from 1.73.0)
+# 1.69.0, no extra settings are needed?
+# 1.69.1-1.71.0, set DOCBOOK_SUPPRESS_SP?
+# 1.71.1, no extra settings are needed?
+# 1.72.0, set DOCBOOK_XSL_172.
+# 1.73.0-, set ASCIIDOC_NO_ROFF
+#
+
+#
+# If you had been using DOCBOOK_XSL_172 in an attempt to get rid
+# of 'the ".ft C" problem' in your generated manpages, and you
+# instead ended up with weird characters around callouts, try
+# using ASCIIDOC_NO_ROFF instead (it works fine with ASCIIDOC8).
+#
+
+ifdef ASCIIDOC8
+ASCIIDOC_EXTRA += -a asciidoc7compatible
+endif
+ifdef DOCBOOK_XSL_172
+ASCIIDOC_EXTRA += -a libtracefs-asciidoc-no-roff
+MANPAGE_XSL = manpage-1.72.xsl
+else
+ ifdef ASCIIDOC_NO_ROFF
+ # docbook-xsl after 1.72 needs the regular XSL, but will not
+ # pass-thru raw roff codes from asciidoc.conf, so turn them off.
+ ASCIIDOC_EXTRA += -a libtracefs-asciidoc-no-roff
+ endif
+endif
+ifdef MAN_BOLD_LITERAL
+XMLTO_EXTRA += -m manpage-bold-literal.xsl
+endif
+ifdef DOCBOOK_SUPPRESS_SP
+XMLTO_EXTRA += -m manpage-suppress-sp.xsl
+endif
+
+SHELL_PATH ?= $(SHELL)
+# Shell quote;
+SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
+
+DESTDIR ?=
+DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))'
+
+export DESTDIR DESTDIR_SQ
+
+QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
+QUIET_SUBDIR1 =
+
+ifneq ($(findstring $(MAKEFLAGS),w),w)
+PRINT_DIR = --no-print-directory
+else # "make -w"
+NO_SUBDIR = :
+endif
+
+ifneq ($(findstring $(MAKEFLAGS),s),s)
+ifneq ($(V),1)
+ QUIET_ASCIIDOC = @echo ' ASCIIDOC '$@;
+ QUIET_XMLTO = @echo ' XMLTO '$@;
+ QUIET_SUBDIR0 = +@subdir=
+ QUIET_SUBDIR1 = ;$(NO_SUBDIR) \
+ echo ' SUBDIR ' $$subdir; \
+ $(MAKE) $(PRINT_DIR) -C $$subdir
+ export V
+endif
+endif
+
+all: check-man-tools html man
+
+man: man3 man1
+man3: $(DOC_MAN3)
+man1: $(DOC_MAN1)
+
+html: $(MAN_HTML) $(MAN1_HTML)
+
+$(MAN_HTML) $(MAN1_HTML) $(DOC_MAN3) $(DOC_MAN1): asciidoc.conf
+
+install: check-man-tools install-man install-html
+
+check-man-tools:
+ifdef missing_tools
+ $(error "You need to install $(missing_tools) for man pages")
+endif
+
+install-%.3: $(OUTPUT)%.3
+ $(Q)$(call do_install,$<,$(man3dir),644);
+
+install-%.1: $(OUTPUT)%.1
+ $(Q)$(call do_install,$<,$(man1dir),644);
+
+do-install-man: man $(addprefix install-,$(wildcard $(OUTPUT)*.3)) $(addprefix install-,$(wildcard $(OUTPUT)*.1))
+
+install-man: man
+ $(Q)$(MAKE) -C . do-install-man
+
+install-%.txt: $(OUTPUT)%.html
+ $(Q)$(call do_install,$<,$(htmldir),644);
+
+install-%.txt.1: $(OUTPUT)%.html
+ $(Q)$(call do_install,$<,$(htmldir),644);
+
+do-install-html: html $(addprefix install-,$(wildcard *.txt)) $(addprefix install-,$(wildcard *.txt.1))
+
+install-html: html do-install-html
+
+uninstall: uninstall-man uninstall-html
+
+uninstall-man:
+ $(Q)$(RM) $(addprefix $(DESTDIR)$(man3dir)/,$(DOC_MAN3)) $(addprefix $(DESTDIR)$(man1dir)/,$(DOC_MAN1))
+
+uninstall-html:
+ $(Q)$(RM) $(addprefix $(DESTDIR)$(htmldir)/,$(MAN_HTML)) $(addprefix $(DESTDIR)$(htmldir)/,$(MAN1_HTML))
+
+ifdef missing_tools
+ DO_INSTALL_MAN = $(warning Please install $(missing_tools) to have the man pages installed)
+else
+ DO_INSTALL_MAN = do-install-man
+endif
+
+CLEAN_FILES = \
+ $(MAN_XML) $(addsuffix +,$(MAN_XML)) \
+ $(MAN_HTML) $(addsuffix +,$(MAN_HTML)) \
+ $(MAN1_HTML) $(addsuffix +,$(MAN1_HTML)) \
+ $(filter-out $(MAN1_TEXT),$(wildcard *.1)) \
+ $(DOC_MAN3) *.3 *.m
+
+clean:
+ $(Q) $(RM) $(CLEAN_FILES)
+
+ifdef USE_ASCIIDOCTOR
+$(OUTPUT)%.3 : $(OUTPUT)%.txt
+ $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
+ $(ASCIIDOC) -b manpage -d manpage \
+ $(ASCIIDOC_EXTRA) -alibtracefs_version=$(TRACEFS_VERSION) -o $@+ $< && \
+ mv $@+ $@
+$(OUTPUT)%.1 : $(OUTPUT)%.txt.1
+ $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
+ $(ASCIIDOC) -b manpage -d manpage \
+ $(ASCIIDOC_EXTRA) -alibtracefs_version=$(TRACEFS_VERSION) -o $@+ $< && \
+ mv $@+ $@
+endif
+
+$(OUTPUT)%.m : $(OUTPUT)%.xml
+ $(QUIET_XMLTO)$(RM) $@ && \
+ $(XMLTO) -o $(OUTPUT). -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<; \
+ touch $@
+
+$(OUTPUT)%.xml : %.txt
+ $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
+ $(ASCIIDOC) -b docbook -d manpage \
+ $(ASCIIDOC_EXTRA) -alibtracefs_version=$(TRACEFS_VERSION) -o $@+ $< && \
+ mv $@+ $@
+
+$(OUTPUT)%.xml : %.txt.1
+ $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
+ $(ASCIIDOC) -b docbook -d manpage \
+ $(ASCIIDOC_EXTRA) -alibtracefs_version=$(TRACEFS_VERSION) -o $@+ $< && \
+ mv $@+ $@
+
+$(MAN_HTML): $(OUTPUT)%.html : %.txt
+ $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
+ $(ASCIIDOC) -b $(ASCIIDOC_HTML) -d manpage \
+ $(ASCIIDOC_EXTRA) -alibtracefs_version=$(TRACEFS_VERSION) -o $@+ $< && \
+ mv $@+ $@
+
+$(MAN1_HTML): $(OUTPUT)%.html : %.txt.1
+ $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
+ $(ASCIIDOC) -b $(ASCIIDOC_HTML) -d manpage \
+ $(ASCIIDOC_EXTRA) -alibtracefs_version=$(TRACEFS_VERSION) -o $@+ $< && \
+ mv $@+ $@
diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf
new file mode 100644
index 0000000..c15aa13
--- /dev/null
+++ b/Documentation/asciidoc.conf
@@ -0,0 +1,120 @@
+## linktep: macro
+#
+# Usage: linktep:command[manpage-section]
+#
+# Note, {0} is the manpage section, while {target} is the command.
+#
+# Show TEP link as: <command>(<section>); if section is defined, else just show
+# the command.
+
+[macros]
+(?su)[\\]?(?P<name>linktep):(?P<target>\S*?)\[(?P<attrlist>.*?)\]=
+
+[attributes]
+asterisk=&#42;
+plus=&#43;
+caret=&#94;
+startsb=&#91;
+endsb=&#93;
+tilde=&#126;
+
+ifdef::backend-docbook[]
+[linktep-inlinemacro]
+{0%{target}}
+{0#<citerefentry>}
+{0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}
+{0#</citerefentry>}
+endif::backend-docbook[]
+
+ifdef::backend-docbook[]
+ifndef::tep-asciidoc-no-roff[]
+# "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this.
+# v1.72 breaks with this because it replaces dots not in roff requests.
+[listingblock]
+<example><title>{title}</title>
+<literallayout>
+ifdef::doctype-manpage[]
+&#10;.ft C&#10;
+endif::doctype-manpage[]
+|
+ifdef::doctype-manpage[]
+&#10;.ft&#10;
+endif::doctype-manpage[]
+</literallayout>
+{title#}</example>
+endif::tep-asciidoc-no-roff[]
+
+ifdef::tep-asciidoc-no-roff[]
+ifdef::doctype-manpage[]
+# The following two small workarounds insert a simple paragraph after screen
+[listingblock]
+<example><title>{title}</title>
+<literallayout>
+|
+</literallayout><simpara></simpara>
+{title#}</example>
+
+[verseblock]
+<formalpara{id? id="{id}"}><title>{title}</title><para>
+{title%}<literallayout{id? id="{id}"}>
+{title#}<literallayout>
+|
+</literallayout>
+{title#}</para></formalpara>
+{title%}<simpara></simpara>
+endif::doctype-manpage[]
+endif::tep-asciidoc-no-roff[]
+endif::backend-docbook[]
+
+ifdef::doctype-manpage[]
+ifdef::backend-docbook[]
+[header]
+template::[header-declarations]
+<refentry>
+<refmeta>
+<refentrytitle>{mantitle}</refentrytitle>
+<manvolnum>{manvolnum}</manvolnum>
+<refmiscinfo class="source">libtracefs</refmiscinfo>
+<refmiscinfo class="version">{libtracefs_version}</refmiscinfo>
+<refmiscinfo class="manual">libtracefs Manual</refmiscinfo>
+</refmeta>
+<refnamediv>
+ <refname>{manname1}</refname>
+ <refname>{manname2}</refname>
+ <refname>{manname3}</refname>
+ <refname>{manname4}</refname>
+ <refname>{manname5}</refname>
+ <refname>{manname6}</refname>
+ <refname>{manname7}</refname>
+ <refname>{manname8}</refname>
+ <refname>{manname9}</refname>
+ <refname>{manname10}</refname>
+ <refname>{manname11}</refname>
+ <refname>{manname12}</refname>
+ <refname>{manname13}</refname>
+ <refname>{manname14}</refname>
+ <refname>{manname15}</refname>
+ <refname>{manname16}</refname>
+ <refname>{manname17}</refname>
+ <refname>{manname18}</refname>
+ <refname>{manname19}</refname>
+ <refname>{manname20}</refname>
+ <refname>{manname21}</refname>
+ <refname>{manname22}</refname>
+ <refname>{manname23}</refname>
+ <refname>{manname24}</refname>
+ <refname>{manname25}</refname>
+ <refname>{manname26}</refname>
+ <refname>{manname27}</refname>
+ <refname>{manname28}</refname>
+ <refname>{manname29}</refname>
+ <refname>{manname30}</refname>
+ <refpurpose>{manpurpose}</refpurpose>
+</refnamediv>
+endif::backend-docbook[]
+endif::doctype-manpage[]
+
+ifdef::backend-xhtml11[]
+[linktep-inlinemacro]
+<a href="{target}.html">{target}{0?({0})}</a>
+endif::backend-xhtml11[]
diff --git a/Documentation/libtracefs-cpu-open.txt b/Documentation/libtracefs-cpu-open.txt
new file mode 100644
index 0000000..c5a900a
--- /dev/null
+++ b/Documentation/libtracefs-cpu-open.txt
@@ -0,0 +1,100 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_cpu_open, tracefs_cpu_close, tracefs_cpu_alloc_fd, tracefs_cpu_free_fd - Opening trace_pipe_raw data for reading
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+struct tracefs_cpu pass:[*]*tracefs_cpu_open*(struct tracefs_instance pass:[*]_instance_,
+ int _cpu_, bool _nonblock_);
+void *tracefs_cpu_close*(struct tracefs_cpu pass:[*]_tcpu_);
+
+struct tracefs_cpu pass:[*]*tracefs_cpu_alloc_fd*(int _fd_, int _subbuf_size_, bool _nonblock_);
+void *tracefs_cpu_free_fd*(struct tracefs_cpu pass:[*]_tcpu_);
+--
+
+DESCRIPTION
+-----------
+This set of APIs can be used to open the raw data from the trace_pipe_raw
+files in the tracefs file system in oder to read them with the *tracefs_cpu_read*(3)
+functions.
+
+The *tracefs_cpu_open()* creates a descriptor that can read the tracefs
+trace_pipe_raw file for a given _cpu_ in a given _instance_. If _instance_ is
+NULL than the toplevel trace_pipe_raw file is used.
+
+The *tracefs_cpu_close()* closes all the file descriptors associated to the trace_pipe_raw
+opened by *tracefs_cpu_open()*.
+
+The *tracefs_cpu_alloc_fd()* will create a tracefs_cpu descriptor from an existing
+file descriptor _fd_. This is useful to use when connecting to a socket or pipe where
+the other end is feeding raw tracing data in the same format as the trace_pipe_raw
+file would (like in guest to host tracing). The caller is responsible for determining
+the _subbuf_size_ that will be used to break up the sub-buffers being read by the
+file descriptor. The _nonblock_ is treated the same as the same parameter in
+*tracefs_cpu_open()*.
+
+The *tracefs_cpu_free_fd()* is used to free the descriptor returned by *tracefs_cpu_alloc_fd()*.
+It does all the clean up that *tracefs_cpu_close()* performs, and that could also be
+used to free up the descriptor created by *tracefs_cpu_alloc_fd()* but will also close
+the file descriptor passed in. Note that *tracefs_cpu_free_fd()* should not be used
+on the descriptor returned by *tracefs_cpu_open()* as it will not close the file descriptor
+created by it.
+
+RETURN VALUE
+------------
+The *tracefs_cpu_open()* returns a struct tracefs_cpu descriptor that can be
+used by the other functions or NULL on error.
+
+The *tracefs_cpu_alloc_fd()* returns a struct tracefs_cpu descriptor that can
+be used by the *tracefs_cpu_read*(3) related functions, where the descriptor
+will be reading the passed in _fd_ file descriptor.
+
+EXAMPLE
+-------
+See *tracefs_cpu_read*(3) for an example.
+
+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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+--
+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) 2022 Google, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).
diff --git a/Documentation/libtracefs-cpu.txt b/Documentation/libtracefs-cpu.txt
new file mode 100644
index 0000000..d6215d9
--- /dev/null
+++ b/Documentation/libtracefs-cpu.txt
@@ -0,0 +1,240 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_cpu_read_size, tracefs_cpu_read, tracefs_cpu_buffered_read, tracefs_cpu_write,
+tracefs_cpu_stop, tracefs_cpu_flush, tracefs_cpu_flush_write, tracefs_cpu_pipe
+- Reading trace_pipe_raw data
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+int *tracefs_cpu_read_size*(struct tracefs_cpu pass:[*]_tcpu_);
+int *tracefs_cpu_read*(struct tracefs_cpu pass:[*]_tcpu_, void pass:[*]_buffer_, bool _nonblock_);
+int *tracefs_cpu_buffered_read*(struct tracefs_cpu pass:[*]_tcpu_, void pass:[*]_buffer_, bool _nonblock_);
+int *tracefs_cpu_write*(struct tracefs_cpu pass:[*]_tcpu_, int _wfd_, bool _nonblock_);
+int *tracefs_cpu_stop*(struct tracefs_cpu pass:[*]_tcpu_);
+int *tracefs_cpu_flush*(struct tracefs_cpu pass:[*]_tcpu_, void pass:[*]_buffer_);
+int *tracefs_cpu_flush_write*(struct tracefs_cpu pass:[*]_tcpu_, int _wfd_);
+int *tracefs_cpu_pipe*(struct tracefs_cpu pass:[*]_tcpu_, int _wfd_, bool _nonblock_);
+--
+
+DESCRIPTION
+-----------
+This set of APIs can be used to read the raw data from the trace_pipe_raw
+files in the tracefs file system.
+
+The *tracefs_cpu_read_size()* returns the subbuffer size of the trace_pipe_raw. This
+returns the minimum size of the buffer that is passed to the below functions.
+
+The *tracefs_cpu_read()* reads the trace_pipe_raw files associated to _tcpu_ into _buffer_.
+_buffer_ must be at least the size of the sub buffer of the ring buffer,
+which is returned by *tracefs_cpu_read_size()*. If _nonblock_ is set, and
+there's no data available, it will return immediately. Otherwise depending
+on how _tcpu_ was opened, it will block. If _tcpu_ was opened with nonblock
+set, then this _nonblock_ will make no difference.
+
+The *tracefs_cpu_buffered_read()* is basically the same as *tracefs_cpu_read()*
+except that it uses a pipe through splice to buffer reads. This will batch
+reads keeping the reading from the ring buffer less intrusive to the system,
+as just reading all the time can cause quite a disturbance. Note, one
+difference between this and *tracefs_cpu_read()* is that it will read only in
+sub buffer pages. If the ring buffer has not filled a page, then it will not
+return anything, even with _nonblock_ set. Calls to *tracefs_cpu_flush()*
+should be done to read the rest of the file at the end of the trace.
+
+The *tracefs_cpu_write()* will pipe the data from the trace_pipe_raw
+file associated with _tcpu_ into the _wfd_ file descriptor. If _nonblock_ is set,
+then it will not block on if there's nothing to write. Note, it will only write
+sub buffer size data to _wfd_. Calls to tracefs_cpu_flush_write() are needed to
+write out the rest.
+
+The *tracefs_cpu_stop()* will attempt to unblock a task blocked on _tcpu_ reading it.
+On older kernels, it may not do anything for the pipe reads, as older kernels do not
+wake up tasks waiting on the ring buffer. Returns 0 if it definitely woke up any possible
+waiters, but returns 1 if it is not sure it worked and waiters may need to have a signal
+sent to them.
+
+The *tracefs_cpu_flush()* reads the trace_pipe_raw file associated by the _tcpu_ and puts it
+into _buffer_, which must be the size of the sub buffer which is retrieved.
+by *tracefs_cpu_read_size()*. This should be called at the end of tracing
+to get the rest of the data. This call will convert the file descriptor of
+trace_pipe_raw into non-blocking mode.
+
+The *tracefs_cpu_flush_write()* same as *trace_cpu_flush()* except it takes a file
+descriptor _wfd_ to flush the data into.
+
+The *tracefs_cpu_pipe()* is similar to *tracefs_cpu_write()* but the _wfd_ file descriptor
+must be a pipe. This call is an optimization of *tracefs_cpu_write()* that uses two calls
+to *splice*(2) in order to connect the trace_pipe_raw file descriptor with the write file
+descriptor. *splice*(2) requires that one of the passed in file descriptors is a pipe.
+If the application wants to pass the data to an existing pipe, there's no reason for
+there to be two *splice*(2) system calls and *tracefs_cpu_pipe()* can simply use a single
+call to _wfd_.
+
+RETURN VALUE
+------------
+The *tracefs_cpu_open()* returns a struct tracefs_cpu descriptor that can be
+used by the other functions or NULL on error.
+
+The *tracefs_cpu_read_size()* returns the minimum size of the buffers to be
+used with *tracefs_cpu_read()*, *tracefs_cpu_buffered_read()* and *tracefs_cpu_flush()*.
+Returns negative on error.
+
+The *tracefs_cpu_read()* returns the number of bytes read, or negative on error.
+
+The *tracefs_cpu_buffered_read()* returns the number of bytes read or negative on error.
+
+The *tracefs_cpu_write()* returns the number of bytes written to the file
+or negative on error.
+
+The *tracefs_cpu_stop()* returns zero if any waiters were guaranteed to be
+woken up from waiting on input, or returns one if this is an older kernel
+that does not supply that guarantee, and a signal may need to be sent to
+any waiters. Returns negative on error.
+
+The *tracefs_cpu_flush()* returns the number of bytes read or negative on error.
+
+The *tracefs_cpu_flush_write()* returns the number of bytes written to the
+file or negative on error.
+
+EXAMPLE
+-------
+[source,c]
+--
+#define _LARGEFILE64_SOURCE
+#include <stdlib.h>
+#include <ctype.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <tracefs.h>
+
+struct thread_data {
+ struct tracefs_cpu *tcpu;
+ int done;
+ int fd;
+};
+
+static void *thread_run(void *arg)
+{
+ struct thread_data *data = arg;
+ struct tracefs_cpu *tcpu = data->tcpu;
+ int fd = data->fd;
+ int ret;
+
+ while (!data->done) {
+ ret = tracefs_cpu_write(tcpu, fd, false);
+ printf("wrote %d\n", ret);
+ }
+ return NULL;
+}
+
+int main (int argc, char **argv)
+{
+ struct tracefs_instance *instance;
+ struct thread_data data;
+ pthread_t thread;
+ char *file;
+ int secs = 10;
+ int cpu;
+ int ret;
+
+ if (argc < 3 || !isdigit(argv[1][0])) {
+ printf("usage: %s cpu file_destination [sleep secs]\n\n", argv[0]);
+ exit(-1);
+ }
+
+ cpu = atoi(argv[1]);
+ file = argv[2];
+
+ if (argc > 3)
+ secs = atoi(argv[3]);
+
+ instance = tracefs_instance_create("cpu_write");
+ if (!instance) {
+ perror("create instance");
+ exit(-1);
+ }
+
+ memset(&data, 0, sizeof(data));
+
+ data.tcpu = tracefs_cpu_open(instance, cpu, 0);
+ if (!data.tcpu) {
+ perror("Open instance");
+ exit(-1);
+ }
+
+ data.fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
+ if (data.fd < 0) {
+ perror(file);
+ exit(-1);
+ }
+
+ pthread_create(&thread, NULL, thread_run, &data);
+
+ sleep(secs);
+
+ data.done = 1;
+ printf("stopping\n");
+ ret = tracefs_cpu_stop(data.tcpu);
+
+ printf("joining %d\n", ret);
+ pthread_join(thread, NULL);
+
+ tracefs_trace_off(instance);
+ do {
+ ret = tracefs_cpu_flush_write(data.tcpu, data.fd);
+ printf("flushed %d\n", ret);
+ } while (ret > 0);
+ tracefs_trace_on(instance);
+
+ tracefs_cpu_close(data.tcpu);
+ close(data.fd);
+
+ return 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
+--------
+*tracefs_cpu_open*(3)
+*tracefs_cpu_close*(3)
+*libtracefs*(3),
+*libtraceevent*(3),
+*trace-cmd*(1)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+--
+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) 2022 Google, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).
diff --git a/Documentation/libtracefs-dynevents.txt b/Documentation/libtracefs-dynevents.txt
new file mode 100644
index 0000000..2c6db47
--- /dev/null
+++ b/Documentation/libtracefs-dynevents.txt
@@ -0,0 +1,283 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_dynevent_create, tracefs_dynevent_destroy, tracefs_dynevent_destroy_all,
+tracefs_dynevent_free, tracefs_dynevent_list_free, tracefs_dynevent_get, tracefs_dynevent_get_all,
+tracefs_dynevent_info, tracefs_dynevent_get_event - Create, destroy, free and get dynamic events.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+struct *tracefs_dynevent*;
+enum *tracefs_dynevent_type*;
+int *tracefs_dynevent_create*(struct tracefs_dynevent pass:[*]_devent_);
+int *tracefs_dynevent_destroy*(struct tracefs_dynevent pass:[*]_devent_, bool _force_);
+int *tracefs_dynevent_destroy_all*(unsigned int _types_, bool _force_);
+void *tracefs_dynevent_free*(struct tracefs_dynevent pass:[*]_devent_);
+void *tracefs_dynevent_list_free*(struct tracefs_dynevent pass:[*]pass:[*]_events_);
+struct tracefs_dynevent pass:[*]*tracefs_dynevent_get*(enum tracefs_dynevent_type _type_, const char pass:[*]_system_, const char pass:[*]_event_);
+struct tracefs_dynevent pass:[*]pass:[*]*tracefs_dynevent_get_all*(unsigned int _types_, const char pass:[*]_system_);
+enum tracefs_dynevent_type *tracefs_dynevent_info*(struct tracefs_dynevent pass:[*]_dynevent_, char pass:[*]pass:[*]_system_, char pass:[*]pass:[*]_event_, char pass:[*]pass:[*]_prefix_, char pass:[*]pass:[*]_addr_, char pass:[*]pass:[*]_format_);
+struct tep_event pass:[*]*tracefs_dynevent_get_event*(struct tep_handle pass:[*]_tep_, struct tracefs_dynevent pass:[*]_dynevent_);
+--
+
+DESCRIPTION
+-----------
+
+The *tracefs_dynevent_create*() function creates dynamic event _devent_ in the system.
+
+The *tracefs_dynevent_destroy*() function removes dynamic event _devent_ from the system. If _force_
+is true, the function will attempt to disable all events in all trace instances, before removing
+the dynamic event. The _devent_ context is not freed, use *tracefs_dynevent_free*() to free it.
+
+The *tracefs_dynevent_destroy_all*() function removes all dynamic events of given types from the
+system. The _types_ parameter is a type of specific dynamic event, or a bitmask of dynamic events
+types *tracefs_dynevent_type*, that will be removed. If _types_ is 0, dynamic events from all types
+will be removed. If _force_ is true, the function will attempt to disable all events in all trace
+instances, before removing the dynamic events.
+
+The *tracefs_dynevent_get*() function allocates and returns a single instance of a dynamic
+event that matches the given *type*, *system* and *event* that is passed to it. NULL is returned
+if there is no match. The returned event is what is found in the system, and must be freed
+with *tracefs_dynevent_free*(). If *system* is NULL, then the first *event* of any system
+of the given type that has the name of *event* will be returned.
+
+The *tracefs_dynevent_get_all*() function allocates and returns an array of pointers to dynamic
+events of given types that exist in the system. The last element of the array is a NULL pointer.
+The array must be freed with *tracefs_dynevent_list_free*(). If there are no events a NULL pointer is
+returned. The _types_ parameter is a type of specific dynamic event, or a bitmask of dynamic events
+types *tracefs_dynevent_type*, that will be retrieved. If _types_ is 0, dynamic events from all
+types will be retrieved.
+
+The *tracefs_dynevent_free*() function frees a dynamic event context _devent_.
+
+The *tracefs_dynevent_list_free*() function frees an array of pointers to dynamic event, returned
+by *tracefs_dynevent_get_all()* API.
+
+The *tracefs_dynevent_info*() function returns the type and information of a given dynamic event
+_dynevent_. If any of the _system_, _event_, _prefix_, _addr_ or _format_ arguments are not NULL,
+then strings are allocated and returned back via these arguments. The _system_ and _event_ holds the
+system and the name of the dynamic event. If _prefix_ is non NULL, then it will hold an allocated
+string that holds the prefix portion of the dynamic event (the content up to the ":", exluding it).
+If _addr_ is non NULL, it will hold the address or function that the dynamic event is attached to,
+if relevant for this event type. If _format_ is non NULL, it will hold the format string of the
+dynamic event. Note, that the content in _group_, _event_, _prefix_, _addr_, and _format_ must be
+freed with free(3) if they are set.
+
+The *tracefs_dynevent_get_event*() function returns a tep event, describing the given dynamic event.
+The API detects any newly created or removed dynamic events. The returned pointer to tep event is
+controlled by @tep and must not be freed.
+
+RETURN VALUE
+------------
+
+*tracefs_dynevent_create*() returns 0 on success, or -1 on error. If a parsing error occurs then
+*tracefs_error_last*(3) may be used to retrieve the error message explaining the parsing issue.
+
+*tracefs_dynevent_destroy*() and *tracefs_dynevent_destroy_all*() return 0 on success, or -1 on
+error. If _force_ is enabled, the functions may fail on disabling the events.
+
+*tracefs_dynevent_get*() function returns an allocated dynamic event from the system that matches
+the type, system and event given.
+
+*tracefs_dynevent_get_all*() function returns allocated array of pointers to dynamic events, or NULL
+in case of an error or in case there are no events in the system. That array must be freed by
+*tracefs_dynevent_list_free*().
+
+*tracefs_dynevent_info*() returns the type of the given dynamic event or TRACEFS_DYNEVENT_UNKNOWN
+on error. If _system_, _event_, _prefix_, _addr_, or _format_ are non NULL, they will contain
+allocated strings that must be freed by free(3).
+
+The *tracefs_dynevent_get_event*() function returns a pointer to a tep event or NULL in case of an
+error or if the requested dynamic event is missing. The returned pointer to tep event is controlled
+by @tep and must not be freed.
+
+ERRORS
+------
+The following errors are for all the above calls:
+
+*ENODEV* dynamic events of requested type are not configured for the running kernel.
+
+*ENOMEM* Memory allocation error.
+
+*tracefs_dynevent_create*() can fail with the following errors:
+
+*EINVAL* Most likely a parsing error occurred (use *tracefs_error_last*(3) to possibly
+ see what that error was).
+
+Other errors may also happen caused by internal system calls.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include <tracefs.h>
+
+static struct tep_event *open_event;
+static struct tep_format_field *file_field;
+
+static struct tep_event *openret_event;
+static struct tep_format_field *ret_field;
+
+static int callback(struct tep_event *event, struct tep_record *record,
+ int cpu, void *data)
+{
+ struct trace_seq seq;
+
+ trace_seq_init(&seq);
+ tep_print_event(event->tep, &seq, record, "%d-%s: ", TEP_PRINT_PID, TEP_PRINT_COMM);
+
+ if (event->id == open_event->id) {
+ trace_seq_puts(&seq, "open file='");
+ tep_print_field(&seq, record->data, file_field);
+ trace_seq_puts(&seq, "'\n");
+ } else if (event->id == openret_event->id) {
+ unsigned long long ret;
+ tep_read_number_field(ret_field, record->data, &ret);
+ trace_seq_printf(&seq, "open ret=%lld\n", ret);
+ } else {
+ goto out;
+ }
+
+ trace_seq_terminate(&seq);
+ trace_seq_do_printf(&seq);
+out:
+ trace_seq_destroy(&seq);
+
+ return 0;
+}
+
+static pid_t run_exec(char **argv, char **env)
+{
+ pid_t pid;
+
+ pid = fork();
+ if (pid)
+ return pid;
+
+ execve(argv[0], argv, env);
+ perror("exec");
+ exit(-1);
+}
+
+const char *mykprobe = "my_kprobes";
+
+int main (int argc, char **argv, char **env)
+{
+ struct tracefs_dynevent *kprobe, *kretprobe;
+ const char *sysnames[] = { mykprobe, NULL };
+ struct tracefs_instance *instance;
+ struct tep_handle *tep;
+ pid_t pid;
+
+ if (argc < 2) {
+ printf("usage: %s command\n", argv[0]);
+ exit(-1);
+ }
+
+ instance = tracefs_instance_create("exec_open");
+ if (!instance) {
+ perror("creating instance");
+ exit(-1);
+ }
+
+ tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, true);
+
+ kprobe = tracefs_kprobe_alloc(mykprobe, "open", "do_sys_openat2",
+ "file=+0($arg2):ustring flags=+0($arg3):x64 mode=+8($arg3):x64\n");
+ kretprobe = tracefs_kretprobe_alloc(mykprobe, "openret", "do_sys_openat2", "ret=%ax", 0);
+ if (!kprobe || !kretprobe) {
+ perror("allocating dynamic events");
+ exit(-1);
+ }
+
+ if (tracefs_dynevent_create(kprobe) || tracefs_dynevent_create(kretprobe)){
+ char *err = tracefs_error_last(NULL);
+ perror("Failed to create kprobes:");
+ if (err && strlen(err))
+ fprintf(stderr, "%s\n", err);
+ exit(-1);
+ }
+
+ tep = tracefs_local_events_system(NULL, sysnames);
+ if (!tep) {
+ perror("reading events");
+ exit(-1);
+ }
+ open_event = tep_find_event_by_name(tep, mykprobe, "open");
+ file_field = tep_find_field(open_event, "file");
+
+ openret_event = tep_find_event_by_name(tep, mykprobe, "openret");
+ ret_field = tep_find_field(openret_event, "ret");
+
+ tracefs_event_enable(instance, mykprobe, NULL);
+ pid = run_exec(&argv[1], env);
+
+ /* Let the child start to run */
+ sched_yield();
+
+ do {
+ tracefs_load_cmdlines(NULL, tep);
+ tracefs_iterate_raw_events(tep, instance, NULL, 0, callback, NULL);
+ } while (waitpid(pid, NULL, WNOHANG) != pid);
+
+ /* Will disable the events */
+ tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, true);
+ tracefs_dynevent_free(kprobe);
+ tracefs_dynevent_free(kretprobe);
+ tracefs_instance_destroy(instance);
+ tep_free(tep);
+
+ return 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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>
+*Yordan Karadzhov* <y.karadz@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) 2021 VMware, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).
diff --git a/Documentation/libtracefs-eprobes.txt b/Documentation/libtracefs-eprobes.txt
new file mode 100644
index 0000000..a96ad1b
--- /dev/null
+++ b/Documentation/libtracefs-eprobes.txt
@@ -0,0 +1,187 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_eprobe_alloc - Allocate new event probe (eprobe)
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+struct tracefs_dynevent pass:[*]
+*tracefs_eprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_target_system_, const char pass:[*]_target_event_,
+ const char pass:[*]_fetchargs_);
+--
+
+DESCRIPTION
+-----------
+*tracefs_eprobe_alloc*() allocates a new eprobe context. The ebrobe is not configured in the system.
+The new eprobe will be in the _system_ group (or eprobes if _system_ is NULL) and have the name of
+_event_. The eprobe will be attached to _target_event_, located in _target_system_. The list of
+arguments, described in _fetchargs_, will be fetched from _target_event_. The returned pointer to
+the event probe must be freed with *tracefs_dynevent_free*().
+
+
+RETURN VALUE
+------------
+The *tracefs_eprobe_alloc*() API returns a pointer to an allocated tracefs_dynevent structure,
+describing the event probe. This pointer must be freed by *tracefs_dynevent_free*(3). Note, this
+only allocates a descriptor representing the eprobe. It does not modify the running system. On error
+NULL is returned.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include <tracefs.h>
+
+static struct tep_event *open_event;
+static struct tep_format_field *file_field;
+
+static int callback(struct tep_event *event, struct tep_record *record,
+ int cpu, void *data)
+{
+ struct trace_seq seq;
+
+ trace_seq_init(&seq);
+ tep_print_event(event->tep, &seq, record, "%d-%s: ", TEP_PRINT_PID, TEP_PRINT_COMM);
+
+ if (event->id == open_event->id) {
+ trace_seq_puts(&seq, "open file='");
+ tep_print_field(&seq, record->data, file_field);
+ trace_seq_puts(&seq, "'\n");
+ }
+
+ trace_seq_terminate(&seq);
+ trace_seq_do_printf(&seq);
+ trace_seq_destroy(&seq);
+
+ return 0;
+}
+
+static pid_t run_exec(char **argv, char **env)
+{
+ pid_t pid;
+
+ pid = fork();
+ if (pid)
+ return pid;
+
+ execve(argv[0], argv, env);
+ perror("exec");
+ exit(-1);
+}
+
+const char *myprobe = "my_eprobes";
+
+int main (int argc, char **argv, char **env)
+{
+ struct tracefs_dynevent *eprobe;
+ struct tracefs_instance *instance;
+ struct tep_handle *tep;
+ const char *sysnames[] = { myprobe, NULL };
+ pid_t pid;
+
+ if (argc < 2) {
+ printf("usage: %s command\n", argv[0]);
+ exit(-1);
+ }
+
+ instance = tracefs_instance_create("exec_open");
+ if (!instance) {
+ perror("creating instance");
+ exit(-1);
+ }
+
+ tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_EPROBE, true);
+
+ eprobe = tracefs_eprobe_alloc(myprobe, "sopen", "syscalls", "sys_enter_openat2",
+ "file=+0($filename):ustring");
+ if (!eprobe) {
+ perror("allocating event probe");
+ exit(-1);
+ }
+
+ if (tracefs_dynevent_create(eprobe)) {
+ perror("creating event probe");
+ exit(-1);
+ }
+
+ tep = tracefs_local_events_system(NULL, sysnames);
+ if (!tep) {
+ perror("reading events");
+ exit(-1);
+ }
+
+ open_event = tep_find_event_by_name(tep, myprobe, "sopen");
+ file_field = tep_find_field(open_event, "file");
+
+ tracefs_event_enable(instance, myprobe, "sopen");
+ pid = run_exec(&argv[1], env);
+
+ /* Let the child start to run */
+ sched_yield();
+
+ do {
+ tracefs_load_cmdlines(NULL, tep);
+ tracefs_iterate_raw_events(tep, instance, NULL, 0, callback, NULL);
+ } while (waitpid(pid, NULL, WNOHANG) != pid);
+
+ /* Will disable the events */
+ tracefs_dynevent_destroy(eprobe, true);
+ tracefs_dynevent_free(eprobe);
+ tracefs_instance_destroy(instance);
+ tep_free(tep);
+
+ return 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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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) 2021 VMware, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).
diff --git a/Documentation/libtracefs-error.txt b/Documentation/libtracefs-error.txt
new file mode 100644
index 0000000..a45332d
--- /dev/null
+++ b/Documentation/libtracefs-error.txt
@@ -0,0 +1,137 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_error_last, tracefs_error_all, tracefs_error_clear -
+functions to read and clear the tracefs error log.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+char pass:[*]*tracefs_error_last*(struct tracefs_instance pass:[*]_instance_);
+char pass:[*]*tracefs_error_all*(struct tracefs_instance pass:[*]_instance_);
+int *tracefs_error_clear*(struct tracefs_instance pass:[*]_instance_);
+--
+
+DESCRIPTION
+-----------
+The *tracefs_error_last*() returns the last error message in the tracefs
+error log. Several actions that require proper syntax written into the
+tracefs file system may produce error messages in the error log. This
+function will show the most recent error in the error log.
+
+The *tracefs_error_all*() returns all messages saved in the error log.
+Note, this may not be all messages that were ever produced, as the kernel
+only keeps a limited amount of messages, and older ones may be discarded
+by the kernel.
+
+The *tracefs_error_clear*() will clear the error log.
+
+RETURN VALUE
+------------
+Both *tracefs_error_last*() and *tracefs_error_all*() will return an allocated
+string an error exists in the log, otherwise NULL is returned. If an error
+occurs, errno will be set, otherwise if there is no error messages to display
+then errno is not touched.
+
+*tracefs_error_clear*() returns 0 on success or -1 on error.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <tracefs.h>
+
+int main (int argc, char **argv, char **env)
+{
+ struct tracefs_dynevent *kevent;
+ char *system = NULL;
+ char *kprobe;
+ char *format;
+ char *addr;
+ int arg = 1;
+ int ret;
+
+ if (argc < 4) {
+ printf("usage: %s [system] kprobe addr fmt\n", argv[0]);
+ exit(-1);
+ }
+
+ if (argc > 5)
+ system = argv[arg++];
+
+ kprobe = argv[arg++];
+ addr = argv[arg++];
+ format = argv[arg++];
+
+ tracefs_error_clear(NULL);
+ kevent = tracefs_dynevent_get(TRACEFS_DYNEVENT_KPROBE, system, kprobe);
+ if (kevent) {
+ tracefs_dynevent_destroy(kevent, true);
+ tracefs_dynevent_free(kevent);
+ }
+
+ ret = tracefs_kprobe_raw(system, kprobe, addr, format);
+ if (ret < 0) {
+ char *err;
+
+ perror("Failed creating kprobe");
+ errno = 0;
+ err = tracefs_error_last(NULL);
+ if (err)
+ fprintf(stderr, "%s\n", err);
+ else if (errno)
+ perror("Failed reading error log");
+ free(err);
+ }
+
+ exit(ret);
+}
+--
+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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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).
diff --git a/Documentation/libtracefs-events-file.txt b/Documentation/libtracefs-events-file.txt
new file mode 100644
index 0000000..425eebd
--- /dev/null
+++ b/Documentation/libtracefs-events-file.txt
@@ -0,0 +1,217 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_event_get_file, tracefs_event_file_read, tracefs_event_file_write, tracefs_event_file_append,
+tracefs_event_file_clear, tracefs_event_file_exists - Work with trace event files.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+char pass:[*]*tracefs_event_get_file*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_file_);
+char pass:[*]*tracefs_event_file_read*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_file_, int pass:[*]_psize_);
+int *tracefs_event_file_write*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_file_, const char pass:[*]_str_);
+int *tracefs_event_file_append*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_file_, const char pass:[*]_str_);
+int *tracefs_event_file_clear*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_file_);
+bool *tracefs_event_file_exists*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_file_)
+
+--
+
+DESCRIPTION
+-----------
+These are functions for accessing tracefs event specific files.
+These functions act similar to the tracefs instance file functions
+but are easier to get to if the system and events are known before hand.
+
+The *tracefs_event_get_file()* returns the full path of the _file_ for
+the given _system_ and _event_ that is within the given _instance_.
+If _instance_ is NULL, then the file for the _event_ for the top level
+instance is returned. Note, there is no check to see if the file actually
+exists or even if the system and event exist. It only creates the path
+name for such an event if it did exist. This acts similar to the
+*tracefs_instance_get_file*(3), but is to be used to get to event files
+if the _system_ and _event_ are already known.
+
+The *tracefs_event_file_read()* reads the content for the _event_ _file_
+for the given _instance_ or the top level instance if _instance_ is
+NULL. The content of the file is returned and _psize_ is set to the amount
+of data that was read. The returned content must be freed with *free*(3).
+This acts similar to the *tracefs_instance_file_read*(3), but is
+to be used to read the event file if the _system_ and _event_ are already
+known.
+
+The *tracefs_event_file_write()* writes _str_ to the _event_ _file_.
+It will truncate anything that is already in that file.
+This acts similar to the *tracefs_instance_file_write*(3), but is
+to be used to read the event file if the _system_ and _event_ are already
+known.
+
+The *tracefs_event_file_append()* appends _str_ to the _event_ _file_.
+It will not clear out the file as it writes _sting_.
+This acts similar to the *tracefs_instance_file_append*(3), but is
+to be used to read the event file if the _system_ and _event_ are already
+known.
+
+The *tracefs_event_file_clear()* clears the content of the _event_ _file_.
+This acts similar to the *tracefs_instance_file_clear*(3), but is
+to be used to read the event file if the _system_ and _event_ are already
+known.
+
+The *tracefs_event_file_exists()* returns true if the _event_ _file_
+exists, and false otherwise. This acts similar to the *tracefs_instance_file_exists*(3),
+but is to be used to read the event file if the _system_ and _event_ are already
+known.
+
+RETURN VALUE
+------------
+*tracefs_event_get_file()* returns the path of the given _system_/_event_ _file_ on
+success and NULL on error. The return value must be freed with *tracefs_put_tracing_file*(3).
+
+*tracefs_event_file_read()* reads the content of the _system_/_event_ _file_ or
+NULL on error. The return pointer must be freed with *free*(3).
+
+*tracefs_event_file_write()* and *tracefs_event_file_append()* returns the number of
+bytes written to the _system_/_event_ _file_ or negative on error.
+
+*tracefs_event_file_clear()* returns zero on success and -1 on error.
+
+*tracefs_event_file_exists()* returns true if the _system_/_event_ _file_ exists for
+the given _instance_ (or top level if _instance_ is NULL) or false otherwise.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <tracefs.h>
+
+int main(int argc, char **argv)
+{
+ char *system;
+ char *event;
+ char *file;
+ char *cmd = NULL;
+ char *buf;
+ char *str;
+ char ch = 'r';
+ int size;
+
+ if (argc < 4) {
+ printf("usage: %s sytem event file [(-a|-w) write | -c]\n"
+ " reads the system/event file or writes if [write is supplied]\n",
+ argv[0]);
+ exit(0);
+ }
+
+ system = argv[1];
+ event = argv[2];
+ file = argv[3];
+ if (argc > 4)
+ cmd = argv[4];
+
+ if (!tracefs_event_file_exists(NULL, system, event, file)) {
+ fprintf(stderr, "File %s/%s/%s does not exist\n",
+ system, event, file);
+ exit(-1);
+ }
+
+ if (cmd) {
+ if (cmd[0] != '-')
+ ch = cmd[0];
+ else
+ ch = cmd[1];
+ if (!ch)
+ ch = 'c';
+ }
+
+ switch (ch) {
+ case 'r':
+ buf = tracefs_event_file_read(NULL, system, event, file, &size);
+ if (buf)
+ printf("%s", buf);
+ else
+ fprintf(stderr, "Failed to read %s/%s/%s\n",
+ system, event, file);
+ free(buf);
+ break;
+ case 'w':
+ case 'a':
+ if (argc < 6) {
+ fprintf(stderr, "%s command requires something to write\n",
+ ch == 'w' ? "write" : "append");
+ exit(-1);
+ }
+ if (ch == 'w')
+ size = tracefs_event_file_write(NULL, system, event, file, argv[5]);
+ else
+ size = tracefs_event_file_append(NULL, system, event, file, argv[5]);
+ if (size < 0) {
+ fprintf(stderr, "Failed to write '%s' to %s/%s/%s\n",
+ argv[5], system, event, file);
+ exit(-1);
+ }
+ break;
+ case 'c':
+ if (tracefs_event_file_clear(NULL, system, event, file) < 0) {
+ fprintf(stderr, "Failed to clear %s/%s/%s\n",
+ system, event, file);
+ exit(-1);
+ }
+ break;
+ default:
+ fprintf(stderr, "Unknown command '%c'\n", ch);
+ exit(-1);
+ }
+ 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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+--
+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) 2022 Google, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).
diff --git a/Documentation/libtracefs-events-tep.txt b/Documentation/libtracefs-events-tep.txt
new file mode 100644
index 0000000..22d3dd5
--- /dev/null
+++ b/Documentation/libtracefs-events-tep.txt
@@ -0,0 +1,148 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_local_events, tracefs_local_events_system, tracefs_fill_local_events,
+tracefs_load_cmdlines -
+Initialize a tep handler with trace events from the local system.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+struct tep_handle pass:[*]*tracefs_local_events*(const char pass:[*]_tracing_dir_);
+struct tep_handle pass:[*]*tracefs_local_events_system*(const char pass:[*]_tracing_dir_, const char pass:[*] const pass:[*]_sys_names_);
+int *tracefs_fill_local_events*(const char pass:[*]_tracing_dir_, struct tep_handle pass:[*]_tep_, int pass:[*]_parsing_failures_);
+int *tracefs_load_cmdlines*(const char pass:[*]_tracing_dir_, struct tep_handle pass:[*]_tep_);
+--
+
+DESCRIPTION
+-----------
+Functions for initializing a tep handler with trace events from the local system.
+
+The *tracefs_local_events()* function allocates a new _tep_ handler and
+initializes it with events from all trace systems, located in the given
+_tracing_dir_ directory. This could be NULL or the location of the tracefs
+mount point for the trace systems of the local machine, or it may be a path
+to a copy of the tracefs directory from another machine.
+
+The *tracefs_local_events_system()* function allocates a new _tep_ handler
+and initializes it with events from specified trace systems _sys_names_,
+located in the given _tracing_dir_ directory. This could be NULL or the
+location of the tracefs mount point for the trace systems of the local
+machine, or it may be a path to a copy of the tracefs directory from another
+machine. The _sys_names_ argument is an array of trace system names, that
+will be used for _tep_ handler initialization. The last element in that
+array must be a NULL pointer.
+
+The *tracefs_fill_local_events()* function initializes already allocated _tep_
+handler with events from all trace systems, located in the given _tracing_dir_
+directory. This could be NULL or the location of the tracefs mount point
+for the trace systems of the local machine, or it may be a path to a copy
+of the tracefs directory from another machine. The _tep_ argument must be
+a pointer to already allocated tep handler, that is going to be initialized.
+The _parsing_failures_ argument could be NULL or a pointer to an integer,
+where the number of failures while parsing the event files are returned.
+
+The above functions will also load the mappings between pids and the process
+command line names. In some cases the _tep_ handle is created with one
+of the above before tracing begins. As the mappings get updated during the
+trace, there may be a need to read the mappings again after the trace.
+The *tracefs_load_cmdlines()* does just that. The _tracing_dir_ is
+the directory of the mount point to load from, or NULL to use the
+mount point of the tracefs file system.
+
+RETURN VALUE
+------------
+The *tracefs_local_events()* and *tracefs_local_events_system()* functions
+return pointer to allocated and initialized _tep_ handler, or NULL in
+case of an error. The returned _tep_ handler must be freed with *tep_free*(3).
+
+The *tracefs_fill_local_events()* function returns -1 in case of an error or
+0 otherwise.
+
+The *tracefs_load_cmdlines()* function returns -1 in case of an error, or
+0 otherwise.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <tracefs.h>
+
+struct tep_handle *tep;
+...
+ tep = tracefs_local_events(NULL);
+ if (!tep) {
+ /* Failed to initialise tep handler with local events from top instance */
+ ...
+ }
+...
+ tep_free(tep);
+...
+ const char *systems[] = {"ftrace", "irq", NULL};
+ tep = tracefs_local_events_system(NULL, systems);
+ if (!tep) {
+ /* Failed to initialise tep handler with local events from
+ * ftrace and irq systems in top instance.
+ */
+ ...
+ }
+...
+ tep_free(tep);
+...
+ int parsing_failures;
+ tep = tep_alloc();
+ if (!tep) {
+ /* Failed to allocate a tep handler */
+ ...
+ }
+ if (tracefs_fill_local_events(NULL, tep, &parsing_failures) < 0) {
+ /* Failed to initialise tep handler with local events from top instance */
+ }
+ tracefs_load_cmdlines(NULL, tep);
+...
+ tep_free(tep);
+--
+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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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).
diff --git a/Documentation/libtracefs-events.txt b/Documentation/libtracefs-events.txt
new file mode 100644
index 0000000..90c54b8
--- /dev/null
+++ b/Documentation/libtracefs-events.txt
@@ -0,0 +1,195 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_event_systems, tracefs_system_events, tracefs_event_enable, tracefs_event_disable,
+tracefs_event_is_enabled - Work with trace systems and events.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+enum tracefs_event_state {
+ TRACEFS_ERROR = -1,
+ TRACEFS_ALL_DISABLED = 0,
+ TRACEFS_ALL_ENABLED = 1,
+ TRACEFS_SOME_ENABLED = 2,
+};
+
+char pass:[*]pass:[*]*tracefs_event_systems*(const char pass:[*]_tracing_dir_);
+char pass:[*]pass:[*]*tracefs_system_events*(const char pass:[*]_tracing_dir_, const char pass:[*]_system_);
+int *tracefs_event_enable*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_system_,
+ const char pass:[*]_event_);
+int *tracefs_event_disable*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_system_,
+ const char pass:[*]_event_);
+enum tracefs_enable_state *tracefs_event_is_enabled*(struct tracefs_instance pass:[*]_instance_,
+ const char pass:[*]_system_, const char pass:[*]_event_);
+--
+
+DESCRIPTION
+-----------
+Trace systems and events related APIs.
+
+The *tracefs_event_systems()* function returns array of strings with the
+names of all registered trace systems, located in the given _tracing_dir_
+directory. This could be NULL or the location of the tracefs mount point
+for the trace systems of the local machine, or it may be a path to a copy
+of the tracefs directory from another machine. The last entry in the array
+is a NULL pointer. The array must be freed with *tracefs_list_free()* API.
+
+The *tracefs_system_events()* function returns array of strings with the
+names of all registered trace events for given trace system specified by
+_system_, located in the given _tracing_dir_ directory. This could be NULL
+or the location of the tracefs mount point for the trace systems of the
+local machine, or it may be a path to a copy of the tracefs directory
+from another machine. The last entry in the array as a NULL pointer.
+The array must be freed with *tracefs_list_free()* API.
+
+The *tracefs_event_enable()* function enables a given event based on
+the _system_ and _event_ passed in for the given _instance_. If _instance_
+is NULL, then the top level tracing directory is used. If _system_
+and _event_ are both NULL, then all events are enabled for the _instance_.
+If _event_ is NULL then all events within the _system_ are enabled.
+If _system_ is NULL, then all systems are searched and any event within
+a system that matches _event_ is enabled. Both _system_ and _event_ may
+be regular expressions as defined by *regex*(3).
+
+The *tracefs_event_disable()* function disables the events that match
+the _system_ and _event_ parameters for the given _instance_. What events
+are disable follow the same rules as *tracefs_event_enable()* for matching
+events. That is, if _instance_ is NULL, then the top level tracing directory
+is used. If both _system_ and _event_ are NULL then all events are disabled
+for the given _instance_, and so on.
+
+The *tracefs_event_is_enabled()* returns if an event is enabled, a set of
+events are enabled, a system is enabled, or all events are enabled. If both
+_system_ and _event_ are NULL, then it returns the enable state of all events.
+If _system_ is not NULL and _event_ is NULL, then it will check if all the events
+in all the systems that _system_ and return the enable state of those events.
+If _system_ is NULL and _event_ is not NULL, then it will match all the events
+in all systems that match _event_ and return their enabled state. If both _system_
+and _event_ are not NULL, then it will return the enabled state of all matching
+events. The enabled state is defined as:
+
+*TRACEFS_ERROR* - An error occurred including no event were matched.
+
+*TRACEFS_ALL_DISABLED* - All matching events are disabled.
+
+*TRACEFS_ALL_ENABLED* - All matching events are enabled.
+
+*TRACEFS_SOME_ENABLED* - Some matching events were enabled while others were not.
+
+RETURN VALUE
+------------
+The *tracefs_event_systems()* and *tracefs_system_events()* functions return
+an array of strings. The last element in that array is a NULL pointer. The array
+must be freed with *tracefs_list_free()* API. In case of an error, NULL is returned.
+
+Both *tracefs_event_enable()* and *tracefs_event_disable()* return 0 if they found
+any matching events (Note it does not check the previous status of the event. If
+*tracefs_event_enable()* finds an event that is already enabled, and there are no
+other errors, then it will return 0). If an error occurs, even if other events were
+found, it will return -1 and errno will be set. If no errors occur, but no events
+are found that match the _system_ and _event_ parameters, then -1 is returned
+and errno is not set.
+
+The *tracefs_event_is_enabled()* returns the enabled status of the matching events
+or TRACEFS_ERROR on error.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <tracefs.h>
+
+char **systems = tracefs_event_systems(NULL);
+
+ if (systems) {
+ int i = 0;
+ /* Got registered trace systems from the top trace instance */
+ while (systems[i]) {
+ char **events = tracefs_system_events(NULL, systems[i]);
+ if (events) {
+ /* Got registered events in system[i] from the top trace instance */
+ int j = 0;
+
+ while (events[j]) {
+ /* Got event[j] in system[i] from the top trace instance */
+ j++;
+ }
+ tracefs_list_free(events);
+ }
+ i++;
+ }
+ tracefs_list_free(systems);
+ }
+....
+static int records_walk(struct tep_event *tep, struct tep_record *record, int cpu, void *context)
+{
+ /* Got recorded event on cpu */
+ return 0;
+}
+...
+struct tep_handle *tep = tracefs_local_events(NULL);
+
+ if (!tep) {
+ /* Failed to initialise tep handler with local events */
+ ...
+ }
+
+ errno = 0;
+ ret = tracefs_event_enable(NULL, "sched", NULL);
+ if (ret < 0 && !errno)
+ printf("Could not find 'sched' events\n");
+ tracefs_event_enable(NULL, "irq", "irq_handler_\(enter\|exit\)");
+
+ if (tracefs_iterate_raw_events(tep, NULL, NULL, 0, records_walk, NULL) < 0) {
+ /* Error walking through the recorded raw events */
+ }
+
+ /* Disable all events */
+ tracefs_event_disable(NULL, NULL, NULL);
+ tep_free(tep);
+--
+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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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).
diff --git a/Documentation/libtracefs-files.txt b/Documentation/libtracefs-files.txt
new file mode 100644
index 0000000..d22e759
--- /dev/null
+++ b/Documentation/libtracefs-files.txt
@@ -0,0 +1,131 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_get_tracing_file, tracefs_put_tracing_file, tracefs_tracing_dir, tracefs_debug_dir, tracefs_set_tracing_dir,
+tracefs_tracing_dir_is_mounted - Find and set locations of trace directory and files.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+char pass:[*]*tracefs_get_tracing_file*(const char pass:[*]_name_);
+void *tracefs_put_tracing_file*(char pass:[*]_name_);
+const char pass:[*]*tracefs_tracing_dir*(void);
+const char pass:[*]*tracefs_debug_dir*(void);
+int *tracefs_set_tracing_dir*(char pass:[*]_tracing_dir_)
+int *tracefs_tracing_dir_is_mounted*(bool _mount_, const char pass:[**]_path_);
+--
+
+DESCRIPTION
+-----------
+This set of APIs can be used to find the full path of the trace file
+system mount point and trace files in it.
+
+The *tracefs_set_tracing_dir()* function sets a custom location of the
+system's tracing directory mount point. Usually, the library auto detects
+it using the information from the /proc/mounts file. Use this API only if the
+mount point is not standard and cannot be detected by the library. The _tracing_dir_
+argument can be NULL, in that case the custom location is deleted and the library
+auto detection logic is used.
+
+The *tracefs_get_tracing_file()* function returns the full path of the
+file with given _name_ in the trace file system. The function works
+only with files in the tracefs main directory, it is not trace instance
+aware. It is recommended to use *tracefs_instance_get_file()* and
+*tracefs_instance_get_dir()* instead. The returned string must be freed
+with *tracefs_put_tracing_file()*.
+
+The *tracefs_put_tracing_file()* function frees trace file name,
+returned by *tracefs_get_tracing_file()*.
+
+The *tracefs_tracing_dir()* function returns the full path to the
+trace file system. In the first function call, the mount point of the
+tracing file system is located, cached and returned. It will mount it,
+if it is not mounted. On any subsequent call the cached path is returned.
+The return string must _not_ be freed.
+
+The *tracefs_debug_dir()* is similar to *tracefs_tracing_dir()* except
+that it will return where the debugfs file system is mounted. If it
+is not mounted it will try to mount it. The return string must _not_
+be freed.
+
+*tracefs_tracing_dir_is_mounted()* returns 1 if the tracing directory is
+already mounted and 0 if it is not. If _mount_ is true, it will try to
+mount it if it is not, and returns 0 if it succesfully mounted it and -1
+if it did not. If _path_ is set, it will be assigned to the path where it
+mounted it. _path_ is internal and should not be freed.
+
+RETURN VALUE
+------------
+The *tracefs_set_tracing_dir()* function returns 0 on success, -1 otherwise.
+
+The *tracefs_get_tracing_file()* function returns a string or NULL in case
+of an error. The returned string must be freed with *tracefs_put_tracing_file()*.
+
+The *tracefs_tracing_dir()* function returns a constant string or NULL
+in case of an error. The returned string must _not_ be freed.
+
+The *tracefs_debug_dir()* function returns a constant string or NULL
+in case of an error. The returned string must _not_ be freed.
+
+The *tracefs_tracing_dir_is_mounted()* returns 1 if the tracing directory
+is already mounted, 0 if it is not, and -1 on error.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <tracefs.h>
+...
+char *trace_on = tracefs_get_tracing_file("tracing_on");
+ if (trace_on) {
+ ...
+ tracefs_put_tracing_file(trace_on);
+ }
+...
+const char *trace_dir = tracefs_tracing_dir();
+
+--
+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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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).
diff --git a/Documentation/libtracefs-filter.txt b/Documentation/libtracefs-filter.txt
new file mode 100644
index 0000000..12726b9
--- /dev/null
+++ b/Documentation/libtracefs-filter.txt
@@ -0,0 +1,345 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_filter_string_append, tracefs_filter_string_verify, tracefs_event_filter_apply, tracefs_event_filter_clear -
+Add, verify and apply event filters
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+int *tracefs_filter_string_append*(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_filter_string_verify*(struct tep_event pass:[*]_event_, const char pass:[*]_filter_, char pass:[**]_err_);
+int *tracefs_event_filter_apply*(struct tracefs_instance pass:[*]_instance_, struct tep_event pass:[*]_event_, const char pass:[*]_filter_);
+int *tracefs_event_filter_clear*(struct tracefs_instance pass:[*]_instance_, struct tep_event pass:[*]_event_);
+
+--
+
+DESCRIPTION
+-----------
+*tracefs_filter_string_append*() 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_filter_string_verify*() 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*().
+
+*tracefs_event_filter_apply*() applies given _filter_ string on _event_ in given _instance_.
+
+*tracefs_event_filter_clear*() clear all filters on _event_ in given _instance_.
+
+RETURN VALUE
+------------
+*tracefs_filter_string_append*() returns 0 on success and -1 on error.
+
+*tracefs_filter_string_verify*() 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*().
+
+*tracefs_event_filter_apply*() returns 0 on success and -1 on error.
+
+*tracefs_event_filter_clear*() returns 0 on success and -1 on error.
+
+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_filter_string_verify(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_filter_string_append(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);
+ }
+ }
+
+ if (tracefs_event_filter_apply(NULL, event, new_filter))
+ fprintf(stderr, "Failed to apply filter on event");
+
+ 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_alloc_2d*(3),
+*tracefs_hist_alloc_nd*(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).
diff --git a/Documentation/libtracefs-function-filter.txt b/Documentation/libtracefs-function-filter.txt
new file mode 100644
index 0000000..2a141fd
--- /dev/null
+++ b/Documentation/libtracefs-function-filter.txt
@@ -0,0 +1,237 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_function_filter, tracefs_function_notrace, tracefs_filter_functions
+- Functions to modify the the function trace filters
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+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
+-----------
+*tracefs_function_filter* and *tracefs_function_notrace* can be used to limit the
+Linux kernel functions that would be traced by the function and function-graph tracers.
+The *tracefs_function_filter* defines a list of functions that can be traced.
+The *tracefs_function_notrace* defines a list of functions that will not be traced.
+If a function is in both lists, it will not be traced.
+
+They take an _instance_ , that can be NULL for the top level tracing,
+_filter_, a string that represents a filter that should
+be applied to define what functions are to be traced,
+_module_, to limit the filtering on a specific module (or NULL to filter on all functions),
+_flags_ which holds control knobs on how the filters will be handled (see *FLAGS*)
+section below.
+
+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
+anything other than alpha numeric characters, or '.', 'pass:[*]', '?') the _filter_
+will be processed as a regex(3) following the rules of regex(3), and '.' is
+not a period, but will match any one character. To force a regular
+expression, either prefix _filter_ with a '^' or append it with a '$' as
+the _filter_ does complete matches of the functions anyway.
+
+If _module_ is set and _filter_ is NULL, this will imply the same as _filter_ being
+equal to "pass:[*]". Which will enable all functions for a given _module_. Otherwise
+the _filter_ may be NULL if a previous call to *tracefs_function_filter()* with
+the same _instance_ had *TRACEFS_FL_CONTINUE* set and this call does not. This is
+useful to simply commit the previous filters. It may also be NULL
+if *TRACEFS_FL_RESET* is set and the previous call did not have the same _instance_
+and *TRACEFS_FL_CONTINUE* set. This is useful to just clear the filter.
+
+FLAGS
+-----
+
+The _flags_ parameter may have the following set, or be zero.
+
+*TRACEFS_FL_RESET* :
+If _flags_ contains *TRACEFS_FL_RESET*, then it will clear the filters that
+are currently set before applying _filter_. Otherwise, _filter_ is added to
+the current set of filters already enabled. If this flag is set and the
+previous call to tracefs_function_filter() had the same _instance_ and the
+*TRACEFS_FL_CONTINUE* flag was set, then the function will fail with a
+return of -1 and errno set to EBUSY.
+
+*TRACEFS_FL_CONTINUE* :
+If _flags_ contains *TRACEFS_FL_CONTINUE*, then _filter_ will not take
+effect after a successful call to tracefs_function_filter(). This allows for
+multiple calls to tracefs_function_filter() to update the filter function
+and then a single call (one without the *TRACEFS_FL_CONTINUE* flag set) to
+commit all the filters.
+It can be called multiple times to add more filters. A call without this
+flag set will commit the changes before returning (if the _filter_ passed in
+successfully matched). A tracefs_function_filter() call after one that had
+the *TRACEFS_FL_CONTINUE* flag set for the same instance will fail if
+*TRACEFS_FL_RESET* flag is set, as the reset flag is only applicable for the
+first filter to be added before committing.
+
+*TRACEFS_FL_FUTURE* :
+If _flags_ contains *TRACEFS_FL_FUTURE* and _module_ holds a string of a module,
+then if the module is not loaded it will attemp to write the filter with the module
+in the filter file. Starting in Linux v4.13 module functions could be added to the
+filter before they are loaded. The filter will be cached, and when the module is
+loaded, the filter will be set before the module executes, allowing to trace
+init functions of a module. This will only work if the _filter_ is not a
+regular expression.
+
+RETURN VALUE
+------------
+
+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.
+
+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
+------
+
+*tracefs_function_filter*() can fail with the following errors:
+
+*EINVAL* The filter is invalid or did not match any functions.
+
+*EBUSY* The previous call of *tracefs_function_filter*() was called
+with the same instance and *TRACEFS_FL_CONTINUE* set and the current call
+had *TRACEFS_FL_RESET* set.
+
+Other errors may also happen caused by internal system calls.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdio.h>
+#include <errno.h>
+#include <tracefs.h>
+
+#define INST "dummy"
+
+static const char *filters[] = { "run_init_process", "try_to_run_init_process", "dummy1", NULL };
+
+int main(int argc, char *argv[])
+{
+ struct tracefs_instance *inst = tracefs_instance_create(INST);
+ char **func_list;
+ int ret;
+ int i;
+
+ if (!inst) {
+ /* 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_list_free(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) {
+ printf("Failed to set the notrace filter\n");
+ goto out;
+ }
+
+ /* First reset the filter */
+ ret = tracefs_function_filter(inst, NULL, NULL,
+ TRACEFS_FL_RESET | TRACEFS_FL_CONTINUE);
+ if (ret) {
+ printf("Failed to reset the filter\n");
+ /* Make sure it is closed, -1 means filter was started */
+ if (ret < 0)
+ tracefs_function_filter(inst, NULL, NULL, 0);
+ }
+
+ for (i = 0; filters[i]; i++) {
+ ret = tracefs_function_filter(inst, filters[i], NULL,
+ TRACEFS_FL_CONTINUE);
+
+ if (ret) {
+ if (errno == EINVAL)
+ printf("Filter %s did not match\n", filters[i]);
+ else
+ printf("Failed writing %s\n", filters[i]);
+ }
+ }
+
+ ret = tracefs_function_filter(inst, "*", "ext4", 0);
+ if (ret) {
+ printf("Failed to set filters for ext4\n");
+ /* Force the function to commit previous filters */
+ tracefs_function_filter(inst, NULL, NULL, 0);
+ }
+
+ out:
+ tracefs_instance_destroy(inst);
+ return ret;
+}
+--
+
+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)
+
+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).
diff --git a/Documentation/libtracefs-hist-cont.txt b/Documentation/libtracefs-hist-cont.txt
new file mode 100644
index 0000000..7159e27
--- /dev/null
+++ b/Documentation/libtracefs-hist-cont.txt
@@ -0,0 +1,222 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_hist_start, tracefs_hist_destroy, tracefs_hist_pause,
+tracefs_hist_continue, tracefs_hist_reset - Pause, continue, or clear an existing histogram
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+int *tracefs_hist_start*(struct tracefs_instance pass:[*]_instance_, struct tracefs_hist pass:[*]_hist_);
+int *tracefs_hist_destroy*(struct tracefs_instance pass:[*]_instance_, struct tracefs_hist pass:[*]_hist_);
+int *tracefs_hist_pause*(struct tracefs_instance pass:[*]_instance_, struct tracefs_hist pass:[*]_hist_);
+int *tracefs_hist_continue*(struct tracefs_instance pass:[*]_instance_, struct tracefs_hist pass:[*]_hist_);
+int *tracefs_hist_reset*(struct tracefs_instance pass:[*]_instance_, struct tracefs_hist pass:[*]_hist_);
+
+--
+
+DESCRIPTION
+-----------
+
+*tracefs_hist_start()* is called to actually start the histogram _hist_.
+The _instance_ is the instance to start the histogram in, NULL if it
+should start at the top level.
+
+*tracefs_hist_pause()* is called to pause the histogram _hist_.
+The _instance_ is the instance to pause the histogram in, NULL if it
+is in the top level.
+
+*tracefs_hist_continue()* is called to continue a paused histogram _hist_.
+The _instance_ is the instance to continue the histogram, NULL if it
+is in the top level.
+
+*tracefs_hist_reset()* is called to clear / reset the histogram _hist_.
+The _instance_ is the instance to clear the histogram, NULL if it
+is in the top level.
+
+*tracefs_hist_destroy()* is called to delete the histogram where it will no longer
+exist. The _instance_ is the instance to delete the histogram from, NULL if it
+is in the top level.
+
+RETURN VALUE
+------------
+All the return zero on success or -1 on error.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdlib.h>
+#include <tracefs.h>
+
+enum commands {
+ START,
+ PAUSE,
+ CONT,
+ RESET,
+ DELETE,
+ SHOW,
+};
+
+int main (int argc, char **argv, char **env)
+{
+ struct tracefs_instance *instance;
+ struct tracefs_hist *hist;
+ struct tep_handle *tep;
+ enum commands cmd;
+ char *cmd_str;
+ int ret;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s command\n", argv[0]);
+ exit(-1);
+ }
+
+ cmd_str = argv[1];
+
+ if (!strcmp(cmd_str, "start"))
+ cmd = START;
+ else if (!strcmp(cmd_str, "pause"))
+ cmd = PAUSE;
+ else if (!strcmp(cmd_str, "cont"))
+ cmd = CONT;
+ else if (!strcmp(cmd_str, "reset"))
+ cmd = RESET;
+ else if (!strcmp(cmd_str, "delete"))
+ cmd = DELETE;
+ else if (!strcmp(cmd_str, "show"))
+ cmd = SHOW;
+ else {
+ fprintf(stderr, "Unknown command %s\n", cmd_str);
+ exit(-1);
+ }
+
+ tep = tracefs_local_events(NULL);
+ if (!tep) {
+ perror("Reading tracefs");
+ exit(-1);
+ }
+
+ instance = tracefs_instance_create("hist_test");
+ if (!instance) {
+ fprintf(stderr, "Failed instance create\n");
+ exit(-1);
+ }
+
+ hist = tracefs_hist_alloc_2d(tep, "kmem", "kmalloc",
+ "call_site",TRACEFS_HIST_KEY_SYM,
+ "bytes_req", 0);
+ if (!hist) {
+ fprintf(stderr, "Failed hist create\n");
+ exit(-1);
+ }
+
+ ret = tracefs_hist_add_value(hist, "bytes_alloc");
+ ret |= tracefs_hist_add_sort_key(hist, "bytes_req");
+ ret |= tracefs_hist_add_sort_key(hist, "bytes_alloc");
+
+ ret |= tracefs_hist_sort_key_direction(hist, "bytes_alloc",
+ TRACEFS_HIST_SORT_DESCENDING);
+ if (ret) {
+ fprintf(stderr, "Failed modifying histogram\n");
+ exit(-1);
+ }
+
+ tracefs_error_clear(instance);
+
+ switch (cmd) {
+ case START:
+ ret = tracefs_hist_start(instance, hist);
+ if (ret) {
+ char *err = tracefs_error_last(instance);
+ if (err)
+ fprintf(stderr, "\n%s\n", err);
+ }
+ break;
+ case PAUSE:
+ ret = tracefs_hist_pause(instance, hist);
+ break;
+ case CONT:
+ ret = tracefs_hist_continue(instance, hist);
+ break;
+ case RESET:
+ ret = tracefs_hist_reset(instance, hist);
+ break;
+ case DELETE:
+ ret = tracefs_hist_destroy(instance, hist);
+ break;
+ case SHOW: {
+ char *content;
+ content = tracefs_event_file_read(instance, "kmem", "kmalloc",
+ "hist", NULL);
+ ret = content ? 0 : -1;
+ if (content) {
+ printf("%s\n", content);
+ free(content);
+ }
+ break;
+ }
+ }
+ if (ret)
+ fprintf(stderr, "Failed: command\n");
+ exit(ret);
+}
+
+--
+
+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_alloc_2d*(3),
+*tracefs_hist_alloc_nd*(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).
diff --git a/Documentation/libtracefs-hist-mod.txt b/Documentation/libtracefs-hist-mod.txt
new file mode 100644
index 0000000..b308c7e
--- /dev/null
+++ b/Documentation/libtracefs-hist-mod.txt
@@ -0,0 +1,540 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_hist_add_sort_key, tracefs_hist_set_sort_key, tracefs_hist_sort_key_direction,
+tracefs_hist_add_name, tracefs_hist_append_filter, tracefs_hist_echo_cmd, tracefs_hist_command,
+tracefs_hist_get_name, tracefs_hist_get_event, tracefs_hist_get_system - Update and describe an event histogram
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+int *tracefs_hist_add_sort_key*(struct tracefs_hist pass:[*]_hist_,
+ const char pass:[*]_sort_key_);
+
+int *tracefs_hist_set_sort_key*(struct tracefs_hist pass:[*]_hist_,
+ const char pass:[*]_sort_key_, _..._);
+int *tracefs_hist_sort_key_direction*(struct tracefs_hist pass:[*]_hist_,
+ const char pass:[*]_sort_key_,
+ enum tracefs_hist_sort_direction _dir_);
+
+int *tracefs_hist_add_name*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_name_);
+
+int *tracefs_hist_append_filter*(struct tracefs_hist pass:[*]_hist_,
+ enum tracefs_filter _type_,
+ const char pass:[*]_field_,
+ enum tracefs_compare _compare_,
+ const char pass:[*]_val_);
+
+int *tracefs_hist_echo_cmd*(struct trace_seq pass:[*]_s_, struct tracefs_instance pass:[*]_instance_,
+ struct tracefs_hist pass:[*]_hist_,
+ enum tracefs_hist_command _command_);
+
+int *tracefs_hist_command*(struct tracefs_instance pass:[*]_instance_,
+ struct tracefs_hist pass:[*]_hist_,
+ enum tracefs_hist_command _command_);
+
+const char pass:[*]*tracefs_hist_get_name*(struct tracefs_hist pass:[*]_hist_);
+
+const char pass:[*]*tracefs_hist_get_event*(struct tracefs_hist pass:[*]_hist_);
+
+const char pass:[*]*tracefs_hist_get_system*(struct tracefs_hist pass:[*]_hist_);
+
+--
+
+DESCRIPTION
+-----------
+Event histograms are created by the trigger file in the event directory.
+The syntax can be complex and difficult to get correct. This API handles the
+syntax, and facilitates the creation and interaction with the event histograms.
+See https://www.kernel.org/doc/html/latest/trace/histogram.html for more information.
+
+*tracefs_hist_add_sort_key*() will add a key to sort on. The _hist_ is the
+histogram descriptor to add the sort key to. The _sort_key_ is a string
+that must match either an already defined key of the histogram, or an already
+defined value. If _hist_ already has sorting keys (previously added) the new
+_sort_key_ will have lower priority(be secondary or so on) when sorting.
+
+*tracefs_hist_set_sort_key*() will reset the list of key to sort on. The _hist_ is
+the histogram descriptor to reset the sort key to. The _sort_key_ is a string
+that must match either an already defined key of the histogram, or an already
+defined value. Multiple sort keys may be added to denote a secondary, sort order
+and so on, but all sort keys must match an existing key or value, or be
+TRACEFS_HIST_HITCOUNT. The last parameter of *tracefs_hist_add_sort_key*() must
+be NULL.
+
+*tracefs_hist_sort_key_direction*() allows to change the direction of an
+existing sort key of _hist_. The _sort_key_ is the sort key to change, and
+_dir_ can be either TRACEFS_HIST_SORT_ASCENDING or TRACEFS_HIST_SORT_DESCENDING,
+to make the direction of the sort key either ascending or descending respectively.
+
+*tracefs_hist_add_name*() adds a name to a histogram. A histogram may be
+named and if the name matches between more than one event, and they have
+compatible keys, the multiple histograms with the same name will be merged
+into a single histogram (shown by either event's hist file). The _hist_
+is the histogram to name, and the _name_ is the name to give it.
+
+*tracefs_hist_append_filter*() creates a filter or appends to it for the
+histogram event. Depending on _type_, it will build a string of tokens for
+parenthesis or logic statements, 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.
+
+*trace_hist_echo_cmd*() prints the commands needed to create the given histogram
+in the given _instance_, or NULL for the top level, into the _seq_.
+The command that is printed is described by _command_ and shows the functionality
+that would be done by *tracefs_hist_command*(3).
+
+*tracefs_hist_command*() is called to process a command on the histogram
+_hist_ for its event in the given _instance_, or NULL for the top level.
+The _cmd_ can be one of:
+
+*TRACEFS_HIST_CMD_START* or zero to start execution of the histogram.
+
+*TRACEFS_HIST_CMD_PAUSE* to pause the given histogram.
+
+*TRACEFS_HIST_CMD_CONT* to continue a paused histogram.
+
+*TRACEFS_HIST_CMD_CLEAR* to reset the values of a histogram.
+
+*TRACEFS_HIST_CMD_DESTROY* to destroy the histogram (undo a START).
+
+The below functions are wrappers to tracefs_hist_command() to make the
+calling conventions a bit easier to understand what is happening.
+
+KEY TYPES
+---------
+
+*tracefs_hist_alloc_nd*() and *tracefs_hist_add_key*() both add a key and requires
+that key to have a type. The types may be:
+
+*TRACEFS_HIST_KEY_NORMAL* or zero (0) which is to not modify the type.
+
+*TRACEFS_HIST_KEY_HEX* to display the key in hex.
+
+*TRACEFS_HIST_KEY_SYM* to display the key as a kernel symbol (if found). If
+the key is an address, this is useful as it will display the function names instead
+of just a number.
+
+*TRACEFS_HIST_KEY_SYM_OFFSET* similar to *TRACEFS_HIST_KEY_SYM* but will also include
+the offset of the function to match the exact address.
+
+*TRACEFS_HIST_KEY_SYSCALL* If the key is a system call "id" (the number passed from user
+space to the kernel to tell it what system call it is calling), then the name of
+the system call is displayed.
+
+*TRACEFS_HIST_KEY_EXECNAME* If "common_pid" is the key (the pid of the executing task),
+instead of showing the number, show the name of the running task.
+
+*TRACEFS_HIST_KEY_LOG* will display the key in a binary logarithmic scale.
+
+*TRACEFS_HIST_KEY_USECS* for use with "common_timestamp" or TRACEFS_HIST_TIMESTAMP,
+in which case it will show the timestamp in microseconds instead of nanoseconds.
+
+RETURN VALUE
+------------
+*tracefs_hist_get_name*() returns the name of the histogram or NULL on error.
+The returned string belongs to the histogram object and is freed with the histogram
+by *tracefs_hist_free*().
+
+*tracefs_hist_get_event*() returns the event name of the histogram or NULL on error.
+The returned string belongs to the histogram object and is freed with the histogram
+by *tracefs_hist_free*().
+
+*tracefs_hist_get_system*() returns the system name of the histogram or NULL on error.
+The returned string belongs to the histogram object and is freed with the histogram
+by *tracefs_hist_free*().
+
+*tracefs_hist_alloc_nd*() returns an allocated histogram descriptor which must
+be freed by *tracefs_hist_free*() or NULL on error.
+
+*tracefs_hist_get_name*(), *tracefs_hist_get_event*() and *tracefs_hist_get_system*()
+return strings owned by the histogram object.
+
+All the other functions return zero on success or -1 on error.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdlib.h>
+#include <unistd.h>
+#include <tracefs.h>
+
+enum commands {
+ START,
+ PAUSE,
+ CONT,
+ RESET,
+ DELETE,
+ SHOW,
+};
+
+static void parse_system_event(char *group, char **system, char **event)
+{
+ *system = strtok(group, "/");
+ *event = strtok(NULL, "/");
+ if (!*event) {
+ *event = *system;
+ *system = NULL;
+ }
+}
+
+static int parse_keys(char *keys, struct tracefs_hist_axis **axes)
+{
+ char *sav = NULL;
+ char *key;
+ int cnt = 0;
+
+ for (key = strtok_r(keys, ",", &sav); key; key = strtok_r(NULL, ",", &sav)) {
+ struct tracefs_hist_axis *ax;
+ char *att;
+
+ ax = realloc(*axes, sizeof(*ax) * (cnt + 2));
+ if (!ax) {
+ perror("Failed to allocate axes");
+ exit(-1);
+ }
+ ax[cnt].key = key;
+ ax[cnt].type = 0;
+ ax[cnt + 1].key = NULL;
+ ax[cnt + 1].type = 0;
+
+ *axes = ax;
+
+ att = strchr(key, '.');
+ if (att) {
+ *att++ = '\0';
+ if (strcmp(att, "hex") == 0)
+ ax[cnt].type = TRACEFS_HIST_KEY_HEX;
+ else if (strcmp(att, "sym") == 0)
+ ax[cnt].type = TRACEFS_HIST_KEY_SYM;
+ else if (strcmp(att, "sym_offset") == 0)
+ ax[cnt].type = TRACEFS_HIST_KEY_SYM_OFFSET;
+ else if (strcmp(att, "syscall") == 0)
+ ax[cnt].type = TRACEFS_HIST_KEY_SYSCALL;
+ else if (strcmp(att, "exec") == 0)
+ ax[cnt].type = TRACEFS_HIST_KEY_EXECNAME;
+ else if (strcmp(att, "log") == 0)
+ ax[cnt].type = TRACEFS_HIST_KEY_LOG;
+ else if (strcmp(att, "usecs") == 0)
+ ax[cnt].type = TRACEFS_HIST_KEY_USECS;
+ else {
+ fprintf(stderr, "Undefined attribute '%s'\n", att);
+ fprintf(stderr," Acceptable attributes:\n");
+ fprintf(stderr," hex, sym, sym_offset, syscall, exe, log, usecs\n");
+ exit(-1);
+ }
+ }
+ cnt++;
+ }
+ return cnt;
+}
+
+static void process_hist(enum commands cmd, const char *instance_name,
+ char *group, char *keys, char *vals, char *sort,
+ char *ascend, char *desc)
+{
+ struct tracefs_instance *instance = NULL;
+ struct tracefs_hist *hist;
+ struct tep_handle *tep;
+ struct tracefs_hist_axis *axes = NULL;
+ char *system;
+ char *event;
+ char *sav;
+ char *val;
+ int ret;
+ int cnt;
+
+ if (instance_name) {
+ instance = tracefs_instance_create(instance_name);
+ if (!instance) {
+ fprintf(stderr, "Failed instance create\n");
+ exit(-1);
+ }
+ }
+
+ tep = tracefs_local_events(NULL);
+ if (!tep) {
+ perror("Could not read events");
+ exit(-1);
+ }
+
+ parse_system_event(group, &system, &event);
+
+ if (cmd == SHOW) {
+ char *content;
+ content = tracefs_event_file_read(instance, system, event,
+ "hist", NULL);
+ if (!content) {
+ perror("Reading hist file");
+ exit(-1);
+ }
+ printf("%s\n", content);
+ free(content);
+ return;
+ }
+
+ if (!keys) {
+ fprintf(stderr, "Command needs -k option\n");
+ exit(-1);
+ }
+
+ cnt = parse_keys(keys, &axes);
+ if (!cnt) {
+ fprintf(stderr, "No keys??\n");
+ exit(-1);
+ }
+
+ /* Show examples of hist1d and hist2d */
+ switch (cnt) {
+ case 1:
+ hist = tracefs_hist_alloc(tep, system, event,
+ axes[0].key, axes[0].type);
+ break;
+ case 2:
+ hist = tracefs_hist_alloc_2d(tep, system, event,
+ axes[0].key, axes[0].type,
+ axes[1].key, axes[1].type);
+ break;
+ default:
+ /* Really, 1 and 2 could use this too */
+ hist = tracefs_hist_alloc_nd(tep, system, event, axes);
+ }
+ if (!hist) {
+ fprintf(stderr, "Failed hist create\n");
+ exit(-1);
+ }
+
+ if (vals) {
+ sav = NULL;
+ for (val = strtok_r(vals, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) {
+ ret = tracefs_hist_add_value(hist, val);
+ if (ret) {
+ fprintf(stderr, "Failed to add value %s\n", val);
+ exit(-1);
+ }
+ }
+ }
+
+ if (sort) {
+ sav = NULL;
+ for (val = strtok_r(sort, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) {
+ ret = tracefs_hist_add_sort_key(hist, val);
+ if (ret) {
+ fprintf(stderr, "Failed to add sort key/val %s\n", val);
+ exit(-1);
+ }
+ }
+ }
+
+ if (ascend) {
+ sav = NULL;
+ for (val = strtok_r(ascend, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) {
+ ret = tracefs_hist_sort_key_direction(hist, val, TRACEFS_HIST_SORT_ASCENDING);
+ if (ret) {
+ fprintf(stderr, "Failed to add ascending key/val %s\n", val);
+ exit(-1);
+ }
+ }
+ }
+
+ if (desc) {
+ sav = NULL;
+ for (val = strtok_r(desc, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) {
+ ret = tracefs_hist_sort_key_direction(hist, val, TRACEFS_HIST_SORT_DESCENDING);
+ if (ret) {
+ fprintf(stderr, "Failed to add descending key/val %s\n", val);
+ exit(-1);
+ }
+ }
+ }
+
+ tracefs_error_clear(instance);
+
+ switch (cmd) {
+ case START:
+ ret = tracefs_hist_start(instance, hist);
+ if (ret) {
+ char *err = tracefs_error_last(instance);
+ if (err)
+ fprintf(stderr, "\n%s\n", err);
+ }
+ break;
+ case PAUSE:
+ ret = tracefs_hist_pause(instance, hist);
+ break;
+ case CONT:
+ ret = tracefs_hist_continue(instance, hist);
+ break;
+ case RESET:
+ ret = tracefs_hist_reset(instance, hist);
+ break;
+ case DELETE:
+ ret = tracefs_hist_destroy(instance, hist);
+ break;
+ case SHOW:
+ /* Show was already done */
+ break;
+ }
+ if (ret)
+ fprintf(stderr, "Failed: command\n");
+ exit(ret);
+}
+
+int main (int argc, char **argv, char **env)
+{
+ enum commands cmd;
+ char *instance = NULL;
+ char *cmd_str;
+ char *event = NULL;
+ char *keys = NULL;
+ char *vals = NULL;
+ char *sort = NULL;
+ char *desc = NULL;
+ char *ascend = NULL;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s command [-B instance][-e [system/]event][-k keys][-v vals][-s sort]\n", argv[0]);
+ fprintf(stderr, " [-a ascending][-d descending]\n");
+ exit(-1);
+ }
+
+ cmd_str = argv[1];
+
+ if (!strcmp(cmd_str, "start"))
+ cmd = START;
+ else if (!strcmp(cmd_str, "pause"))
+ cmd = PAUSE;
+ else if (!strcmp(cmd_str, "cont"))
+ cmd = CONT;
+ else if (!strcmp(cmd_str, "reset"))
+ cmd = RESET;
+ else if (!strcmp(cmd_str, "delete"))
+ cmd = DELETE;
+ else if (!strcmp(cmd_str, "show"))
+ cmd = SHOW;
+ else {
+ fprintf(stderr, "Unknown command %s\n", cmd_str);
+ exit(-1);
+ }
+
+ for (;;) {
+ int c;
+
+ c = getopt(argc - 1, argv + 1, "e:k:v:B:s:d:a:");
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'e':
+ event = optarg;
+ break;
+ case 'k':
+ keys = optarg;
+ break;
+ case 'v':
+ vals = optarg;
+ break;
+ case 'B':
+ instance = optarg;
+ break;
+ case 's':
+ sort = optarg;
+ break;
+ case 'd':
+ desc = optarg;
+ break;
+ case 'a':
+ ascend = optarg;
+ break;
+ }
+ }
+ if (!event) {
+ event = "kmem/kmalloc";
+ if (!keys)
+ keys = "call_site.sym,bytes_req";
+ if (!vals)
+ vals = "bytes_alloc";
+ if (!sort)
+ sort = "bytes_req,bytes_alloc";
+ if (!desc)
+ desc = "bytes_alloc";
+ }
+ process_hist(cmd, instance, event, keys, vals, sort, ascend, desc);
+}
+--
+
+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_pause*(3),
+*tracefs_hist_continue*(3),
+*tracefs_hist_reset*(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).
diff --git a/Documentation/libtracefs-hist.txt b/Documentation/libtracefs-hist.txt
new file mode 100644
index 0000000..7503fd0
--- /dev/null
+++ b/Documentation/libtracefs-hist.txt
@@ -0,0 +1,531 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_hist_alloc, tracefs_hist_alloc_2d, tracefs_hist_alloc_nd, tracefs_hist_alloc_nd_cnt, tracefs_hist_free,
+tracefs_hist_add_key, tracefs_hist_add_key_cnt, tracefs_hist_add_value - Create and destroy event histograms
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+enum *tracefs_hist_key_type* {
+ *TRACEFS_HIST_KEY_NORMAL* = 0,
+ *TRACEFS_HIST_KEY_HEX*,
+ *TRACEFS_HIST_KEY_SYM*,
+ *TRACEFS_HIST_KEY_SYM_OFFSET*,
+ *TRACEFS_HIST_KEY_SYSCALL*,
+ *TRACEFS_HIST_KEY_EXECNAME*,
+ *TRACEFS_HIST_KEY_LOG*,
+ *TRACEFS_HIST_KEY_USECS*,
+ *TRACEFS_HIST_KEY_MAX*
+};
+
+struct *tracefs_hist_axis* {
+ const char pass:[*]_key_;
+ enum tracefs_hist_key_type _type_;
+};
+
+struct tracefs_hist pass:[*]*tracefs_hist_alloc*(struct tracefs_tep pass:[*] _tep_,
+ const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_key_, enum tracefs_hist_key_type _type_);
+struct tracefs_hist pass:[*]*tracefs_hist_alloc_2d*(struct tracefs_tep pass:[*] _tep_,
+ const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_key1_, enum tracefs_hist_key_type _type1_,
+ const char pass:[*]_key2_, enum tracefs_hist_key_type _type2_));
+struct tracefs_hist pass:[*]*tracefs_hist_alloc_nd*(struct tracefs_tep pass:[*] _tep_,
+ const char pass:[*]_system_, const char pass:[*]_event_,
+ struct tracefs_hist_axis pass:[*]_axes_);
+struct tracefs_hist pass:[*]*tracefs_hist_alloc_nd_cnt*(struct tep_handle pass:[*]_tep_,
+ const char pass:[*]_system_, const char pass:[*]_event_name_,
+ struct tracefs_hist_axis_cnt pass:[*]_axes_);
+void *tracefs_hist_free*(struct tracefs_hist pass:[*]_hist_);
+
+int *tracefs_hist_add_key*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_key_,
+ enum tracefs_hist_key_type _type_);
+int *tracefs_hist_add_key_cnt*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_key_,
+ enum tracefs_hist_key_type _type_, int _cnt_);
+int *tracefs_hist_add_value*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_value_);
+--
+
+DESCRIPTION
+-----------
+Event histograms are created by the trigger file in the event directory.
+The syntax can be complex and difficult to get correct. This API handles the
+syntax, and facilitates the creation and interaction with the event histograms.
+See https://www.kernel.org/doc/html/latest/trace/histogram.html for more information.
+
+*tracefs_hist_alloc*() allocates a "struct tracefs_hist" descriptor of a one-dimensional
+histogram and returns the address of it. This descriptor must be freed by *tracefs_hist_free*().
+The _tep_ is a trace event handle (see *tracefs_local_events*(3)), that holds the
+_system_ and _event_ that the histogram will be attached to. The _system_ is the
+system or group of the event. The _event_ is the event to attach the histogram to.
+The _key_ is a field of the event that will be used as the key(dimension) of the histogram.
+The _type_ is the type of the _key_. See KEY TYPES below.
+
+*tracefs_hist_alloc_2d*() allocates a "struct tracefs_hist" descriptor of a two-dimensional
+histogram and returns the address of it. This descriptor must be freed by *tracefs_hist_free*().
+The _tep_ is a trace event handle (see *tracefs_local_events*(3)), that holds the
+_system_ and _event_ that the histogram will be attached to. The _system_ is the
+system or group of the event. The _event_ is the event to attach the histogram to.
+The _key1_ is the first field of the event that will be used as the key(dimension)
+of the histogram. The _type1_ is the type of the _key1_. See KEY TYPES below.
+The _key2_ is the second field of the event that will be used as the key(dimension)
+of the histogram. The _type2_ is the type of the _key2_. See KEY TYPES below.
+
+*tracefs_hist_alloc_nd*() allocates a "struct tracefs_hist" descriptor of an N-dimensional
+histogram and returns the address of it. This descriptor must be freed by *tracefs_hist_free*().
+The _tep_ is a trace event handle (see *tracefs_local_events*(3)), that holds the
+_system_ and _event_ that the histogram will be attached to. The _system_ is the
+system or group of the event. The _event_ is the event to attach the histogram to.
+The _axes_ is an array of _key_ / _type_ pairs, defining the dimensions of the histogram.
+
+*tracefs_hist_alloc_nd_cnt*() will initialize a histogram descriptor that will be attached to
+the _system_/_event_. This only initializes the descriptor with the given _axes_ keys as primaries.
+This only initializes the descriptor, it does not start the histogram in the kernel.
+The difference between this and *tracefs_hist_alloc_nd()* is that the _axes_ parameter
+is of type *struct tracefs_hist_axis_cnt* and not *struct tracefs_hist_axis*.
+
+*tracefs_hist_free*() frees the _tracefs_hist_ descriptor. Note, it does not stop
+or disable the running histogram if it was started. *tracefs_hist_destroy*() needs
+to be called to do so.
+
+*tracefs_hist_add_key*() Adds a secondary or tertiary key to the histogram.
+The key passed to *tracefs_hist_alloc_nd*() is the primary key of the histogram.
+The first time this function is called, it will add a secondary key (or two dimensional
+histogram). If this function is called again on the same histogram, it will add
+a _tertiary_ key (or three dimensional histogram). The _hist_ parameter is the
+histogram descriptor to add the _key_ to. The _type_ is the type of key to add
+(See KEY TYPES below).
+
+The *tracefs_hist_add_key_cnt*() is the same as *tracefs_hist_add_key*() except
+that it allows to add a counter for the given type. Currently, there's only
+the *buckets* type that requires a counter. When adding a key with the buckets
+type, *tracefs_hist_add_key*() is not sufficient, as the *buckets* type requires
+a counter or bucket size. Use *tracefs_hist_add_key_cnt*() when specifing
+a key that is broken up into buckets, and pass in the size of those buckets
+into _cnt_.
+
+*tracefs_hist_add_value*() will add a value to record. By default, the value is
+simply the "hitcount" of the number of times a instance of the histogram's
+key was hit. The _hist_ is the histogram descriptor to add the value to.
+The _value_ is a field in the histogram to add to when an instance of the
+key is hit.
+
+KEY TYPES
+---------
+
+*tracefs_hist_alloc_nd*() and *tracefs_hist_add_key*() both add a key and requires
+that key to have a type. The types may be:
+
+*TRACEFS_HIST_KEY_NORMAL* or zero (0) which is to not modify the type.
+
+*TRACEFS_HIST_KEY_HEX* to display the key in hex.
+
+*TRACEFS_HIST_KEY_SYM* to display the key as a kernel symbol (if found). If
+the key is an address, this is useful as it will display the function names instead
+of just a number.
+
+*TRACEFS_HIST_KEY_SYM_OFFSET* similar to *TRACEFS_HIST_KEY_SYM* but will also include
+the offset of the function to match the exact address.
+
+*TRACEFS_HIST_KEY_SYSCALL* If the key is a system call "id" (the number passed from user
+space to the kernel to tell it what system call it is calling), then the name of
+the system call is displayed.
+
+*TRACEFS_HIST_KEY_EXECNAME* If "common_pid" is the key (the pid of the executing task),
+instead of showing the number, show the name of the running task.
+
+*TRACEFS_HIST_KEY_LOG* will display the key in a binary logarithmic scale.
+
+*TRACEFS_HIST_KEY_USECS* for use with "common_timestamp" or TRACEFS_HIST_TIMESTAMP,
+in which case it will show the timestamp in microseconds instead of nanoseconds.
+
+RETURN VALUE
+------------
+*tracefs_hist_alloc_nd*() returns an allocated histogram descriptor which must
+be freed by *tracefs_hist_free*() or NULL on error.
+
+All the other functions return zero on success or -1 on error.
+
+If *tracefs_hist_start*() returns an error, a message may be displayed
+in the kernel that can be retrieved by *tracefs_error_last()*.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <tracefs.h>
+
+enum commands {
+ START,
+ PAUSE,
+ CONT,
+ RESET,
+ DELETE,
+ SHOW,
+};
+
+static void parse_system_event(char *group, char **system, char **event)
+{
+ *system = strtok(group, "/");
+ *event = strtok(NULL, "/");
+ if (!*event) {
+ *event = *system;
+ *system = NULL;
+ }
+}
+
+static int parse_keys(char *keys, struct tracefs_hist_axis_cnt **axes)
+{
+ char *sav = NULL;
+ char *key;
+ int cnt = 0;
+
+ for (key = strtok_r(keys, ",", &sav); key; key = strtok_r(NULL, ",", &sav)) {
+ struct tracefs_hist_axis_cnt *ax;
+ char *att;
+
+ ax = realloc(*axes, sizeof(*ax) * (cnt + 2));
+ if (!ax) {
+ perror("Failed to allocate axes");
+ exit(-1);
+ }
+ ax[cnt].key = key;
+ ax[cnt].type = 0;
+ ax[cnt + 1].key = NULL;
+ ax[cnt + 1].type = 0;
+
+ *axes = ax;
+
+ att = strchr(key, '.');
+ if (att) {
+ *att++ = '\0';
+ if (strcmp(att, "hex") == 0)
+ ax[cnt].type = TRACEFS_HIST_KEY_HEX;
+ else if (strcmp(att, "sym") == 0)
+ ax[cnt].type = TRACEFS_HIST_KEY_SYM;
+ else if (strcmp(att, "sym_offset") == 0)
+ ax[cnt].type = TRACEFS_HIST_KEY_SYM_OFFSET;
+ else if (strcmp(att, "syscall") == 0)
+ ax[cnt].type = TRACEFS_HIST_KEY_SYSCALL;
+ else if (strcmp(att, "exec") == 0)
+ ax[cnt].type = TRACEFS_HIST_KEY_EXECNAME;
+ else if (strcmp(att, "log") == 0)
+ ax[cnt].type = TRACEFS_HIST_KEY_LOG;
+ else if (strcmp(att, "usecs") == 0)
+ ax[cnt].type = TRACEFS_HIST_KEY_USECS;
+ else if (strncmp(att, "buckets", 7) == 0) {
+ if (att[7] != '=' && !isdigit(att[8])) {
+ fprintf(stderr, "'buckets' key type requires '=<size>'\n");
+ exit(-1);
+ }
+ ax[cnt].type = TRACEFS_HIST_KEY_BUCKETS;
+ ax[cnt].cnt = atoi(&att[8]);
+ } else {
+ fprintf(stderr, "Undefined attribute '%s'\n", att);
+ fprintf(stderr," Acceptable attributes:\n");
+ fprintf(stderr," hex, sym, sym_offset, syscall, exe, log, usecs\n");
+ exit(-1);
+ }
+ }
+ cnt++;
+ }
+ return cnt;
+}
+
+static void process_hist(enum commands cmd, const char *instance_name,
+ char *group, char *keys, char *vals, char *sort,
+ char *ascend, char *desc)
+{
+ struct tracefs_instance *instance = NULL;
+ struct tracefs_hist *hist;
+ struct tep_handle *tep;
+ struct tracefs_hist_axis_cnt *axes = NULL;
+ char *system;
+ char *event;
+ char *sav;
+ char *val;
+ int ret;
+ int cnt;
+
+ if (instance_name) {
+ instance = tracefs_instance_create(instance_name);
+ if (!instance) {
+ fprintf(stderr, "Failed instance create\n");
+ exit(-1);
+ }
+ }
+
+ tep = tracefs_local_events(NULL);
+ if (!tep) {
+ perror("Could not read events");
+ exit(-1);
+ }
+
+ parse_system_event(group, &system, &event);
+
+ if (cmd == SHOW) {
+ char *content;
+ content = tracefs_event_file_read(instance, system, event,
+ "hist", NULL);
+ if (!content) {
+ perror("Reading hist file");
+ exit(-1);
+ }
+ printf("%s\n", content);
+ free(content);
+ return;
+ }
+
+ if (!keys) {
+ fprintf(stderr, "Command needs -k option\n");
+ exit(-1);
+ }
+
+ cnt = parse_keys(keys, &axes);
+ if (!cnt) {
+ fprintf(stderr, "No keys??\n");
+ exit(-1);
+ }
+
+ /* buckets require the nd_cnt function */
+ switch (cnt) {
+ case 2:
+ if (axes[1].type == TRACEFS_HIST_KEY_BUCKETS)
+ cnt = -1;
+ /* fall through */
+ case 1:
+ if (axes[0].type == TRACEFS_HIST_KEY_BUCKETS)
+ cnt = -1;
+ }
+
+ /* Show examples of hist1d and hist2d */
+ switch (cnt) {
+ case 1:
+ hist = tracefs_hist_alloc(tep, system, event,
+ axes[0].key, axes[0].type);
+ break;
+ case 2:
+ hist = tracefs_hist_alloc_2d(tep, system, event,
+ axes[0].key, axes[0].type,
+ axes[1].key, axes[1].type);
+ break;
+ default:
+ /* Really, 1 and 2 could use this too */
+ hist = tracefs_hist_alloc_nd_cnt(tep, system, event, axes);
+ }
+ if (!hist) {
+ fprintf(stderr, "Failed hist create\n");
+ exit(-1);
+ }
+
+ if (vals) {
+ sav = NULL;
+ for (val = strtok_r(vals, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) {
+ ret = tracefs_hist_add_value(hist, val);
+ if (ret) {
+ fprintf(stderr, "Failed to add value %s\n", val);
+ exit(-1);
+ }
+ }
+ }
+
+ if (sort) {
+ sav = NULL;
+ for (val = strtok_r(sort, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) {
+ ret = tracefs_hist_add_sort_key(hist, val);
+ if (ret) {
+ fprintf(stderr, "Failed to add sort key/val %s\n", val);
+ exit(-1);
+ }
+ }
+ }
+
+ if (ascend) {
+ sav = NULL;
+ for (val = strtok_r(ascend, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) {
+ ret = tracefs_hist_sort_key_direction(hist, val, TRACEFS_HIST_SORT_ASCENDING);
+ if (ret) {
+ fprintf(stderr, "Failed to add ascending key/val %s\n", val);
+ exit(-1);
+ }
+ }
+ }
+
+ if (desc) {
+ sav = NULL;
+ for (val = strtok_r(desc, ",", &sav); val; val = strtok_r(NULL, ",", &sav)) {
+ ret = tracefs_hist_sort_key_direction(hist, val, TRACEFS_HIST_SORT_DESCENDING);
+ if (ret) {
+ fprintf(stderr, "Failed to add descending key/val %s\n", val);
+ exit(-1);
+ }
+ }
+ }
+
+ tracefs_error_clear(instance);
+
+ switch (cmd) {
+ case START:
+ ret = tracefs_hist_start(instance, hist);
+ if (ret) {
+ char *err = tracefs_error_last(instance);
+ if (err)
+ fprintf(stderr, "\n%s\n", err);
+ }
+ break;
+ case PAUSE:
+ ret = tracefs_hist_pause(instance, hist);
+ break;
+ case CONT:
+ ret = tracefs_hist_continue(instance, hist);
+ break;
+ case RESET:
+ ret = tracefs_hist_reset(instance, hist);
+ break;
+ case DELETE:
+ ret = tracefs_hist_destroy(instance, hist);
+ break;
+ case SHOW:
+ /* Show was already done */
+ break;
+ }
+ if (ret)
+ fprintf(stderr, "Failed: command\n");
+ exit(ret);
+}
+
+int main (int argc, char **argv, char **env)
+{
+ enum commands cmd;
+ char *instance = NULL;
+ char *cmd_str;
+ char *event = NULL;
+ char *keys = NULL;
+ char *vals = NULL;
+ char *sort = NULL;
+ char *desc = NULL;
+ char *ascend = NULL;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s command [-B instance][-e [system/]event][-k keys][-v vals][-s sort]\n", argv[0]);
+ fprintf(stderr, " [-a ascending][-d descending]\n");
+ exit(-1);
+ }
+
+ cmd_str = argv[1];
+
+ if (!strcmp(cmd_str, "start"))
+ cmd = START;
+ else if (!strcmp(cmd_str, "pause"))
+ cmd = PAUSE;
+ else if (!strcmp(cmd_str, "cont"))
+ cmd = CONT;
+ else if (!strcmp(cmd_str, "reset"))
+ cmd = RESET;
+ else if (!strcmp(cmd_str, "delete"))
+ cmd = DELETE;
+ else if (!strcmp(cmd_str, "show"))
+ cmd = SHOW;
+ else {
+ fprintf(stderr, "Unknown command %s\n", cmd_str);
+ exit(-1);
+ }
+
+ for (;;) {
+ int c;
+
+ c = getopt(argc - 1, argv + 1, "e:k:v:B:s:d:a:");
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'e':
+ event = optarg;
+ break;
+ case 'k':
+ keys = optarg;
+ break;
+ case 'v':
+ vals = optarg;
+ break;
+ case 'B':
+ instance = optarg;
+ break;
+ case 's':
+ sort = optarg;
+ break;
+ case 'd':
+ desc = optarg;
+ break;
+ case 'a':
+ ascend = optarg;
+ break;
+ }
+ }
+ if (!event) {
+ event = "kmem/kmalloc";
+ if (!keys)
+ keys = "call_site.sym,bytes_req";
+ if (!vals)
+ vals = "bytes_alloc";
+ if (!sort)
+ sort = "bytes_req,bytes_alloc";
+ if (!desc)
+ desc = "bytes_alloc";
+ }
+ process_hist(cmd, instance, event, keys, vals, sort, ascend, desc);
+}
+
+--
+
+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_pause*(3),
+*tracefs_hist_continue*(3),
+*tracefs_hist_reset*(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).
diff --git a/Documentation/libtracefs-instances-affinity.txt b/Documentation/libtracefs-instances-affinity.txt
new file mode 100644
index 0000000..39dd44c
--- /dev/null
+++ b/Documentation/libtracefs-instances-affinity.txt
@@ -0,0 +1,200 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_instance_set_affinity, tracefs_instance_set_affinity_set, tracefs_instance_set_affinity_raw,
+tracefs_instance_get_affinity, tracefs_instance_get_affinity_set, tracefs_instance_get_affinity_raw
+- Sets or retrieves the affinity for an instance or top level for what CPUs enable tracing.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+int *tracefs_instance_set_affinity*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_cpu_str_);
+int *tracefs_instance_set_affinity_set*(struct tracefs_instance pass:[*]_instance_, cpu_set_t pass:[*]_set_, size_t _set_size_);
+int *tracefs_instance_set_affinity_raw*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_mask_);
+
+char pass:[*]*tracefs_instance_get_affinity*(struct tracefs_instance pass:[*]_instance_);
+int *tracefs_instance_get_affinity_set*(struct tracefs_instance pass:[*]_instance_, cpu_set_t pass:[*]_set_, size_t _set_size_);
+char pass:[*]*tracefs_instance_get_affinity_raw*(struct tracefs_instance pass:[*]_instance_);
+--
+
+DESCRIPTION
+-----------
+These functions set or retrieve the CPU affinity that limits what CPUs will have tracing enabled
+for a given instance defined by the _instance_ parameter. If _instance_ is NULL, then
+the top level instance is affected.
+
+The *tracefs_instance_set_affinity()* function takes a string _cpu_str_ that is a
+list of CPUs to set the affinity for. If _cpu_str_ is NULL, then all the CPUs in
+the system will be set. The format of _cpu_str_ is a comma delimited string of
+decimal numbers with no spaces. A range may be specified by a hyphen.
+
+For example: "1,4,6-8"
+
+The numbers do not need to be in order except for ranges, where the second number
+must be equal to or greater than the first.
+
+The *tracefs_instance_set_affinity_set()* function takes a CPU set defined by
+*CPU_SET*(3). The size of the set defined by _set_size_ is the size in bytes of
+_set_. If _set_ is NULL then all the CPUs on the system will be set, and _set_size_
+is ignored.
+
+The *tracefs_instance_set_affinity_raw()* function takes a string that holds
+a hexidecimal bitmask, where each 32 bits is separated by a comma. For a
+machine with more that 32 CPUs, to set CPUS 1-10 and CPU 40:
+
+ "100,000007fe"
+
+Where the above is a hex representation of bits 1-10 and bit 40 being set.
+
+The *tracefs_instance_get_affinity()* will retrieve the affinity in a human readable
+form.
+
+For example: "1,4,6-8"
+
+The string returned must be freed with *free*(3).
+
+The *tracefs_instance_get_affinity_set()* will set all the bits in the passed in
+cpu set (from *CPU_SET*(3)). Note it will not clear any bits that are already set
+in the set but the CPUs are not. If only the bits for the CPUs that are enabled
+should be set, a CPU_ZERO_S() should be performed on the set before calling this
+function.
+
+The *tracefs_instance_get_affinity_raw()* will simply read the instance tracing_cpumask
+and return that string. The returned string must be freed with *free*(3).
+
+RETURN VALUE
+------------
+All the set functions return 0 on success and -1 on error.
+
+The functions *tracefs_instance_get_affinity()* and *tracefs_instance_get_affinity_raw()*
+returns an allocated string that must be freed with *free*(3), or NULL on error.
+
+The function *tracefs_instance_get_affinity_set()* returns the number of CPUs that
+were found set, or -1 on error.
+
+
+ERRORS
+------
+The following errors are for all the above calls:
+
+*EFBIG* if a CPU is set that is greater than what is in the system.
+
+*EINVAL* One of the parameters was invalid.
+
+The following errors are for *tracefs_instance_set_affinity*() and *tracefs_instance_set_affinity_set*():
+
+*ENOMEM* Memory allocation error.
+
+*ENODEV* dynamic events of requested type are not configured for the running kernel.
+
+The following errors are just for *tracefs_instance_set_affinity*()
+
+*EACCES* The _cpu_str_ was modified by another thread when processing it.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <tracefs.h>
+
+int main (int argc, char **argv)
+{
+ struct trace_seq seq;
+ cpu_set_t *set;
+ size_t set_size;
+ char *c;
+ int cpu1;
+ int cpu2;
+ int i;
+
+ c = tracefs_instance_get_affinity(NULL);
+ printf("The affinity was %s\n", c);
+ free(c);
+
+ if (argc < 2) {
+ tracefs_instance_set_affinity(NULL, NULL);
+ exit(0);
+ }
+ /* Show example using a set */
+ if (argc == 2 && !strchr(argv[1],',')) {
+ cpu1 = atoi(argv[1]);
+ c = strchr(argv[1], '-');
+ if (c++)
+ cpu2 = atoi(c);
+ else
+ cpu2 = cpu1;
+ if (cpu2 < cpu1) {
+ fprintf(stderr, "Invalid CPU range\n");
+ exit(-1);
+ }
+ set = CPU_ALLOC(cpu2 + 1);
+ set_size = CPU_ALLOC_SIZE(cpu2 + 1);
+ CPU_ZERO_S(set_size, set);
+ for ( ; cpu1 <= cpu2; cpu1++)
+ CPU_SET(cpu1, set);
+ tracefs_instance_set_affinity_set(NULL, set, set_size);
+ CPU_FREE(set);
+ exit(0);
+ }
+
+ trace_seq_init(&seq);
+ for (i = 1; i < argc; i++) {
+ if (i > 1)
+ trace_seq_putc(&seq, ',');
+ trace_seq_puts(&seq, argv[i]);
+ }
+ trace_seq_terminate(&seq);
+ tracefs_instance_set_affinity(NULL, seq.buffer);
+ trace_seq_destroy(&seq);
+ exit(0);
+
+ return 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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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).
diff --git a/Documentation/libtracefs-instances-file-manip.txt b/Documentation/libtracefs-instances-file-manip.txt
new file mode 100644
index 0000000..8c04240
--- /dev/null
+++ b/Documentation/libtracefs-instances-file-manip.txt
@@ -0,0 +1,199 @@
+libtracefs(3)
+=============
+
+NAME
+----
+
+tracefs_instance_file_open,
+tracefs_instance_file_write, tracefs_instance_file_append, tracefs_instance_file_clear,
+tracefs_instance_file_read, tracefs_instance_file_read_number - Work with files in tracing instances.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+int *tracefs_instance_file_open*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_file_, int _mode_);
+int *tracefs_instance_file_write*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_file_, const char pass:[*]_str_);
+int *tracefs_instance_file_append*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_file_, const char pass:[*]_str_);
+int *tracefs_instance_file_clear*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_file_);
+char pass:[*]*tracefs_instance_file_read*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_file_, int pass:[*]_psize_);
+int *tracefs_instance_file_read_number*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_file_, long long int pass:[*]_res_);
+
+--
+
+DESCRIPTION
+-----------
+This set of APIs can be used to work with trace files in all trace instances.
+Each of these APIs take an _instance_ argument, that can be NULL to act
+on the top level instance. Otherwise, it acts on an instance created with
+*tracefs_insance_create*(3)
+
+The *tracefs_instance_file_open()* function opens trace _file_ from given _instance_ and returns
+a file descriptor to it. The file access _mode_ can be specified, see *open*(3) for more details.
+If -1 is passed as _mode_, default O_RDWR is used.
+
+The *tracefs_instance_file_write()* function writes a string _str_ in a _file_ from
+the given _instance_, without the terminating NULL character. When opening the file, this function
+tries to truncates the size of the file to zero, which clears all previously existing settings.
+
+The *tracefs_instance_file_append()* function writes a string _str_ in a _file_ from
+the given _instance_, without the terminating NULL character. This function is similar to
+*tracefs_instance_file_write()*, but the existing content of the is not cleared. Thus the
+new settings are appended to the existing ones (if any).
+
+The *tracefs_instance_file_clear()* function tries to truncates the size of the file to zero,
+which clears all previously existing settings. If the file has content that does not get
+cleared in this way, this will not have any effect.
+
+The *tracefs_instance_file_read()* function reads the content of a _file_ from
+the given _instance_.
+
+The *tracefs_instance_file_read_number()* function reads the content of a _file_ from
+the given _instance_ and converts it to a long long integer, which is stored in _res_.
+
+RETURN VALUE
+------------
+The *tracefs_instance_file_open()* function returns a file descriptor to the opened file. It must be
+closed with *close*(3). In case of an error, -1 is returned.
+
+The *tracefs_instance_file_write()* function returns the number of written bytes,
+or -1 in case of an error.
+
+The *tracefs_instance_file_append()* function returns the number of written bytes,
+or -1 in case of an error.
+
+The *tracefs_instance_file_clear()* function returns 0 on success, or -1 in case of an error.
+
+The *tracefs_instance_file_read()* function returns a pointer to a NULL terminated
+string, read from the file, or NULL in case of an error. The returned string must
+be freed with free().
+
+The *tracefs_instance_file_read_number()* function returns 0 if a valid integer is read from
+the file and stored in _res_ or -1 in case of an error.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <tracefs.h>
+
+struct tracefs_instance *inst = tracefs_instance_create("foo");
+ if (!inst) {
+ /* Error creating a new trace instance */
+ ...
+ }
+
+ if (tracefs_file_exists(inst,"trace_clock")) {
+ /* The instance foo supports trace clock */
+ char *path, *clock;
+ int size;
+
+ path = = tracefs_instance_get_file(inst, "trace_clock")
+ if (!path) {
+ /* Error getting the path to trace_clock file in instance foo */
+ ...
+ }
+ ...
+ tracefs_put_tracing_file(path);
+
+ clock = tracefs_instance_file_read(inst, "trace_clock", &size);
+ if (!clock) {
+ /* Failed to read trace_clock file in instance foo */
+ ...
+ }
+ ...
+ free(clock);
+
+ if (tracefs_instance_file_write(inst, "trace_clock", "global") != strlen("global")) {
+ /* Failed to set gloabl trace clock in instance foo */
+ ...
+ }
+ } else {
+ /* The instance foo does not support trace clock */
+ }
+
+ if (tracefs_dir_exists(inst,"options")) {
+ /* The instance foo supports trace options */
+ char *path = tracefs_instance_get_file(inst, "options");
+ if (!path) {
+ /* Error getting the path to options directory in instance foo */
+ ...
+ }
+
+ tracefs_put_tracing_file(path);
+ } else {
+ /* The instance foo does not support trace options */
+ }
+
+ ...
+
+ if (tracefs_instance_is_new(inst))
+ tracefs_instance_destroy(inst);
+ else
+ tracefs_instance_free(inst);
+ ...
+
+ long long int res;
+ if (tracefs_instance_file_read_number(NULL, "tracing_on", &res) == 0) {
+ if (res == 0) {
+ /* tracing is disabled in the top instance */
+ } else if (res == 1) {
+ /* tracing is enabled in the top instance */
+ } else {
+ /* Unknown tracing state of the top instance */
+ }
+ } else {
+ /* Failed to read integer from tracing_on file */
+ }
+
+ ...
+
+ int fd;
+ fd = tracefs_instance_file_open(NULL, "tracing_on", O_WRONLY);
+ if (fd >= 0) {
+ /* Got file descriptor to the tracing_on file from the top instance for writing */
+ ...
+ close(fd);
+ }
+--
+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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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).
diff --git a/Documentation/libtracefs-instances-files.txt b/Documentation/libtracefs-instances-files.txt
new file mode 100644
index 0000000..e298557
--- /dev/null
+++ b/Documentation/libtracefs-instances-files.txt
@@ -0,0 +1,173 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_file_exists, tracefs_dir_exists,
+tracefs_instance_get_file, tracefs_instance_get_dir - Work with files directories in tracing instances.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+bool *tracefs_file_exists*(struct tracefs_instance pass:[*]_instance_, char pass:[*]_name_);
+bool *tracefs_dir_exists*(struct tracefs_instance pass:[*]_instance_, char pass:[*]_name_);
+char pass:[*]*tracefs_instance_get_file*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_file_);
+char pass:[*]*tracefs_instance_get_dir*(struct tracefs_instance pass:[*]_instance_);
+
+--
+
+DESCRIPTION
+-----------
+This set of APIs can be used to work with trace files in all trace instances.
+Each of these APIs take an _instance_ argument, that can be NULL to act
+on the top level instance. Otherwise, it acts on an instance created with
+*tracefs_insance_create*(3)
+
+The *tracefs_file_exists()* function checks if a file with _name_ exists in _instance_.
+
+The *tracefs_dir_exists()* function checks if a directory with _name_ exists in _instance_.
+
+The *tracefs_instance_get_file()* function returns the full path of the file
+with given _name_ in _instance_. Note, it does not check if the file exists in
+the instance.
+
+The *tracefs_instance_get_dir()* function returns the full path of the directory
+with given _name_ in _instance_. Note, it does not check if the directory exists
+in the instance.
+
+RETURN VALUE
+------------
+The *tracefs_file_exists()* and *tracefs_dir_exists()* functions return true if the
+file / directory exist in the given instance or false if it does not exist.
+
+The *tracefs_instance_get_file()* and *tracefs_instance_get_dir()* functions return
+a string or NULL in case of an error. The returned string must be freed with
+*tracefs_put_tracing_file()*.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <tracefs.h>
+
+struct tracefs_instance *inst = tracefs_instance_create("foo");
+ if (!inst) {
+ /* Error creating a new trace instance */
+ ...
+ }
+
+ if (tracefs_file_exists(inst,"trace_clock")) {
+ /* The instance foo supports trace clock */
+ char *path, *clock;
+ int size;
+
+ path = = tracefs_instance_get_file(inst, "trace_clock")
+ if (!path) {
+ /* Error getting the path to trace_clock file in instance foo */
+ ...
+ }
+ ...
+ tracefs_put_tracing_file(path);
+
+ clock = tracefs_instance_file_read(inst, "trace_clock", &size);
+ if (!clock) {
+ /* Failed to read trace_clock file in instance foo */
+ ...
+ }
+ ...
+ free(clock);
+
+ if (tracefs_instance_file_write(inst, "trace_clock", "global") != strlen("global")) {
+ /* Failed to set gloabl trace clock in instance foo */
+ ...
+ }
+ } else {
+ /* The instance foo does not support trace clock */
+ }
+
+ if (tracefs_dir_exists(inst,"options")) {
+ /* The instance foo supports trace options */
+ char *path = tracefs_instance_get_file(inst, "options");
+ if (!path) {
+ /* Error getting the path to options directory in instance foo */
+ ...
+ }
+
+ tracefs_put_tracing_file(path);
+ } else {
+ /* The instance foo does not support trace options */
+ }
+
+ ...
+
+ if (tracefs_instance_is_new(inst))
+ tracefs_instance_destroy(inst);
+ else
+ tracefs_instance_free(inst);
+ ...
+
+ long long int res;
+ if (tracefs_instance_file_read_number(NULL, "tracing_on", &res) == 0) {
+ if (res == 0) {
+ /* tracing is disabled in the top instance */
+ } else if (res == 1) {
+ /* tracing is enabled in the top instance */
+ } else {
+ /* Unknown tracing state of the top instance */
+ }
+ } else {
+ /* Failed to read integer from tracing_on file */
+ }
+
+ ...
+
+ int fd;
+ fd = tracefs_instance_file_open(NULL, "tracing_on", O_WRONLY);
+ if (fd >= 0) {
+ /* Got file descriptor to the tracing_on file from the top instance for writing */
+ ...
+ close(fd);
+ }
+--
+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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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).
diff --git a/Documentation/libtracefs-instances-manage.txt b/Documentation/libtracefs-instances-manage.txt
new file mode 100644
index 0000000..c03a272
--- /dev/null
+++ b/Documentation/libtracefs-instances-manage.txt
@@ -0,0 +1,150 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_instance_create, tracefs_instance_destroy, tracefs_instance_alloc, tracefs_instance_free,
+tracefs_instance_is_new, tracefs_instances - Manage trace instances.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+struct tracefs_instance pass:[*]*tracefs_instance_create*(const char pass:[*]_name_);
+int *tracefs_instance_destroy*(struct tracefs_instance pass:[*]_instance_);
+struct tracefs_instance pass:[*]*tracefs_instance_alloc*(const char pass:[*]_tracing_dir_, const char pass:[*]_name_);
+void *tracefs_instance_free*(struct tracefs_instance pass:[*]_instance_);
+bool *tracefs_instance_is_new*(struct tracefs_instance pass:[*]_instance_);
+char pass:[**]*tracefs_instances*(const char pass:[*]_regex_);
+
+--
+
+DESCRIPTION
+-----------
+This set of functions can be used to manage trace instances. A trace
+instance is a sub buffer used by the Linux tracing system. Given a unique
+name, the events enabled in an instance do not affect the main tracing
+system, nor other instances, as events enabled in the main tracing system
+or other instances do not affect the given instance.
+
+The *tracefs_instance_create()* function allocates and initializes a new
+tracefs_instance structure and returns it. If the instance with _name_ does
+not yet exist in the system, it will be created. The _name_ could be NULL,
+then the new tracefs_instance structure is initialized for the top instance.
+Note that the top instance cannot be created in the system, if it does not
+exist.
+
+The *tracefs_instance_destroy()* removes the instance from the system, but
+does not free the structure. *tracefs_instance_free()* must still be called
+on _instance_.
+
+The tracefs_instance_alloc()* function allocates a new tracefs_instance structure
+for existing trace instance. If the instance does not exist in the system, the function
+fails. The _tracing_dir_ parameter points to the system trace directory. It can be
+NULL, then default system trace directory is used. This parameter is useful to allocate
+instances to trace directories, copied from another machine. The _name_ is the name of
+the instance, or NULL for the top instance in the given _tracing_dir_.
+
+The *tracefs_instance_free()* function frees the tracefs_instance structure,
+without removing the trace instance from the system.
+
+The *tracefs_instance_is_new()* function checks if the given _instance_ is
+newly created by *tracefs_instance_create()*, or it has been in the system
+before that.
+
+The *tracefs_instances*() function returns a list of instances that exist in
+the system that match the regular expression _regex_. If _regex_ is NULL, then
+it will match all instances that exist. The returned list must be freed with
+*tracefs_list_free*(3). Note, if no instances are found an empty list is returned
+and that too needs to be free with *tracefs_list_free*(3).
+
+RETURN VALUE
+------------
+The *tracefs_instance_create()* and *tracefs_instance_alloc()* functions return a pointer to
+a newly allocated tracefs_instance structure. It must be freed with *tracefs_instance_free()*.
+
+The *tracefs_instance_destroy()* function returns 0 if it succeeds to remove
+the instance, otherwise it returns -1 if the instance does not exist or it
+fails to remove it.
+
+The *tracefs_instance_is_new()* function returns true if the
+*tracefs_instance_create()* that allocated _instance_ also created the
+trace instance in the system, or false if the trace instance already
+existed in the system when _instance_ was allocated by
+*tracefs_instance_create()* or *tracefs_instance_alloc()*.
+
+The *tracefs_instances()* returns a list of instance names that exist on the system.
+The list must be freed with *tracefs_list_free*(3). An empty list is returned if
+no instance exists that matches _regex_, and this needs to be freed with
+*tracefs_list_free*(3) as well. NULL is returned on error.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <tracefs.h>
+
+struct tracefs_instance *inst = tracefs_instance_create("foo");
+ if (!inst) {
+ /* Error creating a new trace instance */
+ ...
+ }
+
+ ...
+
+ if (tracefs_instance_is_new(inst))
+ tracefs_instance_destroy(inst);
+ tracefs_instance_free(inst);
+...
+
+struct tracefs_instance *inst = tracefs_instance_alloc(NULL, "bar");
+ if (!inst) {
+ /* Error allocating 'bar' trace instance */
+ ...
+ }
+
+ ...
+
+ tracefs_instance_free(inst);
+--
+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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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).
diff --git a/Documentation/libtracefs-instances-utils.txt b/Documentation/libtracefs-instances-utils.txt
new file mode 100644
index 0000000..bc8c9a7
--- /dev/null
+++ b/Documentation/libtracefs-instances-utils.txt
@@ -0,0 +1,141 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_instance_get_name, tracefs_instance_get_trace_dir, tracefs_instances_walk, tracefs_instance_exists,
+tracefs_instance_get_buffer_size, tracefs_instance_set_buffer_size - Helper functions for working with tracing instances.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+const char pass:[*]*tracefs_instance_get_name*(struct tracefs_instance pass:[*]_instance_);
+const char pass:[*]*tracefs_instance_get_trace_dir*(struct tracefs_instance pass:[*]_instance_);
+int *tracefs_instances_walk*(int (pass:[*]_callback_)(const char pass:[*], void pass:[*]), void pass:[*]_context)_;
+bool *tracefs_instance_exists*(const char pass:[*]_name_);
+size_t *tracefs_instance_get_buffer_size*(struct tracefs_instance pass:[*]_instance_, int _cpu_);
+int *tracefs_instance_set_buffer_size*(struct tracefs_instance pass:[*]_instance_, size_t _size_, int _cpu_);
+--
+
+DESCRIPTION
+-----------
+Helper functions for working with trace instances.
+
+The *tracefs_instance_get_name()* function returns the name of the given _instance_.
+Note that the top instance has no name, the function returns NULL for it.
+
+The *tracefs_instance_get_trace_dir()* function returns the tracing directory, where
+the given _instance_ is configured.
+
+The *tracefs_instances_walk()* function walks through all configured tracing
+instances in the system and calls _callback_ for each one of them. The _context_
+argument is passed to the _callback_, together with the instance name. If the
+_callback_ returns non-zero, the iteration stops. Note, the _callback_ is not
+called for the top top instance.
+
+The *tracefs_instance_exists()* function checks if an instance with the given
+_name_ exists in the system.
+
+The *tracefs_instace_get_buffer_size()* returns the size of the ring buffer. If _cpu_
+is negative, it returns the total size of all the per CPU ring buffers, otherwise
+it returns the size of the per CPU ring buffer for _cpu_.
+
+The *tracefs_instance_set_buffer_size()* function sets the size of the ring buffer.
+If _cpu_ is negative, then it sets all the per CPU ring buffers to _size_ (note
+the total size is the number of CPUs * _size_). If _cpu_ is specified, then it only
+sets the size of the per CPU ring buffer.
+
+RETURN VALUE
+------------
+The *tracefs_instance_get_name()* returns a string or NULL in case of the top
+instance. The returned string must _not_ be freed.
+
+The *tracefs_instance_get_trace_dir()* returns a string or NULL in case of an error.
+The returned string must _not_ be freed.
+
+The *tracefs_instances_walk()* function returns 0, if all instances were iterated, 1
+if the iteration was stopped by the _callback_, or -1 in case of an error.
+
+The *tracefs_instance_exists()* returns true if an instance with the given _name_
+exists in the system or false otherwise.
+
+The *tracefs_instance_get_buffer_size()* returns the size of the ring buffer depending on
+the _cpu_ value passed in, or -1 on error.
+
+The *tracefs_instance_set_buffer_size()* returns zero on success and -1 on error.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <tracefs.h>
+
+struct tracefs_instance *inst;
+....
+char *name = tracefs_instance_get_name(inst);
+ if(name) {
+ /* Got name of the instance */
+ }
+char *dir = tracefs_instance_get_trace_dir(inst);
+ if(dir) {
+ /* Got tracing directory of the instance */
+ }
+...
+static int instance_walk(char *name, void *context)
+{
+ /* Got instance with name */
+ return 0;
+}
+...
+ if (tracefs_instances_walk(instance_walk, NULL) < 0) {
+ /* Error walking through the instances */
+ }
+...
+ if (tracefs_instance_exists("foo")) {
+ /* There is instance with name foo in the system */
+ } else {
+ /* There is no instance with name foo in the system */
+ }
+--
+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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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).
diff --git a/Documentation/libtracefs-iterator.txt b/Documentation/libtracefs-iterator.txt
new file mode 100644
index 0000000..b971bd0
--- /dev/null
+++ b/Documentation/libtracefs-iterator.txt
@@ -0,0 +1,229 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_iterate_raw_events, tracefs_iterate_stop, tracefs_follow_event, tracefs_follow_missed_events - Iterate over events in the ring buffer
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+int *tracefs_iterate_raw_events*(struct tep_handle pass:[*]_tep_, struct tracefs_instance pass:[*]_instance_,
+ cpu_set_t pass:[*]_cpus_, int _cpu_size_,
+ int (pass:[*]_callback_)(struct tep_event pass:[*], struct tep_record pass:[*], int, void pass:[*]),
+ void pass:[*]_callback_context_);
+void *tracefs_iterate_stop*(struct tracefs_instance pass:[*]_instance_);
+
+int *tracefs_follow_event*(struct tep_handle pass:[*]_tep_, struct tracefs_instance pass:[*]_instance_,
+ const char pass:[*]_system_, const char pass:[*]_event_name_,
+ int (pass:[*]_callback_)(struct tep_event pass:[*],
+ struct tep_record pass:[*],
+ int, void pass:[*]),
+ void pass:[*]_callback_data_);
+int *tracefs_follow_missed_events*(struct tracefs_instance pass:[*]_instance_,
+ int (pass:[*]_callback_)(struct tep_event pass:[*],
+ struct tep_record pass:[*],
+ int, void pass:[*]),
+ void pass:[*]_callback_data_);
+--
+
+DESCRIPTION
+-----------
+Trace iterator over raw events.
+
+The *tracefs_iterate_raw_events()* function will read the tracefs raw
+data buffers and call the specified _callback_ function for every event it
+encounters. Events are iterated in sorted order: oldest first. An initialized
+_tep_ handler is required (See *tracefs_local_events*(3)). If _instance_ is
+NULL, then the toplevel tracefs buffer is used, otherwise the buffer for
+the corresponding _instance_ is read. To filter only on a subset of CPUs,
+_cpus_ and _cpu_size_ may be set to only call _callback_ with events that
+occurred on the CPUs specified, otherwise if _cpus_ is NULL then the _callback_
+function will be called for all events, and _cpu_size_ is ignored. The
+_callback_ function will be called with the following parameters: A
+pointer to a struct tep_event that corresponds to the type of event the
+record is; The record representing the event; The CPU that the event
+occurred on; and a pointer to user specified _callback_context_. If the _callback_
+returns non-zero, the iteration stops.
+
+Use *tracefs_iterate_stop()* to force a executing *tracefs_iterate_raw_events()*
+to halt. This can be called from either a callback that is called by
+the iterator (even though a return of non-zero will stop it), or from another
+thread.
+
+The *tracefs_follow_event()* is used with *tracefs_iterate_raw_events()* but
+intead of the callback being called for every event, it is only called for the
+specified _system_ / _event_name_ given to the function. The _callback_ is the
+same as for *tracefs_iterate_raw_events()*, and the passed in _callback_context_
+will be passed to the _callback_ as well. Note, if it returns something other
+than 0, it will stop the loop before the _callback_ of *tracefs_iterate_raw_events()*
+is called.
+
+The *tracefs_follow_missed_events()* will call the _callback_ when missed
+events are detected. It will set the _record_ parameter of the callback to the
+record that came after the missed events and _event_ will be of the type of
+event _record_ is. _cpu_ will be set to the CPU that missed the events, and
+_callback_data_ will be the content that was passed in to the function.
+
+RETURN VALUE
+------------
+The *tracefs_iterate_raw_events()* function returns -1 in case of an error or
+0 otherwise.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <unistd.h>
+#include <tracefs.h>
+#include <stdbool.h>
+#include <signal.h>
+
+struct my_struct {
+ bool stopped;
+};
+
+#define MAX_COUNT 500000
+static int counter;
+
+static int callback(struct tep_event *event, struct tep_record *record,
+ int cpu, void *data)
+{
+ struct my_struct *my_data = data;
+ static struct trace_seq seq;
+
+ if (counter++ > MAX_COUNT) {
+ my_data->stopped = true;
+ return 1;
+ }
+
+ if (!seq.buffer)
+ trace_seq_init(&seq);
+
+ tep_print_event(event->tep, &seq, record, "%16s-%-5d [%03d] %6.1000d %s: %s\n",
+ TEP_PRINT_COMM, TEP_PRINT_PID, TEP_PRINT_CPU,
+ TEP_PRINT_TIME, TEP_PRINT_NAME, TEP_PRINT_INFO);
+ trace_seq_terminate(&seq);
+ trace_seq_do_printf(&seq);
+ trace_seq_reset(&seq);
+ return 0;
+}
+
+static int sched_callback(struct tep_event *event, struct tep_record *record,
+ int cpu, void *data)
+{
+ static struct tep_format_field *prev_pid;
+ static struct tep_format_field *next_pid;
+ unsigned long long pid;
+ int this_pid = *(int *)data;
+
+ if (!prev_pid) {
+ prev_pid = tep_find_field(event, "prev_pid");
+ next_pid = tep_find_field(event, "next_pid");
+ if (!prev_pid || !next_pid) {
+ fprintf(stderr, "No pid fields??\n");
+ return -1;
+ }
+ }
+
+ tep_read_number_field(prev_pid, record->data, &pid);
+ if (pid == this_pid)
+ printf("WE ARE LEAVING!\n");
+ tep_read_number_field(next_pid, record->data, &pid);
+ if (pid == this_pid)
+ printf("WE ARE ARRIVING!\n");
+ return 0;
+}
+
+static int missed_callback(struct tep_event *event, struct tep_record *record,
+ int cpu, void *data)
+{
+ printf("OOPS! cpu %d dropped ", cpu);
+ if (record->missed_events > 0)
+ printf("%lld ", record->missed_events);
+ printf("events\n");
+ return 0;
+}
+
+static struct tracefs_instance *instance;
+static struct my_struct my_data;
+
+static void sig(int s)
+{
+ tracefs_iterate_stop(instance);
+ my_data.stopped = true;
+}
+
+int main (int argc, char **argv, char **env)
+{
+ struct tep_handle *tep;
+ int this_pid = getpid();
+
+ instance = tracefs_instance_create("my-buffer");
+ if (!instance)
+ return -1;
+
+ signal(SIGINT, sig);
+
+ tracefs_event_enable(instance, NULL, NULL);
+ sleep(1);
+ tracefs_event_disable(instance, NULL, NULL);
+ tep = tracefs_local_events(NULL);
+ tep_load_plugins(tep);
+ tracefs_follow_missed_events(instance, missed_callback, NULL);
+ tracefs_follow_event(tep, instance, "sched", "sched_switch", sched_callback, &this_pid);
+ tracefs_iterate_raw_events(tep, instance, NULL, 0, callback, &my_data);
+ tracefs_instance_destroy(instance);
+
+ if (my_data.stopped) {
+ if (counter > MAX_COUNT)
+ printf("Finished max count\n");
+ else
+ printf("Finished via signal\n");
+ }
+
+ return 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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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).
diff --git a/Documentation/libtracefs-kprobes.txt b/Documentation/libtracefs-kprobes.txt
new file mode 100644
index 0000000..593ef9e
--- /dev/null
+++ b/Documentation/libtracefs-kprobes.txt
@@ -0,0 +1,273 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_kprobe_alloc, tracefs_kretprobe_alloc, tracefs_kprobe_raw, tracefs_kretprobe_raw -
+Allocate, get, and create kprobes
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+struct tracefs_dynevent pass:[*]
+*tracefs_kprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_addr_, const char pass:[*]_format_);
+struct tracefs_dynevent pass:[*]
+*tracefs_kretprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_addr_, const char pass:[*]_format_, unsigned int _max_);
+int *tracefs_kprobe_raw*(const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_addr_, const char pass:[*]_format_);
+int *tracefs_kretprobe_raw*(const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_addr_, const char pass:[*]_format_);
+--
+
+DESCRIPTION
+-----------
+*tracefs_kprobe_alloc*() allocates a new kprobe context. The kbrobe is not configured in the system.
+The new kprobe will be in the _system_ group (or kprobes if _system_ is NULL) and have the name of
+_event_ (or _addr_ if _event_ is NULL). The kprobe will be inserted to _addr_ (function name, with
+or without offset, or a address), and the _format_ will define the format of the kprobe. See the
+Linux documentation file under: Documentation/trace/kprobetrace.rst
+
+*tracefs_kretprobe_alloc*() is the same as *tracefs_kprobe_alloc*, but allocates context for
+kretprobe. It has one additional parameter, which is optional, _max_ - maxactive count.
+See description of kretprobes in the Documentation/trace/kprobetrace.rst file.
+
+*tracefs_kprobe_raw*() will create a kprobe event. If _system_ is NULL, then
+the default "kprobes" is used for the group (event system). Otherwise if _system_
+is specified then the kprobe will be created under the group by that name. The
+_event_ is the name of the kprobe event to create. The _addr_ can be a function,
+a function and offset, or a kernel address. This is where the location of the
+kprobe will be inserted in the kernel. The _format_ is the kprobe format as
+specified as FETCHARGS in the Linux kernel source in the Documentation/trace/kprobetrace.rst
+document.
+
+*tracefs_kretprobe_raw*() is the same as *tracefs_kprobe_raw()*, except that it
+creates a kretprobe instead of a kprobe. The difference is also described
+in the Linux kernel source in the Documentation/trace/kprobetrace.rst file.
+
+RETURN VALUE
+------------
+
+*tracefs_kprobe_raw*() and *tracefs_kretprobe_raw*() return 0 on success, or -1 on error.
+If a parsing error occurs on *tracefs_kprobe_raw*() or *tracefs_kretprobe_raw*() then
+*tracefs_error_last*(3) may be used to retrieve the error message explaining the parsing issue.
+
+The *tracefs_kprobe_alloc*() and *tracefs_kretprobe_alloc*() APIs return a pointer to an allocated
+tracefs_dynevent structure, describing the probe. This pointer must be freed by
+*tracefs_dynevent_free*(3). Note, this only allocates a descriptor representing the kprobe. It does
+not modify the running system.
+
+ERRORS
+------
+The following errors are for all the above calls:
+
+*EPERM* Not run as root user
+
+*ENODEV* Kprobe events are not configured for the running kernel.
+
+*ENOMEM* Memory allocation error.
+
+*tracefs_kprobe_raw*(), *tracefs_kretprobe_raw*(), *tracefs_kprobe_alloc*(),
+and *tracefs_kretprobe_alloc*() can fail with the following errors:
+
+*EBADMSG* if _addr_ is NULL.
+
+*EINVAL* Most likely a parsing error occurred (use *tracefs_error_last*(3) to possibly
+ see what that error was).
+
+Other errors may also happen caused by internal system calls.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include <tracefs.h>
+
+static struct tep_event *open_event;
+static struct tep_format_field *file_field;
+
+static struct tep_event *openret_event;
+static struct tep_format_field *ret_field;
+
+static int callback(struct tep_event *event, struct tep_record *record,
+ int cpu, void *data)
+{
+ struct trace_seq seq;
+
+ trace_seq_init(&seq);
+ tep_print_event(event->tep, &seq, record, "%d-%s: ", TEP_PRINT_PID, TEP_PRINT_COMM);
+
+ if (event->id == open_event->id) {
+ trace_seq_puts(&seq, "open file='");
+ tep_print_field(&seq, record->data, file_field);
+ trace_seq_puts(&seq, "'\n");
+ } else if (event->id == openret_event->id) {
+ unsigned long long ret;
+ tep_read_number_field(ret_field, record->data, &ret);
+ trace_seq_printf(&seq, "open ret=%lld\n", ret);
+ } else {
+ goto out;
+ }
+
+ trace_seq_terminate(&seq);
+ trace_seq_do_printf(&seq);
+out:
+ trace_seq_destroy(&seq);
+
+ return 0;
+}
+
+static pid_t run_exec(char **argv, char **env)
+{
+ pid_t pid;
+
+ pid = fork();
+ if (pid)
+ return pid;
+
+ execve(argv[0], argv, env);
+ perror("exec");
+ exit(-1);
+}
+
+const char *mykprobe = "my_kprobes";
+
+enum kprobe_type {
+ KPROBE,
+ KRETPROBE,
+};
+
+static void __kprobe_create(enum kprobe_type type, const char *event,
+ const char *addr, const char *fmt)
+{
+ char *err;
+ int r;
+
+ if (type == KPROBE)
+ r = tracefs_kprobe_raw(mykprobe, event, addr, fmt);
+ else
+ r = tracefs_kretprobe_raw(mykprobe, event, addr, fmt);
+ if (r < 0) {
+ err = tracefs_error_last(NULL);
+ perror("Failed to create kprobe:");
+ if (err && strlen(err))
+ fprintf(stderr, "%s\n", err);
+ }
+}
+
+static void kprobe_create(const char *event, const char *addr,
+ const char *fmt)
+{
+ __kprobe_create(KPROBE, event, addr, fmt);
+}
+
+static void kretprobe_create(const char *event, const char *addr,
+ const char *fmt)
+{
+ __kprobe_create(KRETPROBE, event, addr, fmt);
+}
+
+int main (int argc, char **argv, char **env)
+{
+ struct tracefs_instance *instance;
+ struct tep_handle *tep;
+ const char *sysnames[] = { mykprobe, NULL };
+ pid_t pid;
+
+ if (argc < 2) {
+ printf("usage: %s command\n", argv[0]);
+ exit(-1);
+ }
+
+ instance = tracefs_instance_create("exec_open");
+ if (!instance) {
+ perror("creating instance");
+ exit(-1);
+ }
+
+ tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, true);
+
+ kprobe_create("open", "do_sys_openat2",
+ "file=+0($arg2):ustring flags=+0($arg3):x64 mode=+8($arg3):x64\n");
+
+ kretprobe_create("openret", "do_sys_openat2", "ret=%ax");
+
+ tep = tracefs_local_events_system(NULL, sysnames);
+ if (!tep) {
+ perror("reading events");
+ exit(-1);
+ }
+ open_event = tep_find_event_by_name(tep, mykprobe, "open");
+ file_field = tep_find_field(open_event, "file");
+
+ openret_event = tep_find_event_by_name(tep, mykprobe, "openret");
+ ret_field = tep_find_field(openret_event, "ret");
+
+ tracefs_event_enable(instance, mykprobe, NULL);
+ pid = run_exec(&argv[1], env);
+
+ /* Let the child start to run */
+ sched_yield();
+
+ do {
+ tracefs_load_cmdlines(NULL, tep);
+ tracefs_iterate_raw_events(tep, instance, NULL, 0, callback, NULL);
+ } while (waitpid(pid, NULL, WNOHANG) != pid);
+
+ /* Will disable the events */
+ tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, true);
+ tracefs_instance_destroy(instance);
+ tep_free(tep);
+
+ return 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)
+
+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) 2021 VMware, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).
diff --git a/Documentation/libtracefs-log.txt b/Documentation/libtracefs-log.txt
new file mode 100644
index 0000000..4b72df1
--- /dev/null
+++ b/Documentation/libtracefs-log.txt
@@ -0,0 +1,76 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_set_loglevel - Set log level of the library
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+int *tracefs_set_loglevel*(enum tep_loglevel _level_);
+--
+
+DESCRIPTION
+-----------
+The *tracefs_set_loglevel()* function sets the level of the library logs that will be printed on
+the console. See _libtraceevent(3)_ for detailed description of the log levels. Setting the log
+level to specific value means that logs from the previous levels will be printed too. For example
+_TEP_LOG_WARNING_ will print any logs with severity _TEP_LOG_WARNING_, _TEP_LOG_ERROR_ and
+_TEP_LOG_CRITICAL_. The default log level is _TEP_LOG_CRITICAL_. When a new level is set, it is
+also propagated to the libtraceevent.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <tracefs.h>
+
+tracefs_set_loglevel(TEP_LOG_ALL);
+...
+/* call libtracefs or libtraceevent APIs and observe any logs they produce */
+...
+tracefs_set_loglevel(TEP_LOG_CRITICAL);
+--
+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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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) 2021 VMware, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).
diff --git a/Documentation/libtracefs-marker.txt b/Documentation/libtracefs-marker.txt
new file mode 100644
index 0000000..adc5419
--- /dev/null
+++ b/Documentation/libtracefs-marker.txt
@@ -0,0 +1,116 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_print_init, tracefs_print_close, tracefs_printf, tracefs_vprintf -
+Open, close and write formated strings in the trace buffer.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+int *tracefs_print_init*(struct tracefs_instance pass:[*]_instance_);
+int *tracefs_printf*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_fmt_, _..._);
+int *tracefs_vprintf*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_fmt_, va_list _ap_);
+void *tracefs_print_close*(struct tracefs_instance pass:[*]_instance_);
+
+--
+
+DESCRIPTION
+-----------
+Set of functions to write formated strings in the trace buffer.
+See Documentation/trace/ftrace.rst from the Linux kernel tree for more information about writing
+data from user space in the trace buffer. All these APIs have _instance_ as a first argument. If
+NULL is passed as _instance_, the top trace instance is used.
+
+The *tracefs_print_init()* function initializes the library for writing into the trace buffer of
+the selected _instance_. It is not mandatory to call this API before writing strings, any of
+the printf APIs will call it automatically, if the library is not yet initialized. But calling
+*tracefs_print_init()* in advance will speed up the writing.
+
+The *tracefs_printf()* function writes a formatted string in the trace buffer of the selected
+_instance_. The _fmt_ argument is a string in printf format, followed by variable arguments _..._.
+
+The *tracefs_vprintf()* function writes a formatted string in the trace buffer of the selected
+_instance_. The _fmt_ argument is a string in printf format, followed by list _ap_ of arguments.
+
+The *tracefs_print_close()* function closes the resources, used by the library for writing in
+the trace buffer of the selected instance.
+
+RETURN VALUE
+------------
+The *tracefs_print_init()*, *tracefs_printf()*, and *tracefs_vprintf()* functions return 0 if
+the operation is successful, or -1 in case of an error.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <tracefs.h>
+
+if (tracefs_print_init(NULL) < 0) {
+ /* Failed to initialize the library for writing in the trace buffer of the top trace instance */
+}
+
+void foo_print(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ if (tracefs_vprintf(NULL, format, ap) < 0) {
+ /* Failed to print in the trace buffer */
+ }
+ va_end(ap);
+}
+
+void foo_print_string(char *message)
+{
+ if (tracefs_printf(NULL, "Message from user space: %s", message) < 0) {
+ /* Failed to print in the trace buffer */
+ }
+}
+
+tracefs_print_close();
+--
+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),
+Documentation/trace/ftrace.rst from the Linux kernel tree
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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) 2021 VMware, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).
diff --git a/Documentation/libtracefs-marker_raw.txt b/Documentation/libtracefs-marker_raw.txt
new file mode 100644
index 0000000..9682f20
--- /dev/null
+++ b/Documentation/libtracefs-marker_raw.txt
@@ -0,0 +1,102 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_binary_init, tracefs_binary_close, tracefs_binary_write -
+Open, close and write binary data in the trace buffer.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+int *tracefs_binary_init*(struct tracefs_instance pass:[*]_instance_);
+int *tracefs_binary_write*(struct tracefs_instance pass:[*]_instance_, void pass:[*]_data_, int _len_);
+void *tracefs_binary_close*(struct tracefs_instance pass:[*]_instance_);
+
+--
+
+DESCRIPTION
+-----------
+Set of functions to write binary data in the trace buffer.
+See Documentation/trace/ftrace.rst from the Linux kernel tree for more information about writing
+data from user space in the trace buffer. All these APIs have _instance_ as a first argument. If
+NULL is passed as _instance_, the top trace instance is used.
+
+The *tracefs_binary_init()* function initializes the library for writing into the trace buffer of
+the selected _instance_. It is not mandatory to call this API before writing data, the
+*tracefs_binary_write()* will call it automatically, if the library is not yet initialized.
+But calling *tracefs_binary_init()* in advance will speed up the writing.
+
+The *tracefs_binary_write()* function writes a binary data in the trace buffer of the selected
+_instance_. The _data_ points to the data with length _len_, that is going to be written in
+the trace buffer.
+
+The *tracefs_binary_close()* function closes the resources, used by the library for writing in
+the trace buffer of the selected instance.
+
+RETURN VALUE
+------------
+The *tracefs_binary_init()*, and *tracefs_binary_write()* functions return 0 if the operation is
+successful, or -1 in case of an error.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <tracefs.h>
+
+if (tracefs_binary_init(NULL) < 0) {
+ /* Failed to initialize the library for writing in the trace buffer of the top trace instance */
+}
+
+unsigned int data = 0xdeadbeef;
+
+ if (tracefs_binary_write(NULL, &data, sizeof(data)) < 0) {
+ /* Failed to write in the trace buffer */
+ }
+
+tracefs_binary_close();
+--
+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),
+Documentation/trace/ftrace.rst from the Linux kernel tree
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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) 2021 VMware, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).
diff --git a/Documentation/libtracefs-option-get.txt b/Documentation/libtracefs-option-get.txt
new file mode 100644
index 0000000..8a688a7
--- /dev/null
+++ b/Documentation/libtracefs-option-get.txt
@@ -0,0 +1,141 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_options_get_supported, tracefs_option_is_supported, tracefs_options_get_enabled,
+tracefs_option_is_enabled, tracefs_option_mask_is_set, tracefs_option_id
+- Get and check ftrace options.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+const struct tracefs_options_mask pass:[*]*tracefs_options_get_supported*(struct tracefs_instance pass:[*]_instance_);
+bool *tracefs_option_is_supported*(struct tracefs_instance pass:[*]_instance_, enum tracefs_option_id _id_);
+const struct tracefs_options_mask pass:[*]*tracefs_options_get_enabled*(struct tracefs_instance pass:[*]_instance_);
+bool *tracefs_option_is_enabled*(struct tracefs_instance pass:[*]_instance_, enum tracefs_option_id _id_);
+bool *tracefs_option_mask_is_set*(const struct tracefs_options_mask *options, enum tracefs_option_id id);
+enum tracefs_option_id *tracefs_option_id*(const char pass:[*]_name_);
+--
+
+DESCRIPTION
+-----------
+This set of APIs can be used to get and check current ftrace options. Supported ftrace options may
+depend on the kernel version and the kernel configuration.
+
+The *tracefs_options_get_supported()* function gets all ftrace options supported by the system in
+the given _instance_. If _instance_ is NULL, supported options of the top trace instance are
+returned. The set of supported options is the same in all created trace instances, but may be different
+than the top trace instance.
+
+The *tracefs_option_is_supported()/ function checks if the option with given _id_ is supported by
+the system in the given _instance_. If _instance_ is NULL, the top trace instance is used. If an
+option is supported at the top trace instance, it it may not be supported in a created trace instance.
+
+The *tracefs_options_get_enabled()* function gets all ftrace options, currently enabled in
+the given _instance_. If _instance_ is NULL, enabled options of the top trace instance are returned.
+
+The *tracefs_option_is_enabled()* function checks if the option with given _id_ is enabled in the
+given _instance_. If _instance_ is NULL, the top trace instance is used.
+
+The *tracefs_option_mask_is_set()* function checks if the bit, corresponding to the option with _id_ is
+set in the _options_ bitmask returned from *tracefs_option_get_enabled()* and *tracefs_option_is_supported()*.
+
+The *tracefs_option_id()* converts an option _name_ into its corresponding id, if it is found.
+This allows to find the option _id_ to use in the other functions if only the _name_ is known.
+
+RETURN VALUE
+------------
+The *tracefs_options_get_supported()* and *tracefs_options_get_enabled()* functions, on success,
+return a pointer to the bitmask within the instance, or a global bitmask for the top level,
+or NULL in case of an error. As the returned bitmask is part of the instance structure (or a
+global variable) and must not be freed or modified.
+
+The *tracefs_option_is_supported()* and *tracefs_option_is_enabled()* functions return true if the
+option in supported / enabled, or false otherwise.
+
+The *tracefs_option_mask_is_set()* returns true if the corresponding option is set in the mask
+or false otherwise.
+
+The *tracefs_option_id()* returns the corresponding id defined by *tracefs_options*(3) from
+the given _name_. If the _name_ can not be found, then TRACEFS_OPTION_INVALID is returned.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <tracefs.h>
+...
+const struct tracefs_options_mask *options;
+...
+options = tracefs_options_get_supported(NULL);
+if (!options) {
+ /* Failed to get supported options */
+} else {
+ ...
+}
+...
+options = tracefs_options_get_enabled(NULL);
+if (!options) {
+ /* Failed to get options, enabled in the top instance */
+} else {
+ ...
+}
+if (tracefs_options_mask_is_set(options, TRACEFS_OPTION_LATENCY_FORMAT)) {
+ ...
+}
+...
+
+if (tracefs_option_is_supported(NULL, TRACEFS_OPTION_LATENCY_FORMAT)) {
+ /* Latency format option is supprted */
+}
+
+...
+
+if (tracefs_option_is_enabled(NULL, TRACEFS_OPTION_STACKTRACE)) {
+ /* Stacktrace option is enabled in the top instance */
+}
+
+--
+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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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).
diff --git a/Documentation/libtracefs-option-misc.txt b/Documentation/libtracefs-option-misc.txt
new file mode 100644
index 0000000..c690bfd
--- /dev/null
+++ b/Documentation/libtracefs-option-misc.txt
@@ -0,0 +1,100 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_option_enable, tracefs_option_disable, tracefs_option_name -
+Various trace option functions.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+int *tracefs_option_enable*(struct tracefs_instance pass:[*]_instance_, enum tracefs_option_id _id_);
+int *tracefs_option_disable*(struct tracefs_instance pass:[*]_instance_, enum tracefs_option_id _id_);
+const char pass:[*]*tracefs_option_name*(enum tracefs_option_id _id_);
+--
+
+DESCRIPTION
+-----------
+This set of APIs can be used to enable and disable ftrace options and to get the name of an option.
+
+The *tracefs_option_enable()* function enables the option with _id_ in the given _instance_. If
+_instance_ is NULL, the option is enabled in the top trace instance.
+
+The *tracefs_option_disable()* function disables the option with _id_ in the given _instance_. If
+_instance_ is NULL, the option is disabled in the top trace instance.
+
+The *tracefs_option_name()* function returns a string, representing the option with _id_. The string
+must *not* be freed.
+
+
+RETURN VALUE
+------------
+The *tracefs_option_enable()* and *tracefs_option_disable()* functions return 0 if the state of the
+option is set successfully, or -1 in case of an error.
+
+The *tracefs_option_name()* function returns string with option name, or "unknown" in case of an
+error. The returned string must *not* be freed.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <tracefs.h>
+...
+if (tracefs_option_enable(NULL, TRACEFS_OPTION_ANNOTATE)) {
+ /* Failed to enable annotate option in top trace instance */
+}
+...
+if (tracefs_option_disable(NULL, TRACEFS_OPTION_CONTEXT_INFO)) {
+ /* Failed to disable context info option in top trace instance */
+}
+...
+char *name = tracefs_option_name(TRACEFS_OPTION_FUNC_STACKTRACE);
+if (strcmp(name, "unknown")) {
+ /* Cannot get the name of the option */
+}
+
+--
+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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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).
diff --git a/Documentation/libtracefs-options.txt b/Documentation/libtracefs-options.txt
new file mode 100644
index 0000000..2c720f2
--- /dev/null
+++ b/Documentation/libtracefs-options.txt
@@ -0,0 +1,159 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_options - ftrace options, that can be controlled using tracefs library.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+enum tracefs_option_id {
+ *TRACEFS_OPTION_INVALID*,
+ *TRACEFS_OPTION_ANNOTATE*,
+ *TRACEFS_OPTION_BIN*,
+ *TRACEFS_OPTION_BLK_CGNAME*,
+ *TRACEFS_OPTION_BLK_CGROUP*,
+ *TRACEFS_OPTION_BLK_CLASSIC*,
+ *TRACEFS_OPTION_BLOCK*,
+ *TRACEFS_OPTION_CONTEXT_INFO*,
+ *TRACEFS_OPTION_DISABLE_ON_FREE*,
+ *TRACEFS_OPTION_DISPLAY_GRAPH*,
+ *TRACEFS_OPTION_EVENT_FORK*,
+ *TRACEFS_OPTION_FGRAPH_ABSTIME*,
+ *TRACEFS_OPTION_FGRAPH_CPU*,
+ *TRACEFS_OPTION_FGRAPH_DURATION*,
+ *TRACEFS_OPTION_FGRAPH_IRQS*,
+ *TRACEFS_OPTION_FGRAPH_OVERHEAD*,
+ *TRACEFS_OPTION_FGRAPH_OVERRUN*,
+ *TRACEFS_OPTION_FGRAPH_PROC*,
+ *TRACEFS_OPTION_FGRAPH_TAIL*,
+ *TRACEFS_OPTION_FUNC_STACKTRACE*,
+ *TRACEFS_OPTION_FUNCTION_FORK*,
+ *TRACEFS_OPTION_FUNCTION_TRACE*,
+ *TRACEFS_OPTION_GRAPH_TIME*,
+ *TRACEFS_OPTION_HEX*,
+ *TRACEFS_OPTION_IRQ_INFO*,
+ *TRACEFS_OPTION_LATENCY_FORMAT*,
+ *TRACEFS_OPTION_MARKERS*,
+ *TRACEFS_OPTION_OVERWRITE*,
+ *TRACEFS_OPTION_PAUSE_ON_TRACE*,
+ *TRACEFS_OPTION_PRINTK_MSG_ONLY*,
+ *TRACEFS_OPTION_PRINT_PARENT*,
+ *TRACEFS_OPTION_RAW*,
+ *TRACEFS_OPTION_RECORD_CMD*,
+ *TRACEFS_OPTION_RECORD_TGID*,
+ *TRACEFS_OPTION_SLEEP_TIME*,
+ *TRACEFS_OPTION_STACKTRACE*,
+ *TRACEFS_OPTION_SYM_ADDR*,
+ *TRACEFS_OPTION_SYM_OFFSET*,
+ *TRACEFS_OPTION_SYM_USEROBJ*,
+ *TRACEFS_OPTION_TRACE_PRINTK*,
+ *TRACEFS_OPTION_USERSTACKTRACE*,
+ *TRACEFS_OPTION_VERBOSE*,
+};
+--
+
+DESCRIPTION
+-----------
+This enum contains all ftrace options, that can be manipulated using tracefs library. More detailed
+information about each option is available in Documentation/trace/ftrace.rst from the Linux
+kernel tree, in the trace_options section. Note that some ftrace options cannot be manipulated by
+this library, as they are intended for internal, debug purposes. These options control the tracers
+or the trace output. All options have two states - on and off, the default state is different for
+each of them.
+[verse]
+--
+Common options for all tracers:
+ *TRACEFS_OPTION_INVALID* Not a valid ftrace option, used by the API to indicate an error.
+ *TRACEFS_OPTION_ANNOTATE* Display when a new CPU buffer started.
+ *TRACEFS_OPTION_BIN* Display the formats in raw binary.
+ *TRACEFS_OPTION_CONTEXT_INFO* Show only the event data. Hides the comm, PID, timestamp, CPU, and other useful data.
+ *TRACEFS_OPTION_BLOCK* When set, reading trace_pipe will not block when polled.
+ *TRACEFS_OPTION_DISABLE_ON_FREE* When the free_buffer is closed, tracing will stop.
+ *TRACEFS_OPTION_DISPLAY_GRAPH* When set, the latency tracers will use function graph tracing instead of function tracing.
+ *TRACEFS_OPTION_EVENT_FORK* When set, tasks with PIDs listed in set_event_pid will have the PIDs of their children added to set_event_pid when those tasks fork.
+ *TRACEFS_OPTION_FUNCTION_FORK* When set, tasks with PIDs listed in set_ftrace_pid will have the PIDs of their children added to set_ftrace_pid when those tasks fork.
+ *TRACEFS_OPTION_FUNCTION_TRACE* When enabled, the latency tracers will trace functions.
+ *TRACEFS_OPTION_HEX* Display numbers in a hexadecimal format.
+ *TRACEFS_OPTION_IRQ_INFO* Display the interrupt, preempt count, need resched data.
+ *TRACEFS_OPTION_LATENCY_FORMAT* Display additional information about the latency.
+ *TRACEFS_OPTION_MARKERS* When set, the trace_marker is enabled - writable (only by root).
+ *TRACEFS_OPTION_OVERWRITE* Controls what happens when the trace buffer is full. If set, the oldest events are discarded and overwritten. If disabled, then the newest events are discarded.
+ *TRACEFS_OPTION_PAUSE_ON_TRACE* When set, opening the trace file for read, will pause writing to the ring buffer. When the file is closed, tracing will be enabled again.
+ *TRACEFS_OPTION_PRINTK_MSG_ONLY* When set, trace_printk()s will only show the format and not their parameters.
+ *TRACEFS_OPTION_PRINT_PARENT* On function traces, display the calling (parent) function as well as the function being traced.
+ *TRACEFS_OPTION_RAW* Display raw numbers.
+ *TRACEFS_OPTION_RECORD_CMD* Save a mapping with a pid and corresponding command.
+ *TRACEFS_OPTION_RECORD_TGID* Save a mapping with a pid and corresponding Thread Group IDs.
+ *TRACEFS_OPTION_STACKTRACE* Record a stack trace after any trace event.
+ *TRACEFS_OPTION_SYM_ADDR* Display the function address as well as the function name.
+ *TRACEFS_OPTION_SYM_OFFSET* Display not only the function name, but also the offset in the function.
+ *TRACEFS_OPTION_SYM_USEROBJ* When *TRACEFS_OPTION_USERSTACKTRACE* is set, look up which object the address belongs to, and print the object and a relative address.
+ *TRACEFS_OPTION_TRACE_PRINTK* Disable trace_printk() from writing into the buffer.
+ *TRACEFS_OPTION_USERSTACKTRACE* Records a stack trace of the current user space thread after each trace event.
+ *TRACEFS_OPTION_VERBOSE* When *TRACEFS_OPTION_LATENCY_FORMAT* is enabled, print more detailed information.
+
+Options, specific to function tracer:
+ *TRACEFS_OPTION_FUNC_STACKTRACE* Record a stack trace after every function.
+
+Options, specific to function_graph tracer:
+ *TRACEFS_OPTION_FGRAPH_ABSTIME* Display the timestamp at each line.
+ *TRACEFS_OPTION_FGRAPH_CPU* Display the CPU number of the CPU where the trace occurred.
+ *TRACEFS_OPTION_FGRAPH_DURATION* Display the duration of the amount of time at the end of each function, in microseconds.
+ *TRACEFS_OPTION_FGRAPH_IRQS* Trace functions that happen inside an interrupt.
+ *TRACEFS_OPTION_FGRAPH_OVERHEAD* Display a marker if a function takes longer than a certain amount of time.
+ *TRACEFS_OPTION_FGRAPH_OVERRUN* Display "overrun" of the call graph, in the case of functions missed due to big callstack.
+ *TRACEFS_OPTION_FGRAPH_PROC* Display the command of each process at every line.
+ *TRACEFS_OPTION_FGRAPH_TAIL* Display the function name on its return.
+ *TRACEFS_OPTION_SLEEP_TIME* Account time the task has been scheduled out as part of the function call.
+ *TRACEFS_OPTION_GRAPH_TIME* Display the time to call nested functions, if function profiler is enabled.
+
+Options, specific to blk tracer:
+ *TRACEFS_OPTION_BLK_CGNAME*
+ *TRACEFS_OPTION_BLK_CGROUP*
+ *TRACEFS_OPTION_BLK_CLASSIC* Display a more minimalistic output.
+--
+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),
+_Documentation/trace/ftrace.rst_ from the Linux kernel tree.
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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) 2021 VMware, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).
diff --git a/Documentation/libtracefs-sql.txt b/Documentation/libtracefs-sql.txt
new file mode 100644
index 0000000..6d606db
--- /dev/null
+++ b/Documentation/libtracefs-sql.txt
@@ -0,0 +1,628 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_sql - Create a synthetic event via an SQL statement
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+struct tracefs_synth pass:[*]*tracefs_sql*(struct tep_handle pass:[*]_tep_, const char pass:[*]_name_,
+ const char pass:[*]_sql_buffer_, char pass:[**]_err_);
+--
+
+DESCRIPTION
+-----------
+Synthetic events are dynamically created events that attach two existing events
+together via one or more matching fields between the two events. It can be used
+to find the latency between the events, or to simply pass fields of the first event
+on to the second event to display as one event.
+
+The Linux kernel interface to create synthetic events is complex, and there needs
+to be a better way to create synthetic events that is easy and can be understood
+via existing technology.
+
+If you think of each event as a table, where the fields are the column of the table
+and each instance of the event as a row, you can understand how SQL can be used
+to attach two events together and form another event (table). Utilizing the
+SQL *SELECT* *FROM* *JOIN* *ON* [ *WHERE* ] syntax, a synthetic event can easily
+be created from two different events.
+
+For simple SQL queries to make a histogram instead of a synthetic event, see
+HISTOGRAMS below.
+
+*tracefs_sql*() takes in a _tep_ handler (See _tep_local_events_(3)) that is used to
+verify the events within the _sql_buffer_ expression. The _name_ is the name of the
+synthetic event to create. If _err_ points to an address of a string, it will be filled
+with a detailed message on any type of parsing error, including fields that do not belong
+to an event, or if the events or fields are not properly compared.
+
+The example program below is a fully functional parser where it will create a synthetic
+event from a SQL syntax passed in via the command line or a file.
+
+The SQL format is as follows:
+
+*SELECT* <fields> *FROM* <start-event> *JOIN* <end-event> *ON* <matching-fields> *WHERE* <filter>
+
+Note, although the examples show the SQL commands in uppercase, they are not required to
+be so. That is, you can use "SELECT" or "select" or "sElEct".
+
+For example:
+[source,c]
+--
+SELECT syscalls.sys_enter_read.fd, syscalls.sys_exit_read.ret FROM syscalls.sys_enter_read
+ JOIN syscalls.sys_exit_read
+ ON syscalls.sys_enter_read.common_pid = syscalls.sys_exit_write.common_pid
+--
+
+Will create a synthetic event that with the fields:
+
+ u64 fd; s64 ret;
+
+Because the function takes a _tep_ handle, and usually all event names are unique, you can
+leave off the system (group) name of the event, and *tracefs_sql*() will discover the
+system for you.
+
+That is, the above statement would work with:
+
+[source,c]
+--
+SELECT sys_enter_read.fd, sys_exit_read.ret FROM sys_enter_read JOIN sys_exit_read
+ ON sys_enter_read.common_pid = sys_exit_write.common_pid
+--
+
+The *AS* keyword can be used to name the fields as well as to give an alias to the
+events, such that the above can be simplified even more as:
+
+[source,c]
+--
+SELECT start.fd, end.ret FROM sys_enter_read AS start JOIN sys_exit_read AS end ON start.common_pid = end.common_pid
+--
+
+The above aliases _sys_enter_read_ as *start* and _sys_exit_read_ as *end* and uses
+those aliases to reference the event throughout the statement.
+
+Using the *AS* keyword in the selection portion of the SQL statement will define what
+those fields will be called in the synthetic event.
+
+[source,c]
+--
+SELECT start.fd AS filed, end.ret AS return FROM sys_enter_read AS start JOIN sys_exit_read AS end
+ ON start.common_pid = end.common_pid
+--
+
+The above labels the _fd_ of _start_ as *filed* and the _ret_ of _end_ as *return* where
+the synthetic event that is created will now have the fields:
+
+ u64 filed; s64 return;
+
+The fields can also be calculated with results passed to the synthetic event:
+
+[source,c]
+--
+select start.truesize, end.len, (start.truesize - end.len) as diff from napi_gro_receive_entry as start
+ JOIN netif_receive_skb as end ON start.skbaddr = end.skbaddr
+--
+
+Which would show the *truesize* of the _napi_gro_receive_entry_ event, the actual
+_len_ of the content, shown by the _netif_receive_skb_, and the delta between
+the two and expressed by the field *diff*.
+
+The code also supports recording the timestamps at either event, and performing calculations
+on them. For wakeup latency, you have:
+
+[source,c]
+--
+select start.pid, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) as lat from sched_waking as start
+ JOIN sched_switch as end ON start.pid = end.next_pid
+--
+
+The above will create a synthetic event that records the _pid_ of the task being woken up,
+and the time difference between the _sched_waking_ event and the _sched_switch_ event.
+The *TIMESTAMP_USECS* will truncate the time down to microseconds as the timestamp usually
+recorded in the tracing buffer has nanosecond resolution. If you do not want that
+truncation, use *TIMESTAMP* instead of *TIMESTAMP_USECS*.
+
+Finally, the *WHERE* clause can be added, that will let you add filters on either or both events.
+
+[source,c]
+--
+select start.pid, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) as lat from sched_waking as start
+ JOIN sched_switch as end ON start.pid = end.next_pid
+ WHERE start.prio < 100 && (!(end.prev_pid < 1 || end.prev_prio > 100) || end.prev_pid == 0)
+--
+
+*NOTE*
+
+Although both events can be used together in the *WHERE* clause, they must not be mixed outside
+the top most "&&" statements. You can not OR (||) the events together, where a filter of one
+event is OR'd to a filter of the other event. This does not make sense, as the synthetic event
+requires both events to take place to be recorded. If one is filtered out, then the synthetic
+event does not execute.
+
+[source,c]
+--
+select start.pid, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) as lat from sched_waking as start
+ JOIN sched_switch as end ON start.pid = end.next_pid
+ WHERE start.prio < 100 && end.prev_prio < 100
+--
+
+The above is valid.
+
+Where as the below is not.
+
+[source,c]
+--
+select start.pid, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) as lat from sched_waking as start
+ JOIN sched_switch as end ON start.pid = end.next_pid
+ WHERE start.prio < 100 || end.prev_prio < 100
+--
+
+
+KEYWORDS AS EVENT FIELDS
+------------------------
+
+In some cases, an event may have a keyword. For example, regcache_drop_region has "from"
+as a field and the following will not work
+
+[source,c]
+--
+ select from from regcache_drop_region
+--
+
+In such cases, add a backslash to the conflicting field, and this will tell the parser
+that the "from" is a field and not a keyword:
+
+[source,c]
+--
+ select \from from regcache_drop_region
+--
+
+HISTOGRAMS
+----------
+
+Simple SQL statements without the *JOIN* *ON* may also be used, which will create a histogram
+instead. When doing this, the struct tracefs_hist descriptor can be retrieved from the
+returned synthetic event descriptor via the *tracefs_synth_get_start_hist*(3).
+
+In order to utilize the histogram types (see xxx) the CAST command of SQL can be used.
+
+That is:
+
+[source,c]
+--
+ select CAST(common_pid AS comm), CAST(id AS syscall) FROM sys_enter
+--
+
+Which produces:
+
+[source,c]
+--
+ # echo 'hist:keys=common_pid.execname,id.syscall' > events/raw_syscalls/sys_enter/trigger
+
+ # cat events/raw_syscalls/sys_enter/hist
+
+{ common_pid: bash [ 18248], id: sys_setpgid [109] } hitcount: 1
+{ common_pid: sendmail [ 1812], id: sys_read [ 0] } hitcount: 1
+{ common_pid: bash [ 18247], id: sys_getpid [ 39] } hitcount: 1
+{ common_pid: bash [ 18247], id: sys_dup2 [ 33] } hitcount: 1
+{ common_pid: gmain [ 13684], id: sys_inotify_add_watch [254] } hitcount: 1
+{ common_pid: cat [ 18247], id: sys_access [ 21] } hitcount: 1
+{ common_pid: bash [ 18248], id: sys_getpid [ 39] } hitcount: 1
+{ common_pid: cat [ 18247], id: sys_fadvise64 [221] } hitcount: 1
+{ common_pid: sendmail [ 1812], id: sys_openat [257] } hitcount: 1
+{ common_pid: less [ 18248], id: sys_munmap [ 11] } hitcount: 1
+{ common_pid: sendmail [ 1812], id: sys_close [ 3] } hitcount: 1
+{ common_pid: gmain [ 1534], id: sys_poll [ 7] } hitcount: 1
+{ common_pid: bash [ 18247], id: sys_execve [ 59] } hitcount: 1
+--
+
+Note, string fields may not be cast.
+
+The possible types to cast to are:
+
+*HEX* - convert the value to use hex and not decimal
+
+*SYM* - convert a pointer to symbolic (kallsyms values)
+
+*SYM-OFFSET* - convert a pointer to symbolic and include the offset.
+
+*SYSCALL* - convert the number to the mapped system call name
+
+*EXECNAME* or *COMM* - can only be used with the common_pid field. Will show the task
+name of the process.
+
+*LOG* or *LOG2* - bucket the key values in a log 2 values (1, 2, 3-4, 5-8, 9-16, 17-32, ...)
+
+The above fields are not case sensitive, and "LOG2" works as good as "log".
+
+A special CAST to _COUNTER_ or __COUNTER__ will make the field a value and not
+a key. For example:
+
+[source,c]
+--
+ SELECT common_pid, CAST(bytes_req AS _COUNTER_) FROM kmalloc
+--
+
+Which will create
+
+[source,c]
+--
+ echo 'hist:keys=common_pid:vals=bytes_req' > events/kmem/kmalloc/trigger
+
+ cat events/kmem/kmalloc/hist
+
+{ common_pid: 1812 } hitcount: 1 bytes_req: 32
+{ common_pid: 9111 } hitcount: 2 bytes_req: 272
+{ common_pid: 1768 } hitcount: 3 bytes_req: 1112
+{ common_pid: 0 } hitcount: 4 bytes_req: 512
+{ common_pid: 18297 } hitcount: 11 bytes_req: 2004
+--
+
+RETURN VALUE
+------------
+Returns 0 on success and -1 on failure. On failure, if _err_ is defined, it will be
+allocated to hold a detailed description of what went wrong if it the error was caused
+by a parsing error, or that an event, field does not exist or is not compatible with
+what it was combined with.
+
+CREATE A TOOL
+-------------
+
+The below example is a functional program that can be used to parse SQL commands into
+synthetic events.
+
+[source, c]
+--
+ man tracefs_sql | sed -ne '/^EXAMPLE/,/FILES/ { /EXAMPLE/d ; /FILES/d ; p}' > sqlhist.c
+ gcc -o sqlhist sqlhist.c `pkg-config --cflags --libs libtracefs`
+--
+
+Then you can run the above examples:
+
+[source, c]
+--
+ sudo ./sqlhist 'select start.pid, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) as lat from sched_waking as start
+ JOIN sched_switch as end ON start.pid = end.next_pid
+ WHERE start.prio < 100 || end.prev_prio < 100'
+--
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <tracefs.h>
+
+static void usage(char **argv)
+{
+ fprintf(stderr, "usage: %s [-ed][-n name][-s][-S fields][-m var][-c var][-T][-t dir][-f file | sql-command-line]\n"
+ " -n name - name of synthetic event 'Anonymous' if left off\n"
+ " -t dir - use dir instead of /sys/kernel/tracing\n"
+ " -e - execute the commands to create the synthetic event\n"
+ " -m - trigger the action when var is a new max.\n"
+ " -c - trigger the action when var changes.\n"
+ " -s - used with -m or -c to do a snapshot of the tracing buffer\n"
+ " -S - used with -m or -c to save fields of the end event (comma deliminated)\n"
+ " -T - used with -m or -c to do both a snapshot and a trace\n"
+ " -f file - read sql lines from file otherwise from the command line\n"
+ " if file is '-' then read from standard input.\n",
+ argv[0]);
+ exit(-1);
+}
+
+enum action {
+ ACTION_DEFAULT = 0,
+ ACTION_SNAPSHOT = (1 << 0),
+ ACTION_TRACE = (1 << 1),
+ ACTION_SAVE = (1 << 2),
+ ACTION_MAX = (1 << 3),
+ ACTION_CHANGE = (1 << 4),
+};
+
+#define ACTIONS ((ACTION_MAX - 1))
+
+static int do_sql(const char *instance_name,
+ const char *buffer, const char *name, const char *var,
+ const char *trace_dir, bool execute, int action,
+ char **save_fields)
+{
+ struct tracefs_synth *synth;
+ struct tep_handle *tep;
+ struct trace_seq seq;
+ enum tracefs_synth_handler handler;
+ char *err;
+ int ret;
+
+ if ((action & ACTIONS) && !var) {
+ fprintf(stderr, "Error: -s, -S and -T not supported without -m or -c");
+ exit(-1);
+ }
+
+ if (!name)
+ name = "Anonymous";
+
+ trace_seq_init(&seq);
+ tep = tracefs_local_events(trace_dir);
+ if (!tep) {
+ if (!trace_dir)
+ trace_dir = "tracefs directory";
+ perror(trace_dir);
+ exit(-1);
+ }
+
+ synth = tracefs_sql(tep, name, buffer, &err);
+ if (!synth) {
+ perror("Failed creating synthetic event!");
+ if (err)
+ fprintf(stderr, "%s", err);
+ free(err);
+ exit(-1);
+ }
+
+ if (tracefs_synth_complete(synth)) {
+ if (var) {
+ if (action & ACTION_MAX)
+ handler = TRACEFS_SYNTH_HANDLE_MAX;
+ else
+ handler = TRACEFS_SYNTH_HANDLE_CHANGE;
+
+ if (action & ACTION_SAVE) {
+ ret = tracefs_synth_save(synth, handler, var, save_fields);
+ if (ret < 0) {
+ err = "adding save";
+ goto failed_action;
+ }
+ }
+ if (action & ACTION_TRACE) {
+ /*
+ * By doing the trace before snapshot, it will be included
+ * in the snapshot.
+ */
+ ret = tracefs_synth_trace(synth, handler, var);
+ if (ret < 0) {
+ err = "adding trace";
+ goto failed_action;
+ }
+ }
+ if (action & ACTION_SNAPSHOT) {
+ ret = tracefs_synth_snapshot(synth, handler, var);
+ if (ret < 0) {
+ err = "adding snapshot";
+ failed_action:
+ perror(err);
+ if (errno == ENODEV)
+ fprintf(stderr, "ERROR: '%s' is not a variable\n",
+ var);
+ exit(-1);
+ }
+ }
+ }
+ tracefs_synth_echo_cmd(&seq, synth);
+ if (execute) {
+ ret = tracefs_synth_create(synth);
+ if (ret < 0) {
+ fprintf(stderr, "%s\n", tracefs_error_last(NULL));
+ exit(-1);
+ }
+ }
+ } else {
+ struct tracefs_instance *instance = NULL;
+ struct tracefs_hist *hist;
+
+ hist = tracefs_synth_get_start_hist(synth);
+ if (!hist) {
+ perror("get_start_hist");
+ exit(-1);
+ }
+ if (instance_name) {
+ if (execute)
+ instance = tracefs_instance_create(instance_name);
+ else
+ instance = tracefs_instance_alloc(trace_dir,
+ instance_name);
+ if (!instance) {
+ perror("Failed to create instance");
+ exit(-1);
+ }
+ }
+ tracefs_hist_echo_cmd(&seq, instance, hist, 0);
+ if (execute) {
+ ret = tracefs_hist_start(instance, hist);
+ if (ret < 0) {
+ fprintf(stderr, "%s\n", tracefs_error_last(instance));
+ exit(-1);
+ }
+ }
+ }
+
+ tracefs_synth_free(synth);
+
+ trace_seq_do_printf(&seq);
+ trace_seq_destroy(&seq);
+ return 0;
+}
+
+int main (int argc, char **argv)
+{
+ char *trace_dir = NULL;
+ char *buffer = NULL;
+ char buf[BUFSIZ];
+ int buffer_size = 0;
+ const char *file = NULL;
+ const char *instance = NULL;
+ bool execute = false;
+ char **save_fields = NULL;
+ const char *name;
+ const char *var;
+ int action = 0;
+ char *tok;
+ FILE *fp;
+ size_t r;
+ int c;
+ int i;
+
+ for (;;) {
+ c = getopt(argc, argv, "ht:f:en:m:c:sS:TB:");
+ if (c == -1)
+ break;
+
+ switch(c) {
+ case 'h':
+ usage(argv);
+ case 't':
+ trace_dir = optarg;
+ break;
+ case 'f':
+ file = optarg;
+ break;
+ case 'e':
+ execute = true;
+ break;
+ case 'm':
+ action |= ACTION_MAX;
+ var = optarg;
+ break;
+ case 'c':
+ action |= ACTION_CHANGE;
+ var = optarg;
+ break;
+ case 's':
+ action |= ACTION_SNAPSHOT;
+ break;
+ case 'S':
+ action |= ACTION_SAVE;
+ tok = strtok(optarg, ",");
+ while (tok) {
+ save_fields = tracefs_list_add(save_fields, tok);
+ tok = strtok(NULL, ",");
+ }
+ if (!save_fields) {
+ perror(optarg);
+ exit(-1);
+ }
+ break;
+ case 'T':
+ action |= ACTION_TRACE | ACTION_SNAPSHOT;
+ break;
+ case 'B':
+ instance = optarg;
+ break;
+ case 'n':
+ name = optarg;
+ break;
+ }
+ }
+
+ if ((action & (ACTION_MAX|ACTION_CHANGE)) == (ACTION_MAX|ACTION_CHANGE)) {
+ fprintf(stderr, "Can not use both -m and -c together\n");
+ exit(-1);
+ }
+ if (file) {
+ if (!strcmp(file, "-"))
+ fp = stdin;
+ else
+ fp = fopen(file, "r");
+ if (!fp) {
+ perror(file);
+ exit(-1);
+ }
+ while ((r = fread(buf, 1, BUFSIZ, fp)) > 0) {
+ buffer = realloc(buffer, buffer_size + r + 1);
+ strncpy(buffer + buffer_size, buf, r);
+ buffer_size += r;
+ }
+ fclose(fp);
+ if (buffer_size)
+ buffer[buffer_size] = '\0';
+ } else if (argc == optind) {
+ usage(argv);
+ } else {
+ for (i = optind; i < argc; i++) {
+ r = strlen(argv[i]);
+ buffer = realloc(buffer, buffer_size + r + 2);
+ if (i != optind)
+ buffer[buffer_size++] = ' ';
+ strcpy(buffer + buffer_size, argv[i]);
+ buffer_size += r;
+ }
+ }
+
+ do_sql(instance, buffer, name, var, trace_dir, execute, action, save_fields);
+ free(buffer);
+
+ return 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
+--------
+*sqlhist*(1),
+*libtracefs*(3),
+*libtraceevent*(3),
+*trace-cmd*(1),
+*tracefs_synth_init*(3),
+*tracefs_synth_add_match_field*(3),
+*tracefs_synth_add_compare_field*(3),
+*tracefs_synth_add_start_field*(3),
+*tracefs_synth_add_end_field*(3),
+*tracefs_synth_append_start_filter*(3),
+*tracefs_synth_append_end_filter*(3),
+*tracefs_synth_create*(3),
+*tracefs_synth_destroy*(3),
+*tracefs_synth_free*(3),
+*tracefs_synth_echo_cmd*(3),
+*tracefs_hist_alloc*(3),
+*tracefs_hist_alloc_2d*(3),
+*tracefs_hist_alloc_nd*(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).
diff --git a/Documentation/libtracefs-sqlhist.txt.1 b/Documentation/libtracefs-sqlhist.txt.1
new file mode 100644
index 0000000..875b250
--- /dev/null
+++ b/Documentation/libtracefs-sqlhist.txt.1
@@ -0,0 +1,356 @@
+SQLHIST(1)
+==========
+
+NAME
+----
+sqlhist - Tool that uses SQL language to create / show creation of tracefs histograms and synthetic events.
+
+SYNOPSIS
+--------
+*sqlhist* ['OPTIONS'] ['SQL-select-command']
+
+DESCRIPTION
+-----------
+The sqlhist(1) will take an SQL like statement to create tracefs histograms and
+synthetic events that can perform various actions for various handling of the
+data.
+
+The tracefs file system interfaces with the Linux tracing infrastructure that
+has various dynamic and static events through out the kernel. Each of these
+events can have a "histogram" attached to it, where the fields of the event
+will define the buckets of the histogram.
+
+A synthetic event is a way to attach two separate events and use the fields
+and time stamps of those events to create a new dynamic event. This new
+dynamic event is call a synthetic event. The fields of each event can have
+simple calculations done on them where, for example, the delta between
+a field of one event to a field of the other event can be taken. This also
+works for the time stamps of the events where the time delta between the
+two events can also be extracted and placed into the synthetic event.
+
+Other actions can be done from the fields of the events. A snapshot can
+be taken of the kernel ring buffer a variable used in the synthetic
+event creating hits a max, or simply changes.
+
+The commands to create histograms and synthetic events are complex and
+not easy to remember. *sqlhist* is used to convert SQL syntax into the
+commands needed to create the histogram or synthetic event.
+
+The *SQL-select-command* is a SQL string defined by *tracefs_sql*(3).
+
+Note, this must be run as root (or sudo) as interacting with the tracefs
+directory requires root privilege, unless the *-t* option is given with
+a copy of the _tracefs_ directory and its events.
+
+The *sqlhist* is a simple program where its code actual exists in the
+*tracefs_sql*(3) man page.
+
+OPTIONS
+-------
+*-n* 'name'::
+ The name of the synthetic event to create. This event can then be
+ used like any other event, and enabled via *trace-cmd*(1).
+
+*-t* 'tracefs-dir'::
+ In order to test this out as non root user, a copy of the tracefs directory
+ can be used, and passing that directory with this option will allow
+ the program to work. Obviously, *-e* will not work as non-root because
+ it will not be able to execute.
+
+ # mkdir /tmp/tracing
+ # cp -r /sys/kernel/tracing/events /tmp/tracing
+ # exit
+ $ ./sqlhist -t /tmp/tracing ...
+
+*-e*::
+ Not only display the commands to create the histogram, but also execute them.
+ This requires root privilege.
+
+*-f* 'file'::
+ Instead of reading the SQL commands from the command line, read them from
+ _file_. If _file_ is '-' then read from standard input.
+
+*-m* 'var'::
+ Do the given action when the variable _var_ hits a new maximum. This can
+ not be used with *-c*.
+
+*-c* 'var'::
+ Do the given action when the variable _var_ changes its value. This can
+ not be used with *-m*.
+
+*-s*::
+ Perform a snapshot instead of calling the synthetic event.
+
+*-T*::
+ Perform both a snapshot and trace the synthetic event.
+
+*-S* 'fields[,fields]'::
+ Save the given fields. The fields must be fields of the "end" event given
+ in the *SQL-select-command*
+
+*-B* 'instance'::
+ For simple statements that only produce a histogram, the instance given here
+ will be where the histogram will be created. This is ignored for full synthetic
+ event creation, as sythetic events have a global affect on all tracing instances,
+ where as, histograms only affect a single instance.
+
+EXAMPLES
+--------
+
+Create the sqlhist executable:
+
+[source, c]
+--
+ man tracefs_sql | sed -ne '/^EXAMPLE/,/FILES/ { /EXAMPLE/d ; /FILES/d ; p}' > sqlhist.c
+ gcc -o sqlhist sqlhist.c `pkg-config --cflags --libs libtracefs`
+--
+
+As described above, for testing purposes, make a copy of the event directory:
+[source, c]
+--
+ $ mkdir /tmp/tracing
+ $ sudo cp -r /sys/kernel/tracing/events /tmp/tracing/
+ $ sudo chmod -R 0644 /tmp/tracing/
+--
+
+For an example of simple histogram output using the copy of the tracefs directory.
+[source, c]
+--
+ $ ./sqlhist -t /tmp/tracing/ 'SELECT CAST(call_site as SYM-OFFSET), bytes_req, CAST(bytes_alloc AS _COUNTER_) FROM kmalloc'
+--
+
+Produces the output:
+[source, c]
+--
+ echo 'hist:keys=call_site.sym-offset,bytes_req:vals=bytes_alloc' > /sys/kernel/tracing/events/kmem/kmalloc/trigger
+--
+
+Which could be used by root:
+[source, c]
+--
+ # echo 'hist:keys=call_site.sym-offset,bytes_req:vals=bytes_alloc' > /sys/kernel/tracing/events/kmem/kmalloc/trigger
+ # cat /sys/kernel/tracing/events/kmem/kmalloc/hist
+# event histogram
+#
+# trigger info: hist:keys=call_site.sym-offset,bytes_req:vals=hitcount,bytes_alloc:sort=hitcount:size=2048 [active]
+#
+
+{ call_site: [ffffffff813f8d8a] load_elf_phdrs+0x4a/0xb0 , bytes_req: 728 } hitcount: 1 bytes_alloc: 1024
+{ call_site: [ffffffffc0c69e74] nf_ct_ext_add+0xd4/0x1d0 [nf_conntrack] , bytes_req: 128 } hitcount: 1 bytes_alloc: 128
+{ call_site: [ffffffff818355e6] dma_resv_get_fences+0xf6/0x440 , bytes_req: 8 } hitcount: 1 bytes_alloc: 8
+{ call_site: [ffffffffc06dc73f] intel_gt_get_buffer_pool+0x15f/0x290 [i915] , bytes_req: 424 } hitcount: 1 bytes_alloc: 512
+{ call_site: [ffffffff813f8d8a] load_elf_phdrs+0x4a/0xb0 , bytes_req: 616 } hitcount: 1 bytes_alloc: 1024
+{ call_site: [ffffffff8161a44c] __sg_alloc_table+0x11c/0x180 , bytes_req: 32 } hitcount: 1 bytes_alloc: 32
+{ call_site: [ffffffffc070749d] shmem_get_pages+0xad/0x5d0 [i915] , bytes_req: 16 } hitcount: 1 bytes_alloc: 16
+{ call_site: [ffffffffc07507f5] intel_framebuffer_create+0x25/0x60 [i915] , bytes_req: 408 } hitcount: 1 bytes_alloc: 512
+{ call_site: [ffffffffc06fc20f] eb_parse+0x34f/0x910 [i915] , bytes_req: 408 } hitcount: 1 bytes_alloc: 512
+{ call_site: [ffffffffc0700ebd] i915_gem_object_get_pages_internal+0x5d/0x270 [i915] , bytes_req: 16 } hitcount: 1 bytes_alloc: 16
+{ call_site: [ffffffffc0771188] intel_frontbuffer_get+0x38/0x220 [i915] , bytes_req: 400 } hitcount: 1 bytes_alloc: 512
+{ call_site: [ffffffff8161a44c] __sg_alloc_table+0x11c/0x180 , bytes_req: 128 } hitcount: 1 bytes_alloc: 128
+{ call_site: [ffffffff813f8f45] load_elf_binary+0x155/0x1680 , bytes_req: 28 } hitcount: 1 bytes_alloc: 32
+{ call_site: [ffffffffc07038c8] __assign_mmap_offset+0x208/0x3d0 [i915] , bytes_req: 288 } hitcount: 1 bytes_alloc: 512
+{ call_site: [ffffffff813737b2] alloc_bprm+0x32/0x2f0 , bytes_req: 416 } hitcount: 1 bytes_alloc: 512
+{ call_site: [ffffffff813f9027] load_elf_binary+0x237/0x1680 , bytes_req: 64 } hitcount: 1 bytes_alloc: 64
+{ call_site: [ffffffff8161a44c] __sg_alloc_table+0x11c/0x180 , bytes_req: 64 } hitcount: 1 bytes_alloc: 64
+{ call_site: [ffffffffc040ffe7] drm_vma_node_allow+0x27/0xe0 [drm] , bytes_req: 40 } hitcount: 2 bytes_alloc: 128
+{ call_site: [ffffffff813cda98] __do_sys_timerfd_create+0x58/0x1c0 , bytes_req: 336 } hitcount: 2 bytes_alloc: 1024
+{ call_site: [ffffffff818355e6] dma_resv_get_fences+0xf6/0x440 , bytes_req: 40 } hitcount: 2 bytes_alloc: 128
+{ call_site: [ffffffff8139b75a] single_open+0x2a/0xa0 , bytes_req: 32 } hitcount: 2 bytes_alloc: 64
+{ call_site: [ffffffff815df715] bio_kmalloc+0x25/0x80 , bytes_req: 136 } hitcount: 2 bytes_alloc: 384
+{ call_site: [ffffffffc071e5cd] i915_vma_work+0x1d/0x50 [i915] , bytes_req: 416 } hitcount: 3 bytes_alloc: 1536
+{ call_site: [ffffffff81390d0d] alloc_fdtable+0x4d/0x100 , bytes_req: 56 } hitcount: 3 bytes_alloc: 192
+{ call_site: [ffffffffc06ff65f] i915_gem_do_execbuffer+0x158f/0x2440 [i915] , bytes_req: 16 } hitcount: 4 bytes_alloc: 64
+{ call_site: [ffffffff8137713c] alloc_pipe_info+0x5c/0x230 , bytes_req: 384 } hitcount: 5 bytes_alloc: 2560
+{ call_site: [ffffffff813771b4] alloc_pipe_info+0xd4/0x230 , bytes_req: 640 } hitcount: 5 bytes_alloc: 5120
+{ call_site: [ffffffff81834cdb] dma_resv_list_alloc+0x1b/0x40 , bytes_req: 40 } hitcount: 6 bytes_alloc: 384
+{ call_site: [ffffffff81834cdb] dma_resv_list_alloc+0x1b/0x40 , bytes_req: 56 } hitcount: 9 bytes_alloc: 576
+{ call_site: [ffffffff8120086e] tracing_map_sort_entries+0x9e/0x3e0 , bytes_req: 24 } hitcount: 60 bytes_alloc: 1920
+
+Totals:
+ Hits: 122
+ Entries: 30
+ Dropped: 0
+--
+
+Note, although the examples use uppercase for the SQL keywords, they do not have
+to be. 'SELECT' could also be 'select' or even 'sElEcT'.
+
+By using the full SQL language, synthetic events can be made and processed.
+For example, using *sqlhist* along with *trace-cmd*(1), wake up latency can
+be recorded by creating a synthetic event by attaching the _sched_waking_
+and the _sched_switch_ events.
+
+[source, c]
+--
+ # sqlhist -n wakeup_lat -e -T -m lat 'SELECT end.next_comm AS comm, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) AS lat FROM ' \
+ 'sched_waking AS start JOIN sched_switch AS end ON start.pid = end.next_pid WHERE end.next_prio < 100 && end.next_comm == "cyclictest"'
+ # trace-cmd start -e all -e wakeup_lat -R stacktrace
+ # cyclictest -l 1000 -p80 -i250 -a -t -q -m -d 0 -b 1000 --tracemark
+ # trace-cmd show -s | tail -30
+ <idle>-0 [002] dNh4 23454.902246: sched_wakeup: comm=cyclictest pid=12272 prio=120 target_cpu=002
+ <idle>-0 [005] ...1 23454.902246: cpu_idle: state=4294967295 cpu_id=5
+ <idle>-0 [007] d..1 23454.902246: cpu_idle: state=0 cpu_id=7
+ <idle>-0 [002] dNh1 23454.902247: hrtimer_expire_exit: hrtimer=0000000037956dc2
+ <idle>-0 [005] d..1 23454.902248: cpu_idle: state=0 cpu_id=5
+ <idle>-0 [002] dNh1 23454.902248: write_msr: 6e0, value 4866ce957272
+ <idle>-0 [006] ...1 23454.902248: cpu_idle: state=4294967295 cpu_id=6
+ <idle>-0 [002] dNh1 23454.902249: local_timer_exit: vector=236
+ <idle>-0 [006] d..1 23454.902250: cpu_idle: state=0 cpu_id=6
+ <idle>-0 [002] .N.1 23454.902250: cpu_idle: state=4294967295 cpu_id=2
+ <idle>-0 [002] dN.1 23454.902251: rcu_utilization: Start context switch
+ <idle>-0 [002] dN.1 23454.902252: rcu_utilization: End context switch
+ <idle>-0 [001] ...1 23454.902252: cpu_idle: state=4294967295 cpu_id=1
+ <idle>-0 [002] dN.3 23454.902253: prandom_u32: ret=3692516021
+ <idle>-0 [001] d..1 23454.902254: cpu_idle: state=0 cpu_id=1
+ <idle>-0 [002] d..2 23454.902254: sched_switch: prev_comm=swapper/2 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=cyclictest next_pid=12275 next_prio=19
+ <idle>-0 [002] d..4 23454.902256: wakeup_lat: next_comm=cyclictest lat=17
+ <idle>-0 [002] d..5 23454.902258: <stack trace>
+ => trace_event_raw_event_synth
+ => action_trace
+ => event_hist_trigger
+ => event_triggers_call
+ => trace_event_buffer_commit
+ => trace_event_raw_event_sched_switch
+ => __traceiter_sched_switch
+ => __schedule
+ => schedule_idle
+ => do_idle
+ => cpu_startup_entry
+ => secondary_startup_64_no_verify
+--
+
+Here's the options for *sqlhist* explained:
+
+ *-n wakeup_lat* ::
+ Name the synthetic event to use *wakeup_lat*.
+
+ *-e*::
+ Execute the commands that are printed.
+
+ *-T*::
+ Perform both a trace action and then a snapshot action (swap the buffer into the static 'snapshot' buffer).
+
+ *-m lat*::
+ Trigger the actions whenever 'lat' hits a new maximum value.
+
+Now a breakdown of the SQL statement:
+[source, c]
+--
+ 'SELECT end.next_comm AS comm, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) AS lat FROM ' \
+ 'sched_waking AS start JOIN sched_switch AS end ON start.pid = end.next_pid WHERE end.next_prio < 100 && end.next_comm == "cyclictest"'
+--
+ *end.next_comm AS comm*::
+ Save the 'sched_switch' field *next_comm* and place it into the *comm* field of the 'wakeup_lat' synthetic event.
+
+ *(end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) AS lat*::
+ Take the delta of the time stamps from the 'sched_switch' event and the 'sched_waking' event.
+ As time stamps are usually recorded in nanoseconds, *TIMESTAMP* would give the full nanosecond time stamp,
+ but here, the *TIMESTAMP_USECS* will truncate it into microseconds. The value is saved in the
+ variable *lat*, which will also be recorded in the synthetic event.
+
+ *FROM 'sched_waking' AS start JOIN sched_switch AS end ON start.pid = end.next_pid*::
+ Create the synthetic event by joining _sched_waking_ to _sched_switch_, matching
+ the _sched_waking_ 'pid' field with the _sched_switch_ 'next_pid' field.
+ Also make *start* an alias for _sched_waking_ and *end* an alias for _sched_switch_
+ which then an use *start* and *end* as a subsitute for _sched_waking_ and _sched_switch_
+ respectively through out the rest of the SQL statement.
+
+ *WHERE end.next_prio < 100 && end.next_comm == "cyclictest"*::
+ Filter the logic where it executes only if _sched_waking_ 'next_prio' field
+ is less than 100. (Note, in the Kernel, priorities are inverse, and the real-time
+ priorities are represented from 0-100 where 0 is the highest priority).
+ Also only trace when the 'next_comm' (the task scheduling in) of the _sched_switch_
+ event has the name "cyclictest".
+
+For the *trace-cmd*(3) command:
+[source, c]
+--
+ trace-cmd start -e all -e wakeup_lat -R stacktrace
+--
+
+ *trace-cmd start*::
+ Enables tracing (does not record to a file).
+
+ *-e all*::
+ Enable all events
+
+ *-e wakeup_lat -R stacktrace*::
+ have the "wakeup_lat" event (our synthetic event) enable the *stacktrace* trigger, were
+ for every instance of the "wakeup_lat" event, a kernel stack trace will be recorded
+ in the ring buffer.
+
+After calling *cyclictest* (a real-time tool to measure wakeup latency), read the snapshot
+buffer.
+
+ *trace-cmd show -s*::
+ *trace-cmd show* reads the kernel ring buffer, and the *-s* option will read the *snapshot*
+ buffer instead of the normal one.
+
+[source, c]
+--
+ <idle>-0 [002] d..4 23454.902256: wakeup_lat: next_comm=cyclictest lat=17
+--
+ We see on the "wakeup_lat" event happened on CPU 2, with a wake up latency 17 microseconds.
+
+This can be extracted into a *trace.dat* file that *trace-cmd*(3) can read and do further
+analysis, as well as *kernelshark*.
+
+[source, c]
+--
+ # trace-cmd extract -s
+ # trace-cmd report --cpu 2 | tail -30
+ <idle>-0 [002] 23454.902238: prandom_u32: ret=1633425088
+ <idle>-0 [002] 23454.902239: sched_wakeup: cyclictest:12275 [19] CPU:002
+ <idle>-0 [002] 23454.902241: hrtimer_expire_exit: hrtimer=0xffffbbd68286fe60
+ <idle>-0 [002] 23454.902241: hrtimer_cancel: hrtimer=0xffffbbd6826efe70
+ <idle>-0 [002] 23454.902242: hrtimer_expire_entry: hrtimer=0xffffbbd6826efe70 now=23455294430750 function=hrtimer_wakeup/0x0
+ <idle>-0 [002] 23454.902243: sched_waking: comm=cyclictest pid=12272 prio=120 target_cpu=002
+ <idle>-0 [002] 23454.902244: prandom_u32: ret=1102749734
+ <idle>-0 [002] 23454.902246: sched_wakeup: cyclictest:12272 [120] CPU:002
+ <idle>-0 [002] 23454.902247: hrtimer_expire_exit: hrtimer=0xffffbbd6826efe70
+ <idle>-0 [002] 23454.902248: write_msr: 6e0, value 4866ce957272
+ <idle>-0 [002] 23454.902249: local_timer_exit: vector=236
+ <idle>-0 [002] 23454.902250: cpu_idle: state=4294967295 cpu_id=2
+ <idle>-0 [002] 23454.902251: rcu_utilization: Start context switch
+ <idle>-0 [002] 23454.902252: rcu_utilization: End context switch
+ <idle>-0 [002] 23454.902253: prandom_u32: ret=3692516021
+ <idle>-0 [002] 23454.902254: sched_switch: swapper/2:0 [120] R ==> cyclictest:12275 [19]
+ <idle>-0 [002] 23454.902256: wakeup_lat: next_comm=cyclictest lat=17
+ <idle>-0 [002] 23454.902258: kernel_stack: <stack trace >
+=> trace_event_raw_event_synth (ffffffff8121a0db)
+=> action_trace (ffffffff8121e9fb)
+=> event_hist_trigger (ffffffff8121ca8d)
+=> event_triggers_call (ffffffff81216c72)
+=> trace_event_buffer_commit (ffffffff811f7618)
+=> trace_event_raw_event_sched_switch (ffffffff8110fda4)
+=> __traceiter_sched_switch (ffffffff8110d449)
+=> __schedule (ffffffff81c02002)
+=> schedule_idle (ffffffff81c02c86)
+=> do_idle (ffffffff8111e898)
+=> cpu_startup_entry (ffffffff8111eba9)
+=> secondary_startup_64_no_verify (ffffffff81000107)
+--
+
+BUGS
+----
+
+As *sqlhist* is just example code from a man page, it is guaranteed to contain
+lots of bugs. For one thing, not all error paths are covered properly.
+
+SEE ALSO
+--------
+trace-cmd(1), tracefs_sql(3)
+
+AUTHOR
+------
+Written by Steven Rostedt, <rostedt@goodmis.org>
+
+RESOURCES
+---------
+https://git.kernel.org/pub/scm/utils/trace-cmd/trace-cmd.git/
+
+COPYING
+-------
+Copyright \(C) 2021 , Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).
+
diff --git a/Documentation/libtracefs-stream.txt b/Documentation/libtracefs-stream.txt
new file mode 100644
index 0000000..8008be8
--- /dev/null
+++ b/Documentation/libtracefs-stream.txt
@@ -0,0 +1,126 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_trace_pipe_stream, tracefs_trace_pipe_print, tracefs_trace_pipe_stop -
+redirect the stream of trace data to an output or stdout.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+ssize_t *tracefs_trace_pipe_stream*(int _fd_, struct tracefs_instance pass:[*]_instance_, int _flags_);
+ssize_t *tracefs_trace_pipe_print*(struct tracefs_instance pass:[*]_instance_, int _flags_);
+void *tracefs_trace_pipe_stop*(struct tracefs_instance pass:[*]_instance_);
+
+
+--
+
+DESCRIPTION
+-----------
+If NULL is passed as _instance_, the top trace instance is used.
+
+The reading of the trace_pipe file can be stopped by calling *tracefs_trace_pipe_stop()*
+which could be placed in a signal handler in case the application wants to stop the
+reading, for example, with the user pressing Ctrl-C.
+
+The *tracefs_trace_pipe_stream()* function redirects the stream of trace data to an output
+file. The "splice" system call is used to moves the data without copying between kernel
+address space and user address space. The _fd_ is the file descriptor of the output file
+and _flags_ is a bit mask of flags to be passed to the open system call of the trace_pipe
+file (see ). If flags contain O_NONBLOCK, then that is also passed to the splice calls
+that may read the file to the output stream file descriptor.
+
+The *tracefs_trace_pipe_print()* function is similar to *tracefs_trace_pipe_stream()*, but
+the stream of trace data is redirected to stdout.
+
+
+RETURN VALUE
+------------
+The *tracefs_trace_pipe_stream()*, and *tracefs_trace_pipe_print()* functions return the
+number of bytes transfered if the operation is successful, or -1 in case of an error.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+
+#include <tracefs.h>
+
+void stop(int sig)
+{
+ tracefs_trace_pipe_stop(NULL);
+}
+
+int main(int argc, char **argv)
+{
+ mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ const char *filename;
+ int fd;
+ int ret;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s output_file\n", argv[0]);
+ exit(-1);
+ }
+ filename = argv[1];
+ fd = creat(filename, mode);
+ if (fd < 0) {
+ perror(filename);
+ exit(-1);
+ }
+ signal(SIGINT, stop);
+ ret = tracefs_trace_pipe_stream(fd, NULL, SPLICE_F_NONBLOCK);
+ close(fd);
+
+ return ret;
+}
+--
+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),
+Documentation/trace/ftrace.rst from the Linux kernel tree
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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) 2021 VMware, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).
diff --git a/Documentation/libtracefs-synth-info.txt b/Documentation/libtracefs-synth-info.txt
new file mode 100644
index 0000000..6ee0320
--- /dev/null
+++ b/Documentation/libtracefs-synth-info.txt
@@ -0,0 +1,298 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_synth_echo_cmd, tracefs_synth_get_start_hist, tracefs_synth_get_name,
+tracefs_synth_raw_fmt, tracefs_synth_show_event, tracefs_synth_show_start_hist, tracefs_synth_show_end_hist,
+tracefs_synth_get_event - Retrieve data of synthetic events.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+int *tracefs_synth_echo_cmd*(struct trace_seq pass:[*]_seq_, struct tracefs_synth pass:[*]_synth_);
+struct tracefs_hist pass:[*]*tracefs_synth_get_start_hist*(struct tracefs_synth pass:[*]_synth_);
+
+const char pass:[*]*tracefs_synth_get_name*(struct tracefs_synth pass:[*]_synth_);
+int *tracefs_synth_raw_fmt*(struct trace_seq pass:[*]_seq_, struct tracefs_synth pass:[*]_synth_);
+const char pass:[*]*tracefs_synth_show_event*(struct tracefs_synth pass:[*]_synth_);
+const char pass:[*]*tracefs_synth_show_start_hist*(struct tracefs_synth pass:[*]_synth_);
+const char pass:[*]*tracefs_synth_show_end_hist*(struct tracefs_synth pass:[*]_synth_);
+struct tep_event pass:[*]*tracefs_synth_get_event*(struct tep_handle pass:[*]_tep_, struct tracefs_synth pass:[*]_synth_);
+
+--
+
+DESCRIPTION
+-----------
+Synthetic events are dynamic events that are created by matching
+two other events which triggers a synthetic event. One event is the starting
+event which some field is recorded, and when the second event is executed,
+if it has a field (or fields) that matches the starting event's field (or fields)
+then it will trigger the synthetic event. The field values other than the matching
+fields may be passed from the starting event to the end event to perform calculations
+on, or to simply pass as a parameter to the synthetic event.
+
+One common use case is to set "sched_waking" as the starting event. This event is
+triggered when a process is awoken. Then set "sched_switch" as the ending event.
+This event is triggered when a new task is scheduled on the CPU. By setting
+the "common_pid" of both events as the matching fields, the time between the
+two events is considered the wake up latency of that process. Use *TRACEFS_TIMESTAMP*
+as a field for both events to calculate the delta in nanoseconds, or use
+*TRACEFS_TIMESTAMP_USECS* as the compare fields for both events to calculate the
+delta in microseconds. This is used as the example below.
+
+See *tracefs_synth_alloc*(3) for allocation of synthetic events, and
+*tracefs_synth_create*() for creating the synthetic event on the system.
+
+*tracefs_synth_echo_cmd*() acts like *tracefs_synth_create*(), but instead of creating
+the synthetic event in the system, it will write the echo commands to manually create
+it in the _seq_ given.
+
+*tracefs_synth_get_start_hist*() returns a struct tracefs_hist descriptor describing
+the histogram used to create the synthetic event.
+
+[verse]
+--
+enum tracefs_synth_handler {
+ *TRACEFS_SYNTH_HANDLE_MATCH*,
+ *TRACEFS_SYNTH_HANDLE_MAX*,
+ *TRACEFS_SYNTH_HANDLE_CHANGE*,
+};
+--
+
+*tracefs_synth_get_name*() returns the name of the synthetic event or NULL on error.
+The returned string belongs to the synth event object and is freed with the event
+by *tracefs_synth_free*().
+
+*tracefs_synth_raw_fmt*() writes the raw format strings (dynamic event and histograms) of
+the synthetic event in the _seq_ given.
+
+*tracefs_synth_show_event*() returns the format of the dynamic event used by the synthetic
+event or NULL on error. The returned string belongs to the synth event object and is freed
+with the event by *tracefs_synth_free*().
+
+*tracefs_synth_show_start_hist*() returns the format of the start histogram used by the
+synthetic event or NULL on error. The returned string belongs to the synth event object
+and is freed with the event by *tracefs_synth_free*().
+
+*tracefs_synth_show_end_hist*() returns the format of the end histogram used by the
+synthetic event or NULL on error. The returned string belongs to the synth event object
+and is freed with the event by *tracefs_synth_free*().
+
+The *tracefs_synth_get_event*() function returns a tep event, describing the given synthetic
+event. The API detects any newly created or removed dynamic events. The returned pointer to
+tep event is controlled by @tep and must not be freed.
+
+RETURN VALUE
+------------
+*tracefs_synth_get_name*(), *tracefs_synth_show_event*(), *tracefs_synth_show_start_hist*()
+and *tracefs_synth_show_end_hist*() return a string owned by the synth event object.
+
+The *tracefs_synth_get_event*() function returns a pointer to a tep event or NULL in case of an
+error or if the requested synthetic event is missing. The returned pointer to tep event is
+controlled by @tep and must not be freed.
+
+All other functions return zero on success or -1 on error.
+
+ERRORS
+------
+The following errors are for all the above calls:
+
+*EPERM* Not run as root user when required.
+
+*EINVAL* Either a parameter is not valid (NULL when it should not be)
+ or a field that is not compatible for calculations.
+
+*ENODEV* An event or one of its fields is not found.
+
+*EBADE* The fields of the start and end events are not compatible for
+ either matching or comparing.
+
+*ENOMEM* not enough memory is available.
+
+And more errors may have happened from the system calls to the system.
+
+EXAMPLE
+-------
+See *tracefs_sql*(3) for a more indepth use of some of this code.
+
+[source,c]
+--
+#include <stdlib.h>
+#include <tracefs.h>
+
+#define start_event "sched_waking"
+#define start_field "pid"
+
+#define end_event "sched_switch"
+#define end_field "next_pid"
+
+#define match_name "pid"
+
+static struct tracefs_synth *synth;
+
+static void make_event(void)
+{
+ struct tep_handle *tep;
+
+ /* Load all events from the system */
+ tep = tracefs_local_events(NULL);
+
+ /* Initialize the synthetic event */
+ synth = tracefs_synth_alloc(tep, "wakeup_lat",
+ NULL, start_event,
+ NULL, end_event,
+ start_field, end_field,
+ match_name);
+
+ /* The tep is no longer needed */
+ tep_free(tep);
+
+
+ /* Save the "prio" field as "prio" from the start event */
+ tracefs_synth_add_start_field(synth, "prio", NULL);
+
+ /* Save the "next_comm" as "comm" from the end event */
+ tracefs_synth_add_end_field(synth, "next_comm", "comm");
+
+ /* Save the "prev_prio" as "prev_prio" from the end event */
+ tracefs_synth_add_end_field(synth, "prev_prio", NULL);
+
+ /*
+ * Take a microsecond time difference between end and start
+ * and record as "delta"
+ */
+ tracefs_synth_add_compare_field(synth, TRACEFS_TIMESTAMP_USECS,
+ TRACEFS_TIMESTAMP_USECS,
+ TRACEFS_SYNTH_DELTA_END, "delta");
+
+ /* Only record if start event "prio" is less than 100 */
+ tracefs_synth_append_start_filter(synth, TRACEFS_FILTER_COMPARE,
+ "prio", TRACEFS_COMPARE_LT, "100");
+
+ /*
+ * Only record if end event "next_prio" is less than 50
+ * or the previous task's prio was not greater than or equal to 100.
+ * next_prio < 50 || !(prev_prio >= 100)
+ */
+ tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_COMPARE,
+ "next_prio", TRACEFS_COMPARE_LT, "50");
+ tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_OR, NULL, 0, NULL);
+ tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_NOT, NULL, 0, NULL);
+ tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_OPEN_PAREN, NULL, 0, NULL);
+ tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_COMPARE,
+ "prev_prio", TRACEFS_COMPARE_GE, "100");
+ /*
+ * Note, the above only added: "next_prio < 50 || !(prev_prio >= 100"
+ * That's because, when the synth is executed, the remaining close parenthesis
+ * will be added. That is, the string will end up being:
+ * "next_prio < 50 || !(prev_prio >= 100)" when one of tracefs_sync_create()
+ * or tracefs_sync_echo_cmd() is run.
+ */
+}
+
+/* Display how to create the synthetic event */
+static void show_event(void)
+{
+ struct trace_seq s;
+
+ trace_seq_init(&s);
+
+ tracefs_synth_echo_cmd(&s, synth);
+ trace_seq_terminate(&s);
+ trace_seq_do_printf(&s);
+ trace_seq_destroy(&s);
+}
+
+int main (int argc, char **argv)
+{
+ make_event();
+
+ if (argc > 1) {
+ if (!strcmp(argv[1], "create")) {
+ /* Create the synthetic event */
+ tracefs_synth_create(synth);
+ } else if (!strcmp(argv[1], "delete")) {
+ /* Delete the synthetic event */
+ tracefs_synth_destroy(synth);
+ } else {
+ printf("usage: %s [create|delete]\n", argv[0]);
+ exit(-1);
+ }
+ } else
+ show_event();
+
+ tracefs_synth_free(synth);
+
+ return 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_alloc_2d*(3),
+*tracefs_hist_alloc_nd*(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),
+*tracefs_synth_alloc*(3),
+*tracefs_synth_add_match_field*(3),
+*tracefs_synth_add_compare_field*(3),
+*tracefs_synth_add_start_field*(3),
+*tracefs_synth_add_end_field*(3),
+*tracefs_synth_append_start_filter*(3),
+*tracefs_synth_append_end_filter*(3),
+*tracefs_synth_free*(3),
+*tracefs_synth_create*(3),
+*tracefs_synth_destroy*(3),
+*tracefs_synth_complete*(3),
+*tracefs_synth_trace*(3),
+*tracefs_synth_snapshot*(3),
+*tracefs_synth_save*(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).
diff --git a/Documentation/libtracefs-synth.txt b/Documentation/libtracefs-synth.txt
new file mode 100644
index 0000000..c57725d
--- /dev/null
+++ b/Documentation/libtracefs-synth.txt
@@ -0,0 +1,368 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_synth_alloc, tracefs_synth_add_match_field, tracefs_synth_add_compare_field, tracefs_synth_add_start_field,
+tracefs_synth_add_end_field, tracefs_synth_append_start_filter, tracefs_synth_append_end_filter, tracefs_synth_free,
+- Creation of a synthetic event descriptor
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+struct tracefs_synth pass:[*]*tracefs_synth_alloc*(struct tep_handle pass:[*]_tep_,
+ const char pass:[*]_name_,
+ const char pass:[*]_start_system_,
+ const char pass:[*]_start_event_,
+ const char pass:[*]_end_system_,
+ const char pass:[*]_end_event_,
+ const char pass:[*]_start_match_field_,
+ const char pass:[*]_end_match_field_,
+ const char pass:[*]_match_name_);
+int *tracefs_synth_add_match_field*(struct tracefs_synth pass:[*]_synth_,
+ const char pass:[*]_start_match_field_,
+ const char pass:[*]_end_match_field_,
+ const char pass:[*]_name_);
+int *tracefs_synth_add_compare_field*(struct tracefs_synth pass:[*]_synth_,
+ const char pass:[*]_start_compare_field_,
+ const char pass:[*]_end_compare_field_,
+ enum tracefs_synth_calc _calc_,
+ const char pass:[*]_name_);
+int *tracefs_synth_add_start_field*(struct tracefs_synth pass:[*]_synth_,
+ const char pass:[*]_start_field_,
+ const char pass:[*]_name_);
+int *tracefs_synth_add_end_field*(struct tracefs_synth pass:[*]_synth_,
+ const char pass:[*]_end_field_,
+ const char pass:[*]_name_);
+int *tracefs_synth_append_start_filter*(struct tracefs_synth pass:[*]_synth_,
+ struct tracefs_filter _type_,
+ const char pass:[*]_field_,
+ enum tracefs_synth_compare _compare_,
+ const char pass:[*]_val_);
+int *tracefs_synth_append_end_filter*(struct tracefs_synth pass:[*]_synth_,
+ struct tracefs_filter _type_,
+ const char pass:[*]_field_,
+ enum tracefs_synth_compare _compare_,
+ const char pass:[*]_val_);
+void *tracefs_synth_free*(struct tracefs_synth pass:[*]_synth_);
+--
+
+DESCRIPTION
+-----------
+Synthetic events are dynamic events that are created by matching
+two other events which triggers a synthetic event. One event is the starting
+event which some field is recorded, and when the second event is executed,
+if it has a field (or fields) that matches the starting event's field (or fields)
+then it will trigger the synthetic event. The field values other than the matching
+fields may be passed from the starting event to the end event to perform calculations
+on, or to simply pass as a parameter to the synthetic event.
+
+One common use case is to set "sched_waking" as the starting event. This event is
+triggered when a process is awoken. Then set "sched_switch" as the ending event.
+This event is triggered when a new task is scheduled on the CPU. By setting
+the "common_pid" of both events as the matching fields, the time between the
+two events is considered the wake up latency of that process. Use *TRACEFS_TIMESTAMP*
+as a field for both events to calculate the delta in nanoseconds, or use
+*TRACEFS_TIMESTAMP_USECS" as the compare fields for both events to calculate the
+delta in microseconds. This is used as the example below.
+
+*tracefs_synth_alloc*() allocates and initializes a synthetic event.
+It does not create the synthetic event, but supplies the minimal information
+to do so. See *tracefs_synth_create*(3) for how to create the synthetic
+event in the system. It requires a _tep_ handler that can be created by
+*tracefs_local_events*(3) for more information. The _name_ holds the name
+of the synthetic event that will be created. The _start_system_ is the name
+of the system for the starting event. It may be NULL and the first event
+with the name of _start_event_ will be chosen. The _end_system_ is the
+name of the system for theh ending event. It may be NULL and the first event
+with the name of _end_event_ will be chosen as the ending event. If _match_name_
+is given, then this will be the field of the created synthetic event that
+holds the matching keys of the starting event's _start_match_field_ and
+the ending event's _end_match_field_. If _match_name_ is NULL, then it will
+not be recorded in the created synthetic event.
+
+*tracefs_synth_add_match_field*() will add a second key to match between the
+starting event and the ending event. If _name_ is given, then the content
+of the matching field will be saved by this _name_ in the synthetic event.
+The _start_match_field_ is the field of the starting event to mach with the
+ending event's _end_match_field_.
+
+*tracefs_synth_add_compare_field*() is used to compare the _start_compare_field_
+of the starting event with the _end_compare_field_ of the ending event. The _name_
+must be given so that the result will be saved by the synthetic event. It makes
+no sense to not pass this to the synthetic event after doing the work of
+the compared fields, as it serves no other purpose. The _calc_ parameter
+can be one of:
+
+*TRACEFS_SYNTH_DELTA_END* - calculate the difference between the content in
+ the _end_compare_field_ from the content of the _start_compare_field_.
+
+_name_ = _end_compare_field_ - _start_compare_field_
+
+*TRACEFS_SYNTH_DELTA_START* - calculate the difference between the content in
+ the _start_compare_field_ from the content of the _end_compare_field_.
+
+_name_ = _start_compare_field_ - _end_compare_field_
+
+*TRACEFS_SYNTH_ADD* - Add the content of the _start_compare_field_ to the
+ content of the _end_compare_field_.
+
+_name_ = _start_compare_field_ + _end_compare_field_
+
+*tracefs_synth_add_start_field*() - Records the _start_field_ of the starting
+event as _name_ in the synthetic event. If _name_ is NULL, then the name used
+will be the same as _start_field_.
+
+*tracefs_synth_add_end_field*() - Records the _end_field_ of the ending
+event as _name_ in the synthetic event. If _name_ is NULL, then the name used
+will be the same as _end_field_.
+
+*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 statements, 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_synth_append_end_filter*() is the same as *tracefs_synth_append_start_filter* but
+filters on the ending event.
+
+*tracefs_synth_free*() frees the allocated descriptor returned by
+*tracefs_synth_alloc*().
+
+RETURN VALUE
+------------
+*tracefs_synth_alloc*() returns an allocated struct tracefs_synth descriptor
+on success or NULL on error.
+
+All other functions that return an integer returns zero on success or -1
+on error.
+
+ERRORS
+------
+The following errors are for all the above calls:
+
+*EPERM* Not run as root user when required.
+
+*EINVAL* Either a parameter is not valid (NULL when it should not be)
+ or a field that is not compatible for calculations.
+
+*ENODEV* An event or one of its fields is not found.
+
+*EBADE* The fields of the start and end events are not compatible for
+ either matching or comparing.
+
+*ENOMEM* not enough memory is available.
+
+And more errors may have happened from the system calls to the system.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdlib.h>
+#include <tracefs.h>
+
+#define start_event "sched_waking"
+#define start_field "pid"
+
+#define end_event "sched_switch"
+#define end_field "next_pid"
+
+#define match_name "pid"
+
+static struct tracefs_synth *synth;
+
+static void make_event(void)
+{
+ struct tep_handle *tep;
+
+ /* Load all events from the system */
+ tep = tracefs_local_events(NULL);
+
+ /* Initialize the synthetic event */
+ synth = tracefs_synth_alloc(tep, "wakeup_lat",
+ NULL, start_event,
+ NULL, end_event,
+ start_field, end_field,
+ match_name);
+
+ /* The tep is no longer needed */
+ tep_free(tep);
+
+
+ /* Save the "prio" field as "prio" from the start event */
+ tracefs_synth_add_start_field(synth, "prio", NULL);
+
+ /* Save the "next_comm" as "comm" from the end event */
+ tracefs_synth_add_end_field(synth, "next_comm", "comm");
+
+ /* Save the "prev_prio" as "prev_prio" from the end event */
+ tracefs_synth_add_end_field(synth, "prev_prio", NULL);
+
+ /*
+ * Take a microsecond time difference between end and start
+ * and record as "delta"
+ */
+ tracefs_synth_add_compare_field(synth, TRACEFS_TIMESTAMP_USECS,
+ TRACEFS_TIMESTAMP_USECS,
+ TRACEFS_SYNTH_DELTA_END, "delta");
+
+ /* Only record if start event "prio" is less than 100 */
+ tracefs_synth_append_start_filter(synth, TRACEFS_FILTER_COMPARE,
+ "prio", TRACEFS_COMPARE_LT, "100");
+
+ /*
+ * Only record if end event "next_prio" is less than 50
+ * or the previous task's prio was not greater than or equal to 100.
+ * next_prio < 50 || !(prev_prio >= 100)
+ */
+ tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_COMPARE,
+ "next_prio", TRACEFS_COMPARE_LT, "50");
+ tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_OR, NULL, 0, NULL);
+ tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_NOT, NULL, 0, NULL);
+ tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_OPEN_PAREN, NULL, 0, NULL);
+ tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_COMPARE,
+ "prev_prio", TRACEFS_COMPARE_GE, "100");
+ /*
+ * Note, the above only added: "next_prio < 50 || !(prev_prio >= 100"
+ * That's because, when the synth is executed, the remaining close parenthesis
+ * will be added. That is, the string will end up being:
+ * "next_prio < 50 || !(prev_prio >= 100)" when one of tracefs_sync_create()
+ * or tracefs_sync_echo_cmd() is run.
+ */
+}
+
+/* Display how to create the synthetic event */
+static void show_event(void)
+{
+ struct trace_seq s;
+
+ trace_seq_init(&s);
+
+ tracefs_synth_echo_cmd(&s, synth);
+ trace_seq_terminate(&s);
+ trace_seq_do_printf(&s);
+ trace_seq_destroy(&s);
+}
+
+int main (int argc, char **argv)
+{
+ make_event();
+
+ if (argc > 1) {
+ if (!strcmp(argv[1], "create")) {
+ /* Create the synthetic event */
+ tracefs_synth_create(synth);
+ } else if (!strcmp(argv[1], "delete")) {
+ /* Delete the synthetic event */
+ tracefs_synth_destroy(synth);
+ } else {
+ printf("usage: %s [create|delete]\n", argv[0]);
+ exit(-1);
+ }
+ } else
+ show_event();
+
+ tracefs_synth_free(synth);
+
+ return 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
+--------
+*tracefs_synth_create*(3),
+*tracefs_synth_destroy*(3),
+*tracfes_synth_echo_cmd*(3),
+*libtracefs*(3),
+*libtraceevent*(3),
+*trace-cmd*(1),
+*tracefs_hist_alloc*(3),
+*tracefs_hist_alloc_2d*(3),
+*tracefs_hist_alloc_nd*(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),
+*tracefs_synth_create*(3),
+*tracefs_synth_destroy*(3),
+*tracefs_synth_complete*(3),
+*tracefs_synth_trace*(3),
+*tracefs_synth_snapshot*(3),
+*tracefs_synth_save*(3),
+*tracefs_synth_echo_cmd*(3),
+*tracefs_synth_get_start_hist*(3),
+*tracefs_synth_get_name*(3),
+*tracefs_synth_raw_fmt*(3),
+*tracefs_synth_show_event*(3),
+*tracefs_synth_show_start_hist*(3),
+*tracefs_synth_show_end_hist*(3),
+*tracefs_synth_get_event*(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).
diff --git a/Documentation/libtracefs-synth2.txt b/Documentation/libtracefs-synth2.txt
new file mode 100644
index 0000000..7e8e6cc
--- /dev/null
+++ b/Documentation/libtracefs-synth2.txt
@@ -0,0 +1,281 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_synth_create, tracefs_synth_destroy, tracefs_synth_complete,
+tracefs_synth_trace, tracefs_synth_snapshot, tracefs_synth_save
+- Creation of synthetic events
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+int *tracefs_synth_create*(struct tracefs_synth pass:[*]_synth_);
+int *tracefs_synth_destroy*(struct tracefs_synth pass:[*]_synth_);
+bool *tracefs_synth_complete*(struct tracefs_synth pass:[*]_synth_);
+
+int *tracefs_synth_trace*(struct tracefs_synth pass:[*]_synth_,
+ enum tracefs_synth_handler _type_, const char pass:[*]_var_);
+int *tracefs_synth_snapshot*(struct tracefs_synth pass:[*]_synth_,
+ enum tracefs_synth_handler _type_, const char pass:[*]_var_);
+int *tracefs_synth_save*(struct tracefs_synth pass:[*]_synth_,
+ enum tracefs_synth_handler _type_, const char pass:[*]_var_,
+ char pass:[**]_save_fields_);
+--
+
+DESCRIPTION
+-----------
+Synthetic events are dynamic events that are created by matching
+two other events which triggers a synthetic event. One event is the starting
+event which some field is recorded, and when the second event is executed,
+if it has a field (or fields) that matches the starting event's field (or fields)
+then it will trigger the synthetic event. The field values other than the matching
+fields may be passed from the starting event to the end event to perform calculations
+on, or to simply pass as a parameter to the synthetic event.
+
+One common use case is to set "sched_waking" as the starting event. This event is
+triggered when a process is awoken. Then set "sched_switch" as the ending event.
+This event is triggered when a new task is scheduled on the CPU. By setting
+the "common_pid" of both events as the matching fields, the time between the
+two events is considered the wake up latency of that process. Use *TRACEFS_TIMESTAMP*
+as a field for both events to calculate the delta in nanoseconds, or use
+*TRACEFS_TIMESTAMP_USECS* as the compare fields for both events to calculate the
+delta in microseconds. This is used as the example below.
+
+*tracefs_synth_create*() creates the synthetic event in the system. The synthetic events apply
+across all instances. A synthetic event must be created with *tracefs_synth_alloc*(3) before
+it can be created.
+
+*tracefs_synth_destroy*() destroys the synthetic event. It will attempt to stop the running of it in
+its instance (top by default), but if its running in another instance this may fail as busy.
+
+*tracefs_synth_complete*() returns true if the synthetic event _synth_ has both
+a starting and ending event.
+
+*tracefs_synth_trace*() Instead of doing just a trace on matching of the start and
+end events, do the _type_ handler where *TRACEFS_SYNTH_HANDLE_MAX* will do a trace
+when the given variable _var_ hits a new max for the matching keys. Or
+*TRACEFS_SYNTH_HANDLE_CHANGE* for when the _var_ changes. _var_ must be one of
+the _name_ elements used in *tracefs_synth_add_end_field*(3).
+
+*tracefs_synth_snapshot*() When the given variable _var_ is either a new max if
+_handler_ is *TRACEFS_SYNTH_HANDLE_MAX* or simply changed if *TRACEFS_SYNTH_HANDLE_CHANGE*
+then take a "snapshot" of the buffer. The snapshot moves the normal "trace" buffer
+into a "snapshot" buffer, that can be accessed via the "snapshot" file in the
+top level tracefs directory, or one of the instances. _var_ changes. _var_ must be one of
+the _name_ elements used in *tracefs_synth_add_end_field*(3).
+
+*tracefs_synth_save*() When the given variable _var_ is either a new max if
+_handler_ is *TRACEFS_SYNTH_HANDLE_MAX* or simpy changed if *TRACEFS_SYNTH_HANDLE_CHANGE*
+then save the given _save_fields_ list. The fields will be stored in the histogram
+"hist" file of the event that can be retrieved with *tracefs_event_file_read*(3).
+_var_ must be one of the _name_ elements used in *tracefs_synth_add_end_field*(3).
+
+RETURN VALUE
+------------
+All functions return zero on success or -1 on error.
+
+ERRORS
+------
+The following errors are for all the above calls:
+
+*EPERM* Not run as root user when required.
+
+*EINVAL* Either a parameter is not valid (NULL when it should not be)
+ or a field that is not compatible for calculations.
+
+*ENODEV* An event or one of its fields is not found.
+
+*EBADE* The fields of the start and end events are not compatible for
+ either matching or comparing.
+
+*ENOMEM* not enough memory is available.
+
+And more errors may have happened from the system calls to the system.
+
+EXAMPLE
+-------
+See *tracefs_sql*(3) for a more indepth use of some of this code.
+
+[source,c]
+--
+#include <stdlib.h>
+#include <tracefs.h>
+
+#define start_event "sched_waking"
+#define start_field "pid"
+
+#define end_event "sched_switch"
+#define end_field "next_pid"
+
+#define match_name "pid"
+
+static struct tracefs_synth *synth;
+
+static void make_event(void)
+{
+ struct tep_handle *tep;
+
+ /* Load all events from the system */
+ tep = tracefs_local_events(NULL);
+
+ /* Initialize the synthetic event */
+ synth = tracefs_synth_alloc(tep, "wakeup_lat",
+ NULL, start_event,
+ NULL, end_event,
+ start_field, end_field,
+ match_name);
+
+ /* The tep is no longer needed */
+ tep_free(tep);
+
+
+ /* Save the "prio" field as "prio" from the start event */
+ tracefs_synth_add_start_field(synth, "prio", NULL);
+
+ /* Save the "next_comm" as "comm" from the end event */
+ tracefs_synth_add_end_field(synth, "next_comm", "comm");
+
+ /* Save the "prev_prio" as "prev_prio" from the end event */
+ tracefs_synth_add_end_field(synth, "prev_prio", NULL);
+
+ /*
+ * Take a microsecond time difference between end and start
+ * and record as "delta"
+ */
+ tracefs_synth_add_compare_field(synth, TRACEFS_TIMESTAMP_USECS,
+ TRACEFS_TIMESTAMP_USECS,
+ TRACEFS_SYNTH_DELTA_END, "delta");
+
+ /* Only record if start event "prio" is less than 100 */
+ tracefs_synth_append_start_filter(synth, TRACEFS_FILTER_COMPARE,
+ "prio", TRACEFS_COMPARE_LT, "100");
+
+ /*
+ * Only record if end event "next_prio" is less than 50
+ * or the previous task's prio was not greater than or equal to 100.
+ * next_prio < 50 || !(prev_prio >= 100)
+ */
+ tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_COMPARE,
+ "next_prio", TRACEFS_COMPARE_LT, "50");
+ tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_OR, NULL, 0, NULL);
+ tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_NOT, NULL, 0, NULL);
+ tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_OPEN_PAREN, NULL, 0, NULL);
+ tracefs_synth_append_end_filter(synth, TRACEFS_FILTER_COMPARE,
+ "prev_prio", TRACEFS_COMPARE_GE, "100");
+ /*
+ * Note, the above only added: "next_prio < 50 || !(prev_prio >= 100"
+ * That's because, when the synth is executed, the remaining close parenthesis
+ * will be added. That is, the string will end up being:
+ * "next_prio < 50 || !(prev_prio >= 100)" when one of tracefs_sync_create()
+ * or tracefs_sync_echo_cmd() is run.
+ */
+}
+
+/* Display how to create the synthetic event */
+static void show_event(void)
+{
+ struct trace_seq s;
+
+ trace_seq_init(&s);
+
+ tracefs_synth_echo_cmd(&s, synth);
+ trace_seq_terminate(&s);
+ trace_seq_do_printf(&s);
+ trace_seq_destroy(&s);
+}
+
+int main (int argc, char **argv)
+{
+ make_event();
+
+ if (argc > 1) {
+ if (!strcmp(argv[1], "create")) {
+ /* Create the synthetic event */
+ tracefs_synth_create(synth);
+ } else if (!strcmp(argv[1], "delete")) {
+ /* Delete the synthetic event */
+ tracefs_synth_destroy(synth);
+ } else {
+ printf("usage: %s [create|delete]\n", argv[0]);
+ exit(-1);
+ }
+ } else
+ show_event();
+
+ tracefs_synth_free(synth);
+
+ return 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_alloc_2d*(3),
+*tracefs_hist_alloc_nd*(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),
+*tracefs_synth_alloc*(3),
+*tracefs_synth_add_match_field*(3),
+*tracefs_synth_add_compare_field*(3),
+*tracefs_synth_add_start_field*(3),
+*tracefs_synth_add_end_field*(3),
+*tracefs_synth_append_start_filter*(3),
+*tracefs_synth_append_end_filter*(3),
+*tracefs_synth_free*(3),
+*tracefs_synth_echo_cmd*(3),
+*tracefs_synth_get_start_hist*(3),
+*tracefs_synth_get_name*(3),
+*tracefs_synth_raw_fmt*(3),
+*tracefs_synth_show_event*(3),
+*tracefs_synth_show_start_hist*(3),
+*tracefs_synth_show_end_hist*(3),
+*tracefs_synth_get_event*(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).
diff --git a/Documentation/libtracefs-traceon.txt b/Documentation/libtracefs-traceon.txt
new file mode 100644
index 0000000..28c79ed
--- /dev/null
+++ b/Documentation/libtracefs-traceon.txt
@@ -0,0 +1,151 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_trace_is_on, tracefs_trace_on, tracefs_trace_off, tracefs_trace_on_get_fd,
+tracefs_trace_on_fd, tracefs_trace_off_fd - Functions to enable or disable tracing.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+int *tracefs_trace_is_on*(struct tracefs_instance pass:[*]_instance_);
+int *tracefs_trace_on*(struct tracefs_instance pass:[*]_instance_);
+int *tracefs_trace_off*(struct tracefs_instance pass:[*]_instance_);
+int *tracefs_trace_on_get_fd*(struct tracefs_instance pass:[*]_instance_);
+int *tracefs_trace_on_fd*(int _fd_);
+int *tracefs_trace_off_fd*(int _fd_);
+--
+
+DESCRIPTION
+-----------
+This set of functions can be used to check, enable or disable writing to the ring buffer in
+the given trace instance. The tracing is enabled when writing to the ring buffer is enabled.
+
+The *tracefs_trace_is_on()* function checks if tracing is enabled for the given _instance_. If
+_instance_ is NULL, the top instance is used.
+
+The *tracefs_trace_on()* and *tracefs_trace_off()* functions set the tracing in the _instance_
+to enable or disable state. If _instance_ is NULL, the top instance is used.
+
+The *tracefs_trace_on_get_fd()* function returns a file descriptor to the "tracing_on" file from
+the given _instance_. If _instance_ is NULL, the top trace instance is used. The returned descriptor
+can be used for fast enabling or disabling the tracing of the instance.
+
+The *tracefs_trace_on_fd()* and *tracefs_trace_off_fd()* functions set the tracing state to enable
+or disable using the given _fd_. This file descriptor must be opened for writing with
+*tracefs_trace_on_get_fd*(3) of the desired trace instance. These functions are faster than
+*tracefs_trace_on* and *tracefs_trace_off*.
+
+RETURN VALUE
+------------
+The *tracefs_trace_is_on()* function returns 0 if tracing is disable, 1 if it is enabled or
+-1 in case of an error.
+
+The *tracefs_trace_on_get_fd()* function returns a file descriptor to "tracing_on"
+file for reading and writing, which must be closed wuth close(). In case of an error -1 is returned.
+
+The *tracefs_trace_on()*, *tracefs_trace_off()*, *tracefs_trace_on_fd()* and
+*tracefs_trace_off_fd()* functions return -1 in case of an error or 0 otherwise.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <tracefs.h>
+
+ int ret;
+
+ ret = tracefs_trace_is_on(NULL);
+ if (ret == 0) {
+ /* Tracing is disabled in the top instance */
+ } else if (ret == 1) {
+ /* Tracing is enabled in the top instance */
+ } else {
+ /* Error getting tracing state of the top instance */
+ }
+
+ ...
+
+ if (!tracefs_trace_on(NULL)) {
+ /* Enabled tracing in the top instance */
+
+ ...
+
+ if (!tracefs_trace_off(NULL)) {
+ /* Disabled tracing in the top instance */
+ } else {
+ /* Error disabling tracing in the top instance */
+ }
+ } else {
+ /* Error enabling tracing in the top instance */
+ }
+
+ ...
+
+ int fd = tracefs_trace_on_get_fd(NULL);
+
+ if (fd < 0) {
+ /* Error opening tracing_on file */
+ }
+ ...
+ if (!tracefs_trace_on_fd(fd)) {
+ /* Enabled tracing in the top instance */
+
+ ...
+
+ if (!tracefs_trace_off_fd(fd)) {
+ /* Disabled tracing in the top instance */
+ } else {
+ /* Error disabling tracing in the top instance */
+ }
+ } else {
+ /* Error enabling tracing in the top instance */
+ }
+
+ ...
+
+ close(fd);
+--
+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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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) 2021 VMware, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).
diff --git a/Documentation/libtracefs-tracer.txt b/Documentation/libtracefs-tracer.txt
new file mode 100644
index 0000000..ea57962
--- /dev/null
+++ b/Documentation/libtracefs-tracer.txt
@@ -0,0 +1,221 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_tracer_set, tracefs_tracer_clear - Enable or disable a tracer in an instance or the top level
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+int *tracefs_tracer_set*(struct tracefs_instance pass:[*]_instance_, enum tracefs_tracers _tracer_);
+int *tracefs_tracer_set*(struct tracefs_instance pass:[*]_instance_, enum tracefs_tracers _tracer_, const char pass:[*]_name_);
+int *tracefs_tracer_clear*(struct tracefs_instance pass:[*]_instance_);
+--
+
+DESCRIPTION
+-----------
+*tracefs_tracer_set* enables a tracer in the given instance, defined by the
+_instance_ parameter. If _instance_ is NULL, then the top level instance is
+changed. If _tracer_ is set to *TRACFES_TRACER_CUSTOM* then a _name_
+string must be passed in as the third parameter, and that is written into the
+instance to enable the tracer with that name. This is useful for newer or
+custom kernels that contain tracers that are not yet identified by the
+tracefs_tracers enum.
+
+*tracefs_tracer_clear* disables the tracer for the given instance defined by
+the _instance_ variable, or the top level instance if it is NULL.
+This is the same as calling *tracefs_tracer_set* with TRACEFS_TRACER_NOP as
+the _tracer_ parameter.
+
+TRACEFS_TRACER ENUMS
+--------------------
+
+The currently defined enums that are accepted are:
+
+*TRACEFS_TRACER_NOP* :
+This is the idle tracer, which does nothing and is used to clear any
+active tracer.
+
+*TRACEFS_TRACER_FUNCTION* :
+Enables most functions in the kernel to be traced.
+
+*TRACEFS_TRACER_FUNCTION_GRAPH* :
+Enables most functions in the kernel to be traced as well as the return
+of the function.
+
+*TRACEFS_TRACER_IRQSOFF* :
+Tracers the latency of interrupts disabled.
+
+*TRACEFS_TRACER_PREEMPTOFF* :
+Tracers the latency of preemption disabled (the time in the kernel that
+tasks can not be scheduled from the CPU).
+
+*TRACEFS_TRACER_PREEMPTIRQSOFF* :
+Traces the combined total latency of when interrupts are disabled as well as when
+preemption is disabled.
+
+*TRACEFS_TRACER_WAKEUP* :
+Traces the latency of when the highest priority task takes to wake up.
+
+*TRACEFS_TRACER_WAKEUP_RT* :
+Traces the latency of when the highest priority real-time task takes to wake up.
+All other tasks are ignored.
+
+*TRACEFS_TRACER_WAKEUP_DL* :
+Traces the latency of when the highest priority DEADLINE task takes to wake up.
+All other tasks are ignored.
+
+*TRACEFS_TRACER_MMIOTRACE* :
+Traces the interaction of devices with the kernel.
+
+*TRACEFS_TRACER_HWLAT* :
+Detects latency caused by the hardware that is outside the scope of the kernel.
+
+*TRACEFS_TRACER_BRANCH* :
+Traces when likely or unlikely branches are taken.
+
+*TRACEFS_TRACER_BLOCK* :
+Special tracer for the block devices.
+
+Note that the above tracers may not be available in the kernel and
+*tracefs_tracer_set()* will return an error with errno set to ENODEV,
+if the kernel does not support the _tracer_ option, or the custom one
+if TRACEFS_TRACER_CUSTOM is used.
+
+RETURN VALUE
+------------
+Returns 0 on success, or -1 on error.
+
+ERRORS
+------
+
+*tracefs_tracer_set*() can fail with the following errors:
+
+*EINVAL* The _tracer_ parameter is outside the scope of what is defined.
+
+*ENOMEM* Memory allocation error.
+
+*ENOENT* Tracers are not supported on the running kernel.
+
+*ENODEV* The specified tracer is not supported on the running kernel.
+
+Other errors may also happen caused by internal system calls.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <errno.h>
+#include <tracefs.h>
+
+int main(int argc, char *argv[])
+{
+ struct tracefs_instance *inst = NULL;
+ enum tracefs_tracers t = TRACEFS_TRACER_NOP;
+ const char *buf = NULL;
+ const char *cust;
+ int ret;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "nfgiwdc:B:")) > 0) {
+ switch (ch) {
+ case 'f': t = TRACEFS_TRACER_FUNCTION; break;
+ case 'g': t = TRACEFS_TRACER_FUNCTION_GRAPH; break;
+ case 'i': t = TRACEFS_TRACER_PREEMPTIRQSOFF; break;
+ case 'w': t = TRACEFS_TRACER_WAKEUP_RT; break;
+ case 'd': t = TRACEFS_TRACER_WAKEUP_DL; break;
+ case 'c':
+ t = TRACEFS_TRACER_CUSTOM;
+ cust = optarg;
+ break;
+ case 'B':
+ buf = optarg;
+ break;
+ case 'n':
+ /* nop */
+ break;
+ default:
+ printf("Unknow arg %c\n", ch);
+ exit(-1);
+ }
+ }
+
+ if (buf) {
+ inst = tracefs_instance_create(buf);
+ if (!inst) {
+ printf("failed to create instance\n");
+ exit(-1);
+ }
+ }
+
+ if (t == TRACEFS_TRACER_CUSTOM)
+ ret = tracefs_tracer_set(inst, t, cust);
+ else
+ ret = tracefs_tracer_set(inst, t);
+
+ if (ret < 0) {
+ if (inst) {
+ tracefs_instance_destroy(inst);
+ tracefs_instance_free(inst);
+ }
+ if (errno == ENODEV)
+ printf("Tracer not supported by kernel\n");
+ else
+ perror("Error");
+ exit(-1);
+ }
+
+ if (inst)
+ tracefs_instance_free(inst);
+
+ 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)
+
+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).
diff --git a/Documentation/libtracefs-uprobes.txt b/Documentation/libtracefs-uprobes.txt
new file mode 100644
index 0000000..1ca80da
--- /dev/null
+++ b/Documentation/libtracefs-uprobes.txt
@@ -0,0 +1,189 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_uprobe_alloc,tracefs_uretprobe_alloc - Allocate new user (return) probe
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+struct tracefs_dynevent pass:[*]
+*tracefs_uprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_file_, unsigned long long _offset_, const char pass:[*]_fetchargs_)
+struct tracefs_dynevent pass:[*]
+*tracefs_uretprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_file_, unsigned long long _offset_, const char pass:[*]_fetchargs_)
+--
+
+DESCRIPTION
+-----------
+*tracefs_uprobe_alloc*() allocates a new uprobe context. It will be in the _system_ group
+(or uprobes if _system_ is NULL) and with _event_ name. The uprobe will be attached to _offset_
+within the _file_. The list of arguments, described in _fetchargs_, will be fetched with the uprobe.
+The returned pointer to the user probe context must be freed with *tracefs_dynevent_free*().
+The ubrobe is not configured in the system, tracefs_dynevent_* set of APIs can be used to configure
+it.
+
+The *tracefs_uretprobe_alloc*() behaves the same as *tracefs_uprobe_alloc*(), the only difference is
+that it allocates context to user return probe (uretprobe).
+
+RETURN VALUE
+------------
+The *tracefs_uprobe_alloc*() and *tracefs_uretprobe_alloc*() APIs return a pointer to an allocated
+tracefs_dynevent structure, describing the user probe. This pointer must be freed with
+*tracefs_dynevent_free*(3). Note, this only allocates a descriptor representing the uprobe. It does
+not modify the running system. On error NULL is returned.
+
+EXAMPLE
+-------
+[source,c]
+--
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include <tracefs.h>
+
+static int callback(struct tep_event *event, struct tep_record *record,
+ int cpu, void *data)
+{
+ struct trace_seq seq;
+
+ trace_seq_init(&seq);
+ tep_print_event(event->tep, &seq, record, "%d-%s: %s",
+ TEP_PRINT_PID, TEP_PRINT_COMM, TEP_PRINT_NAME);
+ trace_seq_puts(&seq, "'\n");
+
+ trace_seq_terminate(&seq);
+ trace_seq_do_printf(&seq);
+ trace_seq_destroy(&seq);
+
+ return 0;
+}
+
+static pid_t run_exec(char **argv, char **env)
+{
+ pid_t pid;
+
+ pid = fork();
+ if (pid)
+ return pid;
+
+ execve(argv[0], argv, env);
+ perror("exec");
+ exit(-1);
+}
+
+const char *myprobe = "my_urobes";
+
+int main (int argc, char **argv, char **env)
+{
+ struct tracefs_dynevent *uprobe, *uretprobe;
+ struct tep_handle *tep;
+ struct tracefs_instance *instance;
+ const char *sysnames[] = { myprobe, NULL };
+ long addr;
+ pid_t pid;
+
+ if (argc < 3) {
+ printf("usage: %s file_offset command\n", argv[0]);
+ exit(-1);
+ }
+ addr = strtol(argv[1], NULL, 0);
+
+ instance = tracefs_instance_create("exec_open");
+ if (!instance) {
+ perror("creating instance");
+ exit(-1);
+ }
+
+ tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_UPROBE|TRACEFS_DYNEVENT_URETPROBE, true);
+
+ uprobe = tracefs_uprobe_alloc(myprobe, "user_probe", argv[2], addr, NULL);
+ uretprobe = tracefs_uretprobe_alloc(myprobe, "user_retprobe", argv[2], addr, NULL);
+ if (!uprobe || !uretprobe) {
+ perror("allocating user probes");
+ exit(-1);
+ }
+
+ if (tracefs_dynevent_create(uprobe) ||
+ tracefs_dynevent_create(uretprobe)) {
+ perror("creating user probes");
+ exit(-1);
+ }
+
+ tep = tracefs_local_events_system(NULL, sysnames);
+ if (!tep) {
+ perror("reading events");
+ exit(-1);
+ }
+
+ tracefs_event_enable(instance, myprobe, "user_probe");
+ tracefs_event_enable(instance, myprobe, "user_retprobe");
+
+ pid = run_exec(&argv[2], env);
+
+ /* Let the child start to run */
+ sched_yield();
+
+ do {
+ tracefs_load_cmdlines(NULL, tep);
+ tracefs_iterate_raw_events(tep, instance, NULL, 0, callback, NULL);
+ } while (waitpid(pid, NULL, WNOHANG) != pid);
+
+ /* disable and destroy the events */
+ tracefs_dynevent_destroy(uprobe, true);
+ tracefs_dynevent_destroy(uretprobe, true);
+ tracefs_dynevent_free(uprobe);
+ tracefs_dynevent_free(uretprobe);
+ tracefs_instance_destroy(instance);
+
+ return 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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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) 2022 VMware, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).
diff --git a/Documentation/libtracefs-utils.txt b/Documentation/libtracefs-utils.txt
new file mode 100644
index 0000000..ab16cc6
--- /dev/null
+++ b/Documentation/libtracefs-utils.txt
@@ -0,0 +1,139 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_tracers, tracefs_tracer_available, tracefs_get_clock, tracefs_list_free,
+tracefs_list_add, tracefs_list_size - Helper functions for working with trace file system.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+char pass:[*]pass:[*]*tracefs_tracers*(const char pass:[*]_tracing_dir_);
+bool *tracefs_tracer_available*(const char pass:[*]_tracing_dir_, const char pass:[*]_tracer_);
+char pass:[*]*tracefs_get_clock*(struct tracefs_instance pass:[*]_instance_);
+void *tracefs_list_free*(char pass:[*]pass:[*]_list_);
+char pass:[**]*tracefs_list_add*(char **_list_, const char *_string_);
+int *tracefs_list_size*(char pass:[**]_list_);
+--
+
+DESCRIPTION
+-----------
+Various useful functions for working with trace file system.
+
+The *tracefs_tracers()* function returns array of strings with the
+names of supported tracer plugins, located in the given _tracing_dir_
+directory. This could be NULL or the location of the tracefs mount point
+for the trace systems of the local machine, or it may be a path to a copy
+of the tracefs directory from another machine. The last entry in the array
+as a NULL pointer. The array must be freed with *tracefs_list_free()* API.
+
+The *tracefs_tracer_available()* returns true if the _tracer_ is available
+in the given _tracing_dir_director_, and false otherwise.
+
+The *tracefs_get_clock()* function returns name of the current trace clock,
+used in the given _instance_. If _instance_ is NULL, the clock of the main
+trace instance is returned. The returned string must be freed with free().
+
+The *tracefs_list_free()* function frees an array of strings, returned by
+*tracefs_event_systems()*, *tracefs_system_events()* and *tracefs_tracers()*
+APIs.
+
+The *tracefs_list_add()* function adds _string_ to the string _list_. If
+_list_ is NULL, then a new list is created with the first element a copy
+of _string_, and the second element will be a NULL pointer. If _list_ is
+not NULL, then it is reallocated to include a new element and a NULL terminator,
+and the new allocated array is returned. The list passed in should be ignored,
+as it wil be freed if a new one was allocated.
+
+The *tracefs_list_size()* is a fast way to find out the number of elements
+in a string array that is to be freed with *tracefs_list_free()*. Note, this
+depends on meta data that is created for these lists and will not work on
+normal string arrays like argv.
+
+RETURN VALUE
+------------
+The *tracefs_tracers()* returns array of strings. The last element in that
+array is a NULL pointer. The array must be freed with *tracefs_list_free()* API.
+In case of an error, NULL is returned.
+
+The *tracefs_tracer_available()* returns true if the _tracer_ is available,
+and false otherwise.
+
+The *tracefs_get_clock()* returns string, that must be freed with free(), or NULL
+in case of an error.
+
+The *tracefs_list_add()* returns an allocated string array that must be freed
+with *tracefs_list_free()* on success or NULL on error. If NULL is returned,
+then the passed in _list_ is untouched. Thus, *tracefs_list_add()* should be
+treated similarly to *realloc*(3).
+
+The *tracefs_list_size()* returns the number of strings in the _list_. The
+passed in list must be one that is to be freed with *tracefs_list_free()*
+as the list has meta data that is used to determine the size and this does
+not work on any normal string array like argv.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <tracefs.h>
+
+char **tracers = tracefs_tracers(NULL);
+
+ if (tracers) {
+ /* Got tracer plugins from the top trace instance */
+ ...
+ tracefs_list_free(tracers);
+ }
+....
+char *clock = tracefs_get_clock(NULL);
+
+ if (clock) {
+ /* Got current trace clock of the top trace instance */
+ ...
+ free(clock);
+ }
+--
+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)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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).
diff --git a/Documentation/libtracefs.txt b/Documentation/libtracefs.txt
new file mode 100644
index 0000000..c3f448d
--- /dev/null
+++ b/Documentation/libtracefs.txt
@@ -0,0 +1,344 @@
+libtracefs(3)
+=============
+
+NAME
+----
+libtracefs - Linux kernel trace file system library
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+Locations of tracing files and directories:
+ char pass:[*]*tracefs_get_tracing_file*(const char pass:[*]_name_);
+ void *tracefs_put_tracing_file*(char pass:[*]_name_);
+ const char pass:[*]*tracefs_tracing_dir*(void);
+ const char pass:[*]*tracefs_debug_dir*(void);
+ int *tracefs_set_tracing_dir*(char pass:[*]_tracing_dir_)
+ int *tracefs_tracing_dir_is_mounted*(bool _mount_, const char pass:[**]_path_);
+
+Trace instances:
+ struct tracefs_instance pass:[*]*tracefs_instance_create*(const char pass:[*]_name_);
+ int *tracefs_instance_destroy*(struct tracefs_instance pass:[*]_instance_);
+ struct tracefs_instance pass:[*]*tracefs_instance_alloc*(const char pass:[*]_tracing_dir_, const char pass:[*]_name_);
+ void *tracefs_instance_free*(struct tracefs_instance pass:[*]_instance_);
+ char pass:[**]*tracefs_instances*(const char pass:[*]_regex_);
+ bool *tracefs_instance_is_new*(struct tracefs_instance pass:[*]_instance_);
+ bool *tracefs_file_exists*(struct tracefs_instance pass:[*]_instance_, char pass:[*]_name_);
+ bool *tracefs_dir_exists*(struct tracefs_instance pass:[*]_instance_, char pass:[*]_name_);
+ char pass:[*]*tracefs_instance_get_file*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_file_);
+ char pass:[*]*tracefs_instance_get_dir*(struct tracefs_instance pass:[*]_instance_);
+ int *tracefs_instance_file_open*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_file_, int _mode_);
+ int *tracefs_instance_file_write*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_file_, const char pass:[*]_str_);
+ int *tracefs_instance_file_append*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_file_, const char pass:[*]_str_);
+ int *tracefs_instance_file_clear*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_file_);
+ char pass:[*]*tracefs_instance_file_read*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_file_, int pass:[*]_psize_);
+ int *tracefs_instance_file_read_number*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_file_, long long int pass:[*]_res_);
+ const char pass:[*]*tracefs_instance_get_name*(struct tracefs_instance pass:[*]_instance_);
+ const char pass:[*]*tracefs_instance_get_trace_dir*(struct tracefs_instance pass:[*]_instance_);
+ int *tracefs_instances_walk*(int (pass:[*]_callback_)(const char pass:[*], void pass:[*]), void pass:[*]_context)_;
+ bool *tracefs_instance_exists*(const char pass:[*]_name_);
+ int *tracefs_instance_set_affinity*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_cpu_str_);
+ int *tracefs_instance_set_affinity_set*(struct tracefs_instance pass:[*]_instance_, cpu_set_t pass:[*]_set_, size_t _set_size_);
+ int *tracefs_instance_set_affinity_raw*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_mask_);
+ char pass:[*]*tracefs_instance_get_affinity*(struct tracefs_instance pass:[*]_instance_);
+ int *tracefs_instance_get_affinity_set*(struct tracefs_instance pass:[*]_instance_, cpu_set_t pass:[*]_set_, size_t _set_size_);
+ char pass:[*]*tracefs_instance_get_affinity_raw*(struct tracefs_instance pass:[*]_instance_);
+ size_t *tracefs_instance_get_buffer_size*(struct tracefs_instance pass:[*]_instance_, int _cpu_);
+ int *tracefs_instance_set_buffer_size*(struct tracefs_instance pass:[*]_instance_, size_t _size_, int _cpu_);
+
+Trace events:
+ char pass:[*]pass:[*]*tracefs_event_systems*(const char pass:[*]_tracing_dir_);
+ char pass:[*]pass:[*]*tracefs_system_events*(const char pass:[*]_tracing_dir_, const char pass:[*]_system_);
+ int *tracefs_event_enable*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_system_,
+ const char pass:[*]_event_);
+ int *tracefs_event_disable*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_system_,
+ const char pass:[*]_event_);
+ enum tracefs_enable_state *tracefs_event_is_enabled*(struct tracefs_instance pass:[*]_instance_,
+ const char pass:[*]_system_, const char pass:[*]_event_);
+ int *tracefs_iterate_raw_events*(struct tep_handle pass:[*]_tep_, struct tracefs_instance pass:[*]_instance_, cpu_set_t pass:[*]_cpus_, int _cpu_size_, int (pass:[*]_callback_)(struct tep_event pass:[*], struct tep_record pass:[*], int, void pass:[*]), void pass:[*]_callback_context_);
+ void *tracefs_iterate_stop*(struct tracefs_instance pass:[*]_instance_);
+ int *tracefs_follow_event*(struct tep_handle pass:[*]_tep_, struct tracefs_instance pass:[*]_instance_,
+ const char pass:[*]_system_, const char pass:[*]_event_name_,
+ int (pass:[*]_callback_)(struct tep_event pass:[*],
+ struct tep_record pass:[*],
+ int, void pass:[*]),
+ void pass:[*]_callback_data_);
+ int *tracefs_follow_missed_events*(struct tracefs_instance pass:[*]_instance_,
+ int (pass:[*]_callback_)(struct tep_event pass:[*],
+ struct tep_record pass:[*],
+ int, void pass:[*]),
+ void pass:[*]_callback_data_);
+ struct tep_handle pass:[*]*tracefs_local_events*(const char pass:[*]_tracing_dir_);
+ struct tep_handle pass:[*]*tracefs_local_events_system*(const char pass:[*]_tracing_dir_, const char pass:[*] const pass:[*]_sys_names_);
+ int *tracefs_fill_local_events*(const char pass:[*]_tracing_dir_, struct tep_handle pass:[*]_tep_, int pass:[*]_parsing_failures_);
+ int *tracefs_load_cmdlines*(const char pass:[*]_tracing_dir_, struct tep_handle pass:[*]_tep_);
+ char pass:[*]*tracefs_event_get_file*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_file_);
+ char pass:[*]*tracefs_event_file_read*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_file_, int pass:[*]_psize_);
+ int *tracefs_event_file_write*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_file_, const char pass:[*]_str_);
+ int *tracefs_event_file_append*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_file_, const char pass:[*]_str_);
+ int *tracefs_event_file_clear*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_file_);
+ bool *tracefs_event_file_exists*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_system_, const char pass:[*]_event_,
+
+Event filters:
+ int *tracefs_filter_string_append*(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_filter_string_verify*(struct tep_event pass:[*]_event_, const char pass:[*]_filter_, char pass:[**]_err_);
+ int *tracefs_event_filter_apply*(struct tracefs_instance pass:[*]_instance_, struct tep_event pass:[*]_event_, const char pass:[*]_filter_);
+ int *tracefs_event_filter_clear*(struct tracefs_instance pass:[*]_instance_, struct tep_event pass:[*]_event_);
+
+Function filters:
+ 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_);
+
+Trace helper functions:
+ void *tracefs_list_free*(char pass:[*]pass:[*]_list_);
+ char pass:[**]*tracefs_list_add*(char **_list_, const char *_string_);
+ int *tracefs_list_size*(char pass:[**]_list_);
+ char pass:[*]*tracefs_get_clock*(struct tracefs_instance pass:[*]_instance_);
+ int *tracefs_trace_is_on*(struct tracefs_instance pass:[*]_instance_);
+ int *tracefs_trace_on*(struct tracefs_instance pass:[*]_instance_);
+ int *tracefs_trace_off*(struct tracefs_instance pass:[*]_instance_);
+ int *tracefs_trace_on_get_fd*(struct tracefs_instance pass:[*]_instance_);
+ int *tracefs_trace_on_fd*(int _fd_);
+ int *tracefs_trace_off_fd*(int _fd_);
+
+Trace stream:
+ ssize_t *tracefs_trace_pipe_stream*(int _fd_, struct tracefs_instance pass:[*]_instance_, int _flags_);
+ ssize_t *tracefs_trace_pipe_print*(struct tracefs_instance pass:[*]_instance_, int _flags_);
+ void *tracefs_trace_pipe_stop*(struct tracefs_instance pass:[*]_instance_);
+
+Trace options:
+ const struct tracefs_options_mask pass:[*]*tracefs_options_get_supported*(struct tracefs_instance pass:[*]_instance_);
+ bool *tracefs_option_is_supported*(struct tracefs_instance pass:[*]_instance_, enum tracefs_option_id _id_);
+ const struct tracefs_options_mask pass:[*]*tracefs_options_get_enabled*(struct tracefs_instance pass:[*]_instance_);
+ bool *tracefs_option_is_enabled*(struct tracefs_instance pass:[*]_instance_, enum tracefs_option_id _id_);
+ bool *tracefs_option_mask_is_set*(const struct tracefs_options_mask *options, enum tracefs_option_id id);
+ int *tracefs_option_enable*(struct tracefs_instance pass:[*]_instance_, enum tracefs_option_id _id_);
+ int *tracefs_option_disable*(struct tracefs_instance pass:[*]_instance_, enum tracefs_option_id _id_);
+ const char pass:[*]*tracefs_option_name*(enum tracefs_option_id _id_);
+ enum tracefs_option_id *tracefs_option_id*(const char pass:[*]_name_);
+
+Ftrace tracers:
+ char pass:[*]pass:[*]*tracefs_tracers*(const char pass:[*]_tracing_dir_);
+ bool *tracefs_tracer_available*(const char pass:[*]_tracing_dir_, const char pass:[*]_tracer_);
+ int *tracefs_tracer_set*(struct tracefs_instance pass:[*]_instance_, enum tracefs_tracers _tracer_);
+ int *tracefs_tracer_set*(struct tracefs_instance pass:[*]_instance_, enum tracefs_tracers _tracer_, const char pass:[*]_name_);
+ int *tracefs_tracer_clear*(struct tracefs_instance pass:[*]_instance_);
+
+Writing data in the trace buffer:
+ int *tracefs_print_init*(struct tracefs_instance pass:[*]_instance_);
+ int *tracefs_printf*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_fmt_, _..._);
+ int *tracefs_vprintf*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_fmt_, va_list _ap_);
+ void *tracefs_print_close*(struct tracefs_instance pass:[*]_instance_);
+ int *tracefs_binary_init*(struct tracefs_instance pass:[*]_instance_);
+ int *tracefs_binary_write*(struct tracefs_instance pass:[*]_instance_, void pass:[*]_data_, int _len_);
+ void *tracefs_binary_close*(struct tracefs_instance pass:[*]_instance_);
+
+Control library logs:
+ int *tracefs_set_loglevel*(enum tep_loglevel _level_);
+
+Dynamic event generic APIs:
+ struct *tracefs_dynevent*;
+ enum *tracefs_dynevent_type*;
+ int *tracefs_dynevent_create*(struct tracefs_dynevent pass:[*]_devent_);
+ int *tracefs_dynevent_destroy*(struct tracefs_dynevent pass:[*]_devent_, bool _force_);
+ int *tracefs_dynevent_destroy_all*(unsigned int _types_, bool _force_);
+ void *tracefs_dynevent_free*(struct tracefs_dynevent pass:[*]_devent_);
+ void *tracefs_dynevent_list_free*(struct tracefs_dynevent pass:[*]pass:[*]_events_);
+ struct tracefs_dynevent pass:[*]*tracefs_dynevent_get*(enum tracefs_dynevent_type _type_, const char pass:[*]_system_, const char pass:[*]_event_);
+ struct tracefs_dynevent pass:[*]pass:[*]*tracefs_dynevent_get_all*(unsigned int _types_, const char pass:[*]_system_);
+ enum tracefs_dynevent_type *tracefs_dynevent_info*(struct tracefs_dynevent pass:[*]_dynevent_, char pass:[*]pass:[*]_system_, char pass:[*]pass:[*]_event_, char pass:[*]pass:[*]_prefix_, char pass:[*]pass:[*]_addr_, char pass:[*]pass:[*]_format_);
+ struct tep_event pass:[*]*tracefs_dynevent_get_event*(struct tep_handle pass:[*]_tep_, struct tracefs_dynevent pass:[*]_dynevent_);
+
+Even probes (eprobes):
+ struct tracefs_dynevent pass:[*] *tracefs_eprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_, const char pass:[*]_target_system_, const char pass:[*]_target_event_, const char pass:[*]_fetchargs_);
+
+Uprobes, Kprobes and Kretprobes:
+ struct tracefs_dynevent pass:[*] *tracefs_kprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_, const char pass:[*]_addr_, const char pass:[*]_format_);
+ struct tracefs_dynevent pass:[*] *tracefs_kretprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_, const char pass:[*]_addr_, const char pass:[*]_format_, unsigned int _max_);
+ int *tracefs_kprobe_raw*(const char pass:[*]_system_, const char pass:[*]_event_, const char pass:[*]_addr_, const char pass:[*]_format_);
+ int *tracefs_kretprobe_raw*(const char pass:[*]_system_, const char pass:[*]_event_, const char pass:[*]_addr_, const char pass:[*]_format_);
+ *tracefs_uprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_file_, unsigned long long _offset_, const char pass:[*]_fetchargs_)
+ *tracefs_uretprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_file_, unsigned long long _offset_, const char pass:[*]_fetchargs_);
+
+Synthetic events:
+ struct tracefs_synth pass:[*]*tracefs_sql*(struct tep_handle pass:[*]_tep_, const char pass:[*]_name_,
+ const char pass:[*]_sql_buffer_, char pass:[**]_err_);
+ struct tracefs_synth pass:[*]*tracefs_synth_alloc*(struct tep_handle pass:[*]_tep_,
+ const char pass:[*]_name_,
+ const char pass:[*]_start_system_,
+ const char pass:[*]_start_event_,
+ const char pass:[*]_end_system_,
+ const char pass:[*]_end_event_,
+ const char pass:[*]_start_match_field_,
+ const char pass:[*]_end_match_field_,
+ const char pass:[*]_match_name_);
+ int *tracefs_synth_add_match_field*(struct tracefs_synth pass:[*]_synth_,
+ const char pass:[*]_start_match_field_,
+ const char pass:[*]_end_match_field_,
+ const char pass:[*]_name_);
+ int *tracefs_synth_add_compare_field*(struct tracefs_synth pass:[*]_synth_,
+ const char pass:[*]_start_compare_field_,
+ const char pass:[*]_end_compare_field_,
+ enum tracefs_synth_calc _calc_,
+ const char pass:[*]_name_);
+ int *tracefs_synth_add_start_field*(struct tracefs_synth pass:[*]_synth_,
+ const char pass:[*]_start_field_,
+ const char pass:[*]_name_);
+ int *tracefs_synth_add_end_field*(struct tracefs_synth pass:[*]_synth_,
+ const char pass:[*]_end_field_,
+ const char pass:[*]_name_);
+ int *tracefs_synth_append_start_filter*(struct tracefs_synth pass:[*]_synth_,
+ struct tracefs_filter _type_,
+ const char pass:[*]_field_,
+ enum tracefs_synth_compare _compare_,
+ const char pass:[*]_val_);
+ int *tracefs_synth_append_end_filter*(struct tracefs_synth pass:[*]_synth_,
+ struct tracefs_filter _type_,
+ const char pass:[*]_field_,
+ enum tracefs_synth_compare _compare_,
+ const char pass:[*]_val_);
+ void *tracefs_synth_free*(struct tracefs_synth pass:[*]_synth_);
+ int *tracefs_synth_create*(struct tracefs_synth pass:[*]_synth_);
+ int *tracefs_synth_destroy*(struct tracefs_synth pass:[*]_synth_);
+ int *tracefs_synth_echo_cmd*(struct trace_seq pass:[*]_seq_, struct tracefs_synth pass:[*]_synth_);
+ bool *tracefs_synth_complete*(struct tracefs_synth pass:[*]_synth_);
+ struct tracefs_hist pass:[*]*tracefs_synth_get_start_hist*(struct tracefs_synth pass:[*]_synth_);
+ int *tracefs_synth_trace*(struct tracefs_synth pass:[*]_synth_,
+ enum tracefs_synth_handler _type_, const char pass:[*]_var_);
+ int *tracefs_synth_snapshot*(struct tracefs_synth pass:[*]_synth_,
+ enum tracefs_synth_handler _type_, const char pass:[*]_var_);
+ int *tracefs_synth_save*(struct tracefs_synth pass:[*]_synth_,
+ enum tracefs_synth_handler _type_, const char pass:[*]_var_,
+ char pass:[**]_save_fields_);
+ const char pass:[*]*tracefs_synth_get_name*(struct tracefs_synth pass:[*]_synth_);
+ int *tracefs_synth_raw_fmt*(struct trace_seq pass:[*]_seq_, struct tracefs_synth pass:[*]_synth_);
+ const char pass:[*]*tracefs_synth_show_event*(struct tracefs_synth pass:[*]_synth_);
+ const char pass:[*]*tracefs_synth_show_start_hist*(struct tracefs_synth pass:[*]_synth_);
+ const char pass:[*]*tracefs_synth_show_end_hist*(struct tracefs_synth pass:[*]_synth_);
+ struct tep_event pass:[*]*tracefs_synth_get_event*(struct tep_handle pass:[*]_tep_, struct tracefs_synth pass:[*]_synth_);
+
+Ftrace errors reporting:
+ char pass:[*]*tracefs_error_last*(struct tracefs_instance pass:[*]_instance_);
+ char pass:[*]*tracefs_error_all*(struct tracefs_instance pass:[*]_instance_);
+ int *tracefs_error_clear*(struct tracefs_instance pass:[*]_instance_);
+
+Histograms:
+ struct tracefs_hist pass:[*]*tracefs_hist_alloc*(struct tracefs_tep pass:[*] _tep_,
+ const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_key_, enum tracefs_hist_key_type _type_);
+ struct tracefs_hist pass:[*]*tracefs_hist_alloc_2d*(struct tracefs_tep pass:[*] _tep_,
+ const char pass:[*]_system_, const char pass:[*]_event_,
+ const char pass:[*]_key1_, enum tracefs_hist_key_type _type1_,
+ const char pass:[*]_key2_, enum tracefs_hist_key_type _type2_));
+ struct tracefs_hist pass:[*]*tracefs_hist_alloc_nd*(struct tracefs_tep pass:[*] _tep_,
+ const char pass:[*]_system_, const char pass:[*]_event_,
+ struct tracefs_hist_axis pass:[*]_axes_);
+ struct tracefs_hist pass:[*]*tracefs_hist_alloc_nd_cnt*(struct tep_handle pass:[*]_tep_,
+ const char pass:[*]_system_, const char pass:[*]_event_name_,
+ struct tracefs_hist_axis_cnt pass:[*]_axes_);
+ void *tracefs_hist_free*(struct tracefs_hist pass:[*]_hist_);
+ int *tracefs_hist_add_key*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_key_,
+ enum tracefs_hist_key_type _type_);
+ int *tracefs_hist_add_key_cnt*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_key_,
+ enum tracefs_hist_key_type _type_, int _cnt_);
+ int *tracefs_hist_add_value*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_value_);
+ int *tracefs_hist_add_sort_key*(struct tracefs_hist pass:[*]_hist_,
+ const char pass:[*]_sort_key_);
+ int *tracefs_hist_set_sort_key*(struct tracefs_hist pass:[*]_hist_,
+ const char pass:[*]_sort_key_, _..._);
+ int *tracefs_hist_sort_key_direction*(struct tracefs_hist pass:[*]_hist_,
+ const char pass:[*]_sort_key_,
+ enum tracefs_hist_sort_direction _dir_);
+ int *tracefs_hist_add_name*(struct tracefs_hist pass:[*]_hist_, const char pass:[*]_name_);
+ int *tracefs_hist_append_filter*(struct tracefs_hist pass:[*]_hist_,
+ enum tracefs_filter _type_,
+ const char pass:[*]_field_,
+ enum tracefs_compare _compare_,
+ const char pass:[*]_val_);
+ int *tracefs_hist_echo_cmd*(struct trace_seq pass:[*]_s_, struct tracefs_instance pass:[*]_instance_,
+ struct tracefs_hist pass:[*]_hist_,
+ enum tracefs_hist_command _command_);
+ int *tracefs_hist_command*(struct tracefs_instance pass:[*]_instance_,
+ struct tracefs_hist pass:[*]_hist_,
+ enum tracefs_hist_command _command_);
+ const char pass:[*]*tracefs_hist_get_name*(struct tracefs_hist pass:[*]_hist_);
+ const char pass:[*]*tracefs_hist_get_event*(struct tracefs_hist pass:[*]_hist_);
+ const char pass:[*]*tracefs_hist_get_system*(struct tracefs_hist pass:[*]_hist_);
+ int *tracefs_hist_start*(struct tracefs_instance pass:[*]_instance_, struct tracefs_hist pass:[*]_hist_);
+ int *tracefs_hist_destroy*(struct tracefs_instance pass:[*]_instance_, struct tracefs_hist pass:[*]_hist_);
+ int *tracefs_hist_pause*(struct tracefs_instance pass:[*]_instance_, struct tracefs_hist pass:[*]_hist_);
+ int *tracefs_hist_continue*(struct tracefs_instance pass:[*]_instance_, struct tracefs_hist pass:[*]_hist_);
+ int *tracefs_hist_reset*(struct tracefs_instance pass:[*]_instance_, struct tracefs_hist pass:[*]_hist_);
+
+Recording of trace_pipe_raw files:
+ struct tracefs_cpu pass:[*]*tracefs_cpu_open*(struct tracefs_instance pass:[*]_instance_,
+ int _cpu_, bool _nonblock_);
+ struct tracefs_cpu pass:[*]*tracefs_cpu_alloc_fd*(int _fd_, int _subbuf_size_, bool _nonblock_);
+ void *tracefs_cpu_close*(struct tracefs_cpu pass:[*]_tcpu_);
+ void *tracefs_cpu_free_fd*(struct tracefs_cpu pass:[*]_tcpu_);
+ int *tracefs_cpu_read_size*(struct tracefs_cpu pass:[*]_tcpu_);
+ int *tracefs_cpu_read*(struct tracefs_cpu pass:[*]_tcpu_, void pass:[*]_buffer_, bool _nonblock_);
+ int *tracefs_cpu_buffered_read*(struct tracefs_cpu pass:[*]_tcpu_, void pass:[*]_buffer_, bool _nonblock_);
+ int *tracefs_cpu_write*(struct tracefs_cpu pass:[*]_tcpu_, int _wfd_, bool _nonblock_);
+ int *tracefs_cpu_stop*(struct tracefs_cpu pass:[*]_tcpu_);
+ int *tracefs_cpu_flush*(struct tracefs_cpu pass:[*]_tcpu_, void pass:[*]_buffer_);
+ int *tracefs_cpu_flush_write*(struct tracefs_cpu pass:[*]_tcpu_, int _wfd_);
+ int *tracefs_cpu_pipe*(struct tracefs_cpu pass:[*]_tcpu_, int _wfd_, bool _nonblock_);
+
+--
+
+DESCRIPTION
+-----------
+The libtracefs(3) library provides APIs to access kernel trace file system.
+
+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
+--------
+*libtraceevent*(3),
+*trace-cmd*(1)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@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).
diff --git a/Documentation/manpage-1.72.xsl b/Documentation/manpage-1.72.xsl
new file mode 100644
index 0000000..b4d315c
--- /dev/null
+++ b/Documentation/manpage-1.72.xsl
@@ -0,0 +1,14 @@
+<!-- manpage-1.72.xsl:
+ special settings for manpages rendered from asciidoc+docbook
+ handles peculiarities in docbook-xsl 1.72.0 -->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0">
+
+<xsl:import href="manpage-base.xsl"/>
+
+<!-- these are the special values for the roff control characters
+ needed for docbook-xsl 1.72.0 -->
+<xsl:param name="git.docbook.backslash">&#x2593;</xsl:param>
+<xsl:param name="git.docbook.dot" >&#x2302;</xsl:param>
+
+</xsl:stylesheet>
diff --git a/Documentation/manpage-base.xsl b/Documentation/manpage-base.xsl
new file mode 100644
index 0000000..a264fa6
--- /dev/null
+++ b/Documentation/manpage-base.xsl
@@ -0,0 +1,35 @@
+<!-- manpage-base.xsl:
+ special formatting for manpages rendered from asciidoc+docbook -->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0">
+
+<!-- these params silence some output from xmlto -->
+<xsl:param name="man.output.quietly" select="1"/>
+<xsl:param name="refentry.meta.get.quietly" select="1"/>
+
+<!-- convert asciidoc callouts to man page format;
+ git.docbook.backslash and git.docbook.dot params
+ must be supplied by another XSL file or other means -->
+<xsl:template match="co">
+ <xsl:value-of select="concat(
+ $git.docbook.backslash,'fB(',
+ substring-after(@id,'-'),')',
+ $git.docbook.backslash,'fR')"/>
+</xsl:template>
+<xsl:template match="calloutlist">
+ <xsl:value-of select="$git.docbook.dot"/>
+ <xsl:text>sp&#10;</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>&#10;</xsl:text>
+</xsl:template>
+<xsl:template match="callout">
+ <xsl:value-of select="concat(
+ $git.docbook.backslash,'fB',
+ substring-after(@arearefs,'-'),
+ '. ',$git.docbook.backslash,'fR')"/>
+ <xsl:apply-templates/>
+ <xsl:value-of select="$git.docbook.dot"/>
+ <xsl:text>br&#10;</xsl:text>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/Documentation/manpage-bold-literal.xsl b/Documentation/manpage-bold-literal.xsl
new file mode 100644
index 0000000..608eb5d
--- /dev/null
+++ b/Documentation/manpage-bold-literal.xsl
@@ -0,0 +1,17 @@
+<!-- manpage-bold-literal.xsl:
+ special formatting for manpages rendered from asciidoc+docbook -->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0">
+
+<!-- render literal text as bold (instead of plain or monospace);
+ this makes literal text easier to distinguish in manpages
+ viewed on a tty -->
+<xsl:template match="literal">
+ <xsl:value-of select="$git.docbook.backslash"/>
+ <xsl:text>fB</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:value-of select="$git.docbook.backslash"/>
+ <xsl:text>fR</xsl:text>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/Documentation/manpage-normal.xsl b/Documentation/manpage-normal.xsl
new file mode 100644
index 0000000..a48f5b1
--- /dev/null
+++ b/Documentation/manpage-normal.xsl
@@ -0,0 +1,13 @@
+<!-- manpage-normal.xsl:
+ special settings for manpages rendered from asciidoc+docbook
+ handles anything we want to keep away from docbook-xsl 1.72.0 -->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0">
+
+<xsl:import href="manpage-base.xsl"/>
+
+<!-- these are the normal values for the roff control characters -->
+<xsl:param name="git.docbook.backslash">\</xsl:param>
+<xsl:param name="git.docbook.dot" >.</xsl:param>
+
+</xsl:stylesheet>
diff --git a/Documentation/manpage-suppress-sp.xsl b/Documentation/manpage-suppress-sp.xsl
new file mode 100644
index 0000000..a63c763
--- /dev/null
+++ b/Documentation/manpage-suppress-sp.xsl
@@ -0,0 +1,21 @@
+<!-- manpage-suppress-sp.xsl:
+ special settings for manpages rendered from asciidoc+docbook
+ handles erroneous, inline .sp in manpage output of some
+ versions of docbook-xsl -->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0">
+
+<!-- attempt to work around spurious .sp at the tail of the line
+ that some versions of docbook stylesheets seem to add -->
+<xsl:template match="simpara">
+ <xsl:variable name="content">
+ <xsl:apply-templates/>
+ </xsl:variable>
+ <xsl:value-of select="normalize-space($content)"/>
+ <xsl:if test="not(ancestor::authorblurb) and
+ not(ancestor::personblurb)">
+ <xsl:text>&#10;&#10;</xsl:text>
+ </xsl:if>
+</xsl:template>
+
+</xsl:stylesheet>