tools lib traceevent: Remove libtraceevent
libtraceevent is now out-of-date and it is better to depend on the system version. Remove this code that is no longer depended upon by any builds. Committer notes: Removed the removed tools/lib/traceevent/ from tools/perf/MANIFEST, so that 'make perf-tar-src-pkg' works. Signed-off-by: Ian Rogers <irogers@google.com> Acked-by: Steven Rostedt (VMware) <rostedt@goodmis.org> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Kan Liang <kan.liang@linux.intel.com> Cc: Leo Yan <leo.yan@linaro.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lore.kernel.org/lkml/20221130062935.2219247-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
378ef0f5d9
commit
4171925aa9
4
tools/lib/traceevent/.gitignore
vendored
4
tools/lib/traceevent/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
TRACEEVENT-CFLAGS
|
||||
libtraceevent-dynamic-list
|
||||
libtraceevent.so.*
|
@ -1,8 +0,0 @@
|
||||
libtraceevent-y += event-parse.o
|
||||
libtraceevent-y += event-plugin.o
|
||||
libtraceevent-y += trace-seq.o
|
||||
libtraceevent-y += parse-filter.o
|
||||
libtraceevent-y += parse-utils.o
|
||||
libtraceevent-y += kbuffer-parse.o
|
||||
libtraceevent-y += tep_strerror.o
|
||||
libtraceevent-y += event-parse-api.o
|
@ -1,207 +0,0 @@
|
||||
include ../../../scripts/Makefile.include
|
||||
include ../../../scripts/utilities.mak
|
||||
|
||||
# This Makefile and manpage XSL files were taken from tools/perf/Documentation
|
||||
# and modified for libtraceevent.
|
||||
|
||||
MAN3_TXT= \
|
||||
$(wildcard libtraceevent-*.txt) \
|
||||
libtraceevent.txt
|
||||
|
||||
MAN_TXT = $(MAN3_TXT)
|
||||
_MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))
|
||||
_MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT))
|
||||
_DOC_MAN3=$(patsubst %.txt,%.3,$(MAN3_TXT))
|
||||
|
||||
MAN_XML=$(addprefix $(OUTPUT),$(_MAN_XML))
|
||||
MAN_HTML=$(addprefix $(OUTPUT),$(_MAN_HTML))
|
||||
DOC_MAN3=$(addprefix $(OUTPUT),$(_DOC_MAN3))
|
||||
|
||||
# Make the path relative to DESTDIR, not prefix
|
||||
ifndef DESTDIR
|
||||
prefix?=$(HOME)
|
||||
endif
|
||||
bindir?=$(prefix)/bin
|
||||
htmldir?=$(prefix)/share/doc/libtraceevent-doc
|
||||
pdfdir?=$(prefix)/share/doc/libtraceevent-doc
|
||||
mandir?=$(prefix)/share/man
|
||||
man3dir=$(mandir)/man3
|
||||
|
||||
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="libtraceevent" -a manmanual="libtraceevent Manual"
|
||||
ASCIIDOC_HTML = xhtml5
|
||||
endif
|
||||
|
||||
XMLTO=xmlto
|
||||
|
||||
_tmp_tool_path := $(call get-executable,$(ASCIIDOC))
|
||||
ifeq ($(_tmp_tool_path),)
|
||||
missing_tools = $(ASCIIDOC)
|
||||
endif
|
||||
|
||||
ifndef USE_ASCIIDOCTOR
|
||||
_tmp_tool_path := $(call get-executable,$(XMLTO))
|
||||
ifeq ($(_tmp_tool_path),)
|
||||
missing_tools += $(XMLTO)
|
||||
endif
|
||||
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 libtraceevent-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 libtraceevent-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
|
||||
|
||||
#
|
||||
# Please note that there is a minor bug in asciidoc.
|
||||
# The version after 6.0.3 _will_ include the patch found here:
|
||||
# http://marc.theaimsgroup.com/?l=libtraceevent&m=111558757202243&w=2
|
||||
#
|
||||
# Until that version is released you may have to apply the patch
|
||||
# yourself - yes, all 6 characters of it!
|
||||
#
|
||||
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: html man
|
||||
|
||||
man: man3
|
||||
man3: $(DOC_MAN3)
|
||||
|
||||
html: $(MAN_HTML)
|
||||
|
||||
$(MAN_HTML) $(DOC_MAN3): asciidoc.conf
|
||||
|
||||
install: install-man
|
||||
|
||||
check-man-tools:
|
||||
ifdef missing_tools
|
||||
$(error "You need to install $(missing_tools) for man pages")
|
||||
endif
|
||||
|
||||
do-install-man: man
|
||||
$(call QUIET_INSTALL, Documentation-man) \
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(man3dir); \
|
||||
$(INSTALL) -m 644 $(DOC_MAN3) $(DESTDIR)$(man3dir);
|
||||
|
||||
install-man: check-man-tools man do-install-man
|
||||
|
||||
uninstall: uninstall-man
|
||||
|
||||
uninstall-man:
|
||||
$(call QUIET_UNINST, Documentation-man) \
|
||||
$(Q)$(RM) $(addprefix $(DESTDIR)$(man3dir)/,$(DOC_MAN3))
|
||||
|
||||
|
||||
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)) \
|
||||
$(DOC_MAN3) *.3
|
||||
|
||||
clean:
|
||||
$(call QUIET_CLEAN, Documentation) $(RM) $(CLEAN_FILES)
|
||||
|
||||
ifdef USE_ASCIIDOCTOR
|
||||
$(OUTPUT)%.3 : $(OUTPUT)%.txt
|
||||
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
|
||||
$(ASCIIDOC) -b manpage -d manpage \
|
||||
$(ASCIIDOC_EXTRA) -alibtraceevent_version=$(EVENT_PARSE_VERSION) -o $@+ $< && \
|
||||
mv $@+ $@
|
||||
endif
|
||||
|
||||
$(OUTPUT)%.3 : $(OUTPUT)%.xml
|
||||
$(QUIET_XMLTO)$(RM) $@ && \
|
||||
$(XMLTO) -o $(OUTPUT). -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
|
||||
|
||||
$(OUTPUT)%.xml : %.txt
|
||||
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
|
||||
$(ASCIIDOC) -b docbook -d manpage \
|
||||
$(ASCIIDOC_EXTRA) -alibtraceevent_version=$(EVENT_PARSE_VERSION) -o $@+ $< && \
|
||||
mv $@+ $@
|
||||
|
||||
$(MAN_HTML): $(OUTPUT)%.html : %.txt
|
||||
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
|
||||
$(ASCIIDOC) -b $(ASCIIDOC_HTML) -d manpage \
|
||||
$(ASCIIDOC_EXTRA) -aperf_version=$(EVENT_PARSE_VERSION) -o $@+ $< && \
|
||||
mv $@+ $@
|
@ -1,120 +0,0 @@
|
||||
## 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=*
|
||||
plus=+
|
||||
caret=^
|
||||
startsb=[
|
||||
endsb=]
|
||||
tilde=~
|
||||
|
||||
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[]
|
||||
.ft C
|
||||
endif::doctype-manpage[]
|
||||
|
|
||||
ifdef::doctype-manpage[]
|
||||
.ft
|
||||
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">libtraceevent</refmiscinfo>
|
||||
<refmiscinfo class="version">{libtraceevent_version}</refmiscinfo>
|
||||
<refmiscinfo class="manual">libtraceevent 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[]
|
@ -1,153 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_register_comm, tep_override_comm, tep_pid_is_registered,
|
||||
tep_data_comm_from_pid, tep_data_pid_from_comm, tep_cmdline_pid -
|
||||
Manage pid to process name mappings.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
int *tep_register_comm*(struct tep_handle pass:[*]_tep_, const char pass:[*]_comm_, int _pid_);
|
||||
int *tep_override_comm*(struct tep_handle pass:[*]_tep_, const char pass:[*]_comm_, int _pid_);
|
||||
bool *tep_is_pid_registered*(struct tep_handle pass:[*]_tep_, int _pid_);
|
||||
const char pass:[*]*tep_data_comm_from_pid*(struct tep_handle pass:[*]_pevent_, int _pid_);
|
||||
struct cmdline pass:[*]*tep_data_pid_from_comm*(struct tep_handle pass:[*]_pevent_, const char pass:[*]_comm_, struct cmdline pass:[*]_next_);
|
||||
int *tep_cmdline_pid*(struct tep_handle pass:[*]_pevent_, struct cmdline pass:[*]_cmdline_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
These functions can be used to handle the mapping between pid and process name.
|
||||
The library builds a cache of these mappings, which is used to display the name
|
||||
of the process, instead of its pid. This information can be retrieved from
|
||||
tracefs/saved_cmdlines file.
|
||||
|
||||
The _tep_register_comm()_ function registers a _pid_ / process name mapping.
|
||||
If a command with the same _pid_ is already registered, an error is returned.
|
||||
The _pid_ argument is the process ID, the _comm_ argument is the process name,
|
||||
_tep_ is the event context. The _comm_ is duplicated internally.
|
||||
|
||||
The _tep_override_comm()_ function registers a _pid_ / process name mapping.
|
||||
If a process with the same pid is already registered, the process name string is
|
||||
udapted with the new one. The _pid_ argument is the process ID, the _comm_
|
||||
argument is the process name, _tep_ is the event context. The _comm_ is
|
||||
duplicated internally.
|
||||
|
||||
The _tep_is_pid_registered()_ function checks if a pid has a process name
|
||||
mapping registered. The _pid_ argument is the process ID, _tep_ is the event
|
||||
context.
|
||||
|
||||
The _tep_data_comm_from_pid()_ function returns the process name for a given
|
||||
pid. The _pid_ argument is the process ID, _tep_ is the event context.
|
||||
The returned string should not be freed, but will be freed when the _tep_
|
||||
handler is closed.
|
||||
|
||||
The _tep_data_pid_from_comm()_ function returns a pid for a given process name.
|
||||
The _comm_ argument is the process name, _tep_ is the event context.
|
||||
The argument _next_ is the cmdline structure to search for the next pid.
|
||||
As there may be more than one pid for a given process, the result of this call
|
||||
can be passed back into a recurring call in the _next_ parameter, to search for
|
||||
the next pid. If _next_ is NULL, it will return the first pid associated with
|
||||
the _comm_. The function performs a linear search, so it may be slow.
|
||||
|
||||
The _tep_cmdline_pid()_ function returns the pid associated with a given
|
||||
_cmdline_. The _tep_ argument is the event context.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
_tep_register_comm()_ function returns 0 on success. In case of an error -1 is
|
||||
returned and errno is set to indicate the cause of the problem: ENOMEM, if there
|
||||
is not enough memory to duplicate the _comm_ or EEXIST if a mapping for this
|
||||
_pid_ is already registered.
|
||||
|
||||
_tep_override_comm()_ function returns 0 on success. In case of an error -1 is
|
||||
returned and errno is set to indicate the cause of the problem: ENOMEM, if there
|
||||
is not enough memory to duplicate the _comm_.
|
||||
|
||||
_tep_is_pid_registered()_ function returns true if the _pid_ has a process name
|
||||
mapped to it, false otherwise.
|
||||
|
||||
_tep_data_comm_from_pid()_ function returns the process name as string, or the
|
||||
string "<...>" if there is no mapping for the given pid.
|
||||
|
||||
_tep_data_pid_from_comm()_ function returns a pointer to a struct cmdline, that
|
||||
holds a pid for a given process, or NULL if none is found. This result can be
|
||||
passed back into a recurring call as the _next_ parameter of the function.
|
||||
|
||||
_tep_cmdline_pid()_ functions returns the pid for the give cmdline. If _cmdline_
|
||||
is NULL, then -1 is returned.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
The following example registers pid for command "ls", in context of event _tep_
|
||||
and performs various searches for pid / process name mappings:
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
int ret;
|
||||
int ls_pid = 1021;
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
ret = tep_register_comm(tep, "ls", ls_pid);
|
||||
if (ret != 0 && errno == EEXIST)
|
||||
ret = tep_override_comm(tep, "ls", ls_pid);
|
||||
if (ret != 0) {
|
||||
/* Failed to register pid / command mapping */
|
||||
}
|
||||
...
|
||||
if (tep_is_pid_registered(tep, ls_pid) == 0) {
|
||||
/* Command mapping for ls_pid is not registered */
|
||||
}
|
||||
...
|
||||
const char *comm = tep_data_comm_from_pid(tep, ls_pid);
|
||||
if (comm) {
|
||||
/* Found process name for ls_pid */
|
||||
}
|
||||
...
|
||||
int pid;
|
||||
struct cmdline *cmd = tep_data_pid_from_comm(tep, "ls", NULL);
|
||||
while (cmd) {
|
||||
pid = tep_cmdline_pid(tep, cmd);
|
||||
/* Found pid for process "ls" */
|
||||
cmd = tep_data_pid_from_comm(tep, "ls", cmd);
|
||||
}
|
||||
--
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,77 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_get_cpus, tep_set_cpus - Get / set the number of CPUs, which have a tracing
|
||||
buffer representing it. Note, the buffer may be empty.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
int *tep_get_cpus*(struct tep_handle pass:[*]_tep_);
|
||||
void *tep_set_cpus*(struct tep_handle pass:[*]_tep_, int _cpus_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The _tep_get_cpus()_ function gets the number of CPUs, which have a tracing
|
||||
buffer representing it. The _tep_ argument is trace event parser context.
|
||||
|
||||
The _tep_set_cpus()_ function sets the number of CPUs, which have a tracing
|
||||
buffer representing it. The _tep_ argument is trace event parser context.
|
||||
The _cpu_ argument is the number of CPUs with tracing data.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_get_cpus()_ functions returns the number of CPUs, which have tracing
|
||||
data recorded.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
tep_set_cpus(tep, 5);
|
||||
...
|
||||
printf("We have tracing data for %d CPUs", tep_get_cpus(tep));
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,78 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_read_number - Reads a number from raw data.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
unsigned long long *tep_read_number*(struct tep_handle pass:[*]_tep_, const void pass:[*]_ptr_, int _size_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The _tep_read_number()_ function reads an integer from raw data, taking into
|
||||
account the endianness of the raw data and the current host. The _tep_ argument
|
||||
is the trace event parser context. The _ptr_ is a pointer to the raw data, where
|
||||
the integer is, and the _size_ is the size of the integer.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_read_number()_ function returns the integer in the byte order of
|
||||
the current host. In case of an error, 0 is returned.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
void process_record(struct tep_record *record)
|
||||
{
|
||||
int offset = 24;
|
||||
int data = tep_read_number(tep, record->data + offset, 4);
|
||||
|
||||
/* Read the 4 bytes at the offset 24 of data as an integer */
|
||||
}
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,103 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_find_event,tep_find_event_by_name,tep_find_event_by_record -
|
||||
Find events by given key.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
struct tep_event pass:[*]*tep_find_event*(struct tep_handle pass:[*]_tep_, int _id_);
|
||||
struct tep_event pass:[*]*tep_find_event_by_name*(struct tep_handle pass:[*]_tep_, const char pass:[*]_sys_, const char pass:[*]_name_);
|
||||
struct tep_event pass:[*]*tep_find_event_by_record*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_record_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
This set of functions can be used to search for an event, based on a given
|
||||
criteria. All functions require a pointer to a _tep_, trace event parser
|
||||
context.
|
||||
|
||||
The _tep_find_event()_ function searches for an event by given event _id_. The
|
||||
event ID is assigned dynamically and can be viewed in event's format file,
|
||||
"ID" field.
|
||||
|
||||
The tep_find_event_by_name()_ function searches for an event by given
|
||||
event _name_, under the system _sys_. If the _sys_ is NULL (not specified),
|
||||
the first event with _name_ is returned.
|
||||
|
||||
The tep_find_event_by_record()_ function searches for an event from a given
|
||||
_record_.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
All these functions return a pointer to the found event, or NULL if there is no
|
||||
such event.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
struct tep_event *event;
|
||||
|
||||
event = tep_find_event(tep, 1857);
|
||||
if (event == NULL) {
|
||||
/* There is no event with ID 1857 */
|
||||
}
|
||||
|
||||
event = tep_find_event_by_name(tep, "kvm", "kvm_exit");
|
||||
if (event == NULL) {
|
||||
/* There is no kvm_exit event, from kvm system */
|
||||
}
|
||||
|
||||
void event_from_record(struct tep_record *record)
|
||||
{
|
||||
struct tep_event *event = tep_find_event_by_record(tep, record);
|
||||
if (event == NULL) {
|
||||
/* There is no event from given record */
|
||||
}
|
||||
}
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,99 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_get_event, tep_get_first_event, tep_get_events_count - Access events.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
struct tep_event pass:[*]*tep_get_event*(struct tep_handle pass:[*]_tep_, int _index_);
|
||||
struct tep_event pass:[*]*tep_get_first_event*(struct tep_handle pass:[*]_tep_);
|
||||
int *tep_get_events_count*(struct tep_handle pass:[*]_tep_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The _tep_get_event()_ function returns a pointer to event at the given _index_.
|
||||
The _tep_ argument is trace event parser context, the _index_ is the index of
|
||||
the requested event.
|
||||
|
||||
The _tep_get_first_event()_ function returns a pointer to the first event.
|
||||
As events are stored in an array, this function returns the pointer to the
|
||||
beginning of the array. The _tep_ argument is trace event parser context.
|
||||
|
||||
The _tep_get_events_count()_ function returns the number of the events
|
||||
in the array. The _tep_ argument is trace event parser context.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_get_event()_ returns a pointer to the event located at _index_.
|
||||
NULL is returned in case of error, in case there are no events or _index_ is
|
||||
out of range.
|
||||
|
||||
The _tep_get_first_event()_ returns a pointer to the first event. NULL is
|
||||
returned in case of error, or in case there are no events.
|
||||
|
||||
The _tep_get_events_count()_ returns the number of the events. 0 is
|
||||
returned in case of error, or in case there are no events.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
int i,count = tep_get_events_count(tep);
|
||||
struct tep_event *event, *events = tep_get_first_event(tep);
|
||||
|
||||
if (events == NULL) {
|
||||
/* There are no events */
|
||||
} else {
|
||||
for (i = 0; i < count; i++) {
|
||||
event = (events+i);
|
||||
/* process events[i] */
|
||||
}
|
||||
|
||||
/* Get the last event */
|
||||
event = tep_get_event(tep, count-1);
|
||||
}
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,122 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_list_events, tep_list_events_copy -
|
||||
Get list of events, sorted by given criteria.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
enum *tep_event_sort_type* {
|
||||
_TEP_EVENT_SORT_ID_,
|
||||
_TEP_EVENT_SORT_NAME_,
|
||||
_TEP_EVENT_SORT_SYSTEM_,
|
||||
};
|
||||
|
||||
struct tep_event pass:[*]pass:[*]*tep_list_events*(struct tep_handle pass:[*]_tep_, enum tep_event_sort_type _sort_type_);
|
||||
struct tep_event pass:[*]pass:[*]*tep_list_events_copy*(struct tep_handle pass:[*]_tep_, enum tep_event_sort_type _sort_type_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The _tep_list_events()_ function returns an array of pointers to the events,
|
||||
sorted by the _sort_type_ criteria. The last element of the array is NULL.
|
||||
The returned memory must not be freed, it is managed by the library.
|
||||
The function is not thread safe. The _tep_ argument is trace event parser
|
||||
context. The _sort_type_ argument is the required sort criteria:
|
||||
[verse]
|
||||
--
|
||||
_TEP_EVENT_SORT_ID_ - sort by the event ID.
|
||||
_TEP_EVENT_SORT_NAME_ - sort by the event (name, system, id) triplet.
|
||||
_TEP_EVENT_SORT_SYSTEM_ - sort by the event (system, name, id) triplet.
|
||||
--
|
||||
|
||||
The _tep_list_events_copy()_ is a thread safe version of _tep_list_events()_.
|
||||
It has the same behavior, but the returned array is allocated internally and
|
||||
must be freed by the caller. Note that the content of the array must not be
|
||||
freed (see the EXAMPLE below).
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_list_events()_ function returns an array of pointers to events.
|
||||
In case of an error, NULL is returned. The returned array must not be freed,
|
||||
it is managed by the library.
|
||||
|
||||
The _tep_list_events_copy()_ function returns an array of pointers to events.
|
||||
In case of an error, NULL is returned. The returned array must be freed by
|
||||
the caller.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
int i;
|
||||
struct tep_event_format **events;
|
||||
|
||||
i=0;
|
||||
events = tep_list_events(tep, TEP_EVENT_SORT_ID);
|
||||
if (events == NULL) {
|
||||
/* Failed to get the events, sorted by ID */
|
||||
} else {
|
||||
while(events[i]) {
|
||||
/* walk through the list of the events, sorted by ID */
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
i=0;
|
||||
events = tep_list_events_copy(tep, TEP_EVENT_SORT_NAME);
|
||||
if (events == NULL) {
|
||||
/* Failed to get the events, sorted by name */
|
||||
} else {
|
||||
while(events[i]) {
|
||||
/* walk through the list of the events, sorted by name */
|
||||
i++;
|
||||
}
|
||||
free(events);
|
||||
}
|
||||
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,130 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_print_event - Writes event information into a trace sequence.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
*#include <trace-seq.h>*
|
||||
|
||||
void *tep_print_event*(struct tep_handle pass:[*]_tep_, struct trace_seqpass:[*]_s_, struct tep_record pass:[*]_record_, const char pass:[*]_fmt_, _..._)
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
The _tep_print_event()_ function parses the event information of the given
|
||||
_record_ and writes it into the trace sequence _s_, according to the format
|
||||
string _fmt_. The desired information is specified after the format string.
|
||||
The _fmt_ is printf-like format string, following arguments are supported:
|
||||
[verse]
|
||||
--
|
||||
TEP_PRINT_PID, "%d" - PID of the event.
|
||||
TEP_PRINT_CPU, "%d" - Event CPU.
|
||||
TEP_PRINT_COMM, "%s" - Event command string.
|
||||
TEP_PRINT_NAME, "%s" - Event name.
|
||||
TEP_PRINT_LATENCY, "%s" - Latency of the event. It prints 4 or more
|
||||
fields - interrupt state, scheduling state,
|
||||
current context, and preemption count.
|
||||
Field 1 is the interrupt enabled state:
|
||||
d : Interrupts are disabled
|
||||
. : Interrupts are enabled
|
||||
X : The architecture does not support this
|
||||
information
|
||||
Field 2 is the "need resched" state.
|
||||
N : The task is set to call the scheduler when
|
||||
possible, as another higher priority task
|
||||
may need to be scheduled in.
|
||||
. : The task is not set to call the scheduler.
|
||||
Field 3 is the context state.
|
||||
. : Normal context
|
||||
s : Soft interrupt context
|
||||
h : Hard interrupt context
|
||||
H : Hard interrupt context which triggered
|
||||
during soft interrupt context.
|
||||
z : NMI context
|
||||
Z : NMI context which triggered during hard
|
||||
interrupt context
|
||||
Field 4 is the preemption count.
|
||||
. : The preempt count is zero.
|
||||
On preemptible kernels (where the task can be scheduled
|
||||
out in arbitrary locations while in kernel context), the
|
||||
preempt count, when non zero, will prevent the kernel
|
||||
from scheduling out the current task. The preempt count
|
||||
number is displayed when it is not zero.
|
||||
Depending on the kernel, it may show other fields
|
||||
(lock depth, or migration disabled, which are unique to
|
||||
specialized kernels).
|
||||
TEP_PRINT_TIME, %d - event time stamp. A divisor and precision can be
|
||||
specified as part of this format string:
|
||||
"%precision.divisord". Example:
|
||||
"%3.1000d" - divide the time by 1000 and print the first
|
||||
3 digits before the dot. Thus, the time stamp
|
||||
"123456000" will be printed as "123.456"
|
||||
TEP_PRINT_INFO, "%s" - event information.
|
||||
TEP_PRINT_INFO_RAW, "%s" - event information, in raw format.
|
||||
|
||||
--
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
#include <trace-seq.h>
|
||||
...
|
||||
struct trace_seq seq;
|
||||
trace_seq_init(&seq);
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
void print_my_event(struct tep_record *record)
|
||||
{
|
||||
trace_seq_reset(&seq);
|
||||
tep_print_event(tep, s, record, "%16s-%-5d [%03d] %s %6.1000d %s %s",
|
||||
TEP_PRINT_COMM, TEP_PRINT_PID, TEP_PRINT_CPU,
|
||||
TEP_PRINT_LATENCY, TEP_PRINT_TIME, TEP_PRINT_NAME,
|
||||
TEP_PRINT_INFO);
|
||||
}
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*trace-seq.h*
|
||||
Header file to include in order to have access to trace sequences related APIs.
|
||||
Trace sequences are used to allow a function to call several other functions
|
||||
to create a string of data to use.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,118 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_find_common_field, tep_find_field, tep_find_any_field -
|
||||
Search for a field in an event.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
struct tep_format_field pass:[*]*tep_find_common_field*(struct tep_event pass:[*]_event_, const char pass:[*]_name_);
|
||||
struct tep_format_field pass:[*]*tep_find_field*(struct tep_event_ormat pass:[*]_event_, const char pass:[*]_name_);
|
||||
struct tep_format_field pass:[*]*tep_find_any_field*(struct tep_event pass:[*]_event_, const char pass:[*]_name_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
These functions search for a field with given name in an event. The field
|
||||
returned can be used to find the field content from within a data record.
|
||||
|
||||
The _tep_find_common_field()_ function searches for a common field with _name_
|
||||
in the _event_.
|
||||
|
||||
The _tep_find_field()_ function searches for an event specific field with
|
||||
_name_ in the _event_.
|
||||
|
||||
The _tep_find_any_field()_ function searches for any field with _name_ in the
|
||||
_event_.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_find_common_field(), _tep_find_field()_ and _tep_find_any_field()_
|
||||
functions return a pointer to the found field, or NULL in case there is no field
|
||||
with the requested name.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
void get_htimer_info(struct tep_handle *tep, struct tep_record *record)
|
||||
{
|
||||
struct tep_format_field *field;
|
||||
struct tep_event *event;
|
||||
long long softexpires;
|
||||
int mode;
|
||||
int pid;
|
||||
|
||||
event = tep_find_event_by_name(tep, "timer", "hrtimer_start");
|
||||
|
||||
field = tep_find_common_field(event, "common_pid");
|
||||
if (field == NULL) {
|
||||
/* Cannot find "common_pid" field in the event */
|
||||
} else {
|
||||
/* Get pid from the data record */
|
||||
pid = tep_read_number(tep, record->data + field->offset,
|
||||
field->size);
|
||||
}
|
||||
|
||||
field = tep_find_field(event, "softexpires");
|
||||
if (field == NULL) {
|
||||
/* Cannot find "softexpires" event specific field in the event */
|
||||
} else {
|
||||
/* Get softexpires parameter from the data record */
|
||||
softexpires = tep_read_number(tep, record->data + field->offset,
|
||||
field->size);
|
||||
}
|
||||
|
||||
field = tep_find_any_field(event, "mode");
|
||||
if (field == NULL) {
|
||||
/* Cannot find "mode" field in the event */
|
||||
} else
|
||||
{
|
||||
/* Get mode parameter from the data record */
|
||||
mode = tep_read_number(tep, record->data + field->offset,
|
||||
field->size);
|
||||
}
|
||||
}
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,122 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_get_any_field_val, tep_get_common_field_val, tep_get_field_val,
|
||||
tep_get_field_raw - Get value of a field.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
*#include <trace-seq.h>*
|
||||
|
||||
int *tep_get_any_field_val*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, unsigned long long pass:[*]_val_, int _err_);
|
||||
int *tep_get_common_field_val*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, unsigned long long pass:[*]_val_, int _err_);
|
||||
int *tep_get_field_val*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, unsigned long long pass:[*]_val_, int _err_);
|
||||
void pass:[*]*tep_get_field_raw*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, int pass:[*]_len_, int _err_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
These functions can be used to find a field and retrieve its value.
|
||||
|
||||
The _tep_get_any_field_val()_ function searches in the _record_ for a field
|
||||
with _name_, part of the _event_. If the field is found, its value is stored in
|
||||
_val_. If there is an error and _err_ is not zero, then an error string is
|
||||
written into _s_.
|
||||
|
||||
The _tep_get_common_field_val()_ function does the same as
|
||||
_tep_get_any_field_val()_, but searches only in the common fields. This works
|
||||
for any event as all events include the common fields.
|
||||
|
||||
The _tep_get_field_val()_ function does the same as _tep_get_any_field_val()_,
|
||||
but searches only in the event specific fields.
|
||||
|
||||
The _tep_get_field_raw()_ function searches in the _record_ for a field with
|
||||
_name_, part of the _event_. If the field is found, a pointer to where the field
|
||||
exists in the record's raw data is returned. The size of the data is stored in
|
||||
_len_. If there is an error and _err_ is not zero, then an error string is
|
||||
written into _s_.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_get_any_field_val()_, _tep_get_common_field_val()_ and
|
||||
_tep_get_field_val()_ functions return 0 on success, or -1 in case of an error.
|
||||
|
||||
The _tep_get_field_raw()_ function returns a pointer to field's raw data, and
|
||||
places the length of this data in _len_. In case of an error NULL is returned.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
#include <trace-seq.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
struct tep_event *event = tep_find_event_by_name(tep, "kvm", "kvm_exit");
|
||||
...
|
||||
void process_record(struct tep_record *record)
|
||||
{
|
||||
int len;
|
||||
char *comm;
|
||||
struct tep_event_format *event;
|
||||
unsigned long long val;
|
||||
|
||||
event = tep_find_event_by_record(pevent, record);
|
||||
if (event != NULL) {
|
||||
if (tep_get_common_field_val(NULL, event, "common_type",
|
||||
record, &val, 0) == 0) {
|
||||
/* Got the value of common type field */
|
||||
}
|
||||
if (tep_get_field_val(NULL, event, "pid", record, &val, 0) == 0) {
|
||||
/* Got the value of pid specific field */
|
||||
}
|
||||
comm = tep_get_field_raw(NULL, event, "comm", record, &len, 0);
|
||||
if (comm != NULL) {
|
||||
/* Got a pointer to the comm event specific field */
|
||||
}
|
||||
}
|
||||
}
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*trace-seq.h*
|
||||
Header file to include in order to have access to trace sequences
|
||||
related APIs. Trace sequences are used to allow a function to call
|
||||
several other functions to create a string of data to use.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,126 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_print_field, tep_print_fields, tep_print_num_field, tep_print_func_field -
|
||||
Print the field content.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
*#include <trace-seq.h>*
|
||||
|
||||
void *tep_print_field*(struct trace_seq pass:[*]_s_, void pass:[*]_data_, struct tep_format_field pass:[*]_field_);
|
||||
void *tep_print_fields*(struct trace_seq pass:[*]_s_, void pass:[*]_data_, int _size_, struct tep_event pass:[*]_event_);
|
||||
int *tep_print_num_field*(struct trace_seq pass:[*]_s_, const char pass:[*]_fmt_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, int _err_);
|
||||
int *tep_print_func_field*(struct trace_seq pass:[*]_s_, const char pass:[*]_fmt_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, int _err_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
These functions print recorded field's data, according to the field's type.
|
||||
|
||||
The _tep_print_field()_ function extracts from the recorded raw _data_ value of
|
||||
the _field_ and prints it into _s_, according to the field type.
|
||||
|
||||
The _tep_print_fields()_ prints each field name followed by the record's field
|
||||
value according to the field's type:
|
||||
[verse]
|
||||
--
|
||||
"field1_name=field1_value field2_name=field2_value ..."
|
||||
--
|
||||
It iterates all fields of the _event_, and calls _tep_print_field()_ for each of
|
||||
them.
|
||||
|
||||
The _tep_print_num_field()_ function prints a numeric field with given format
|
||||
string. A search is performed in the _event_ for a field with _name_. If such
|
||||
field is found, its value is extracted from the _record_ and is printed in the
|
||||
_s_, according to the given format string _fmt_. If the argument _err_ is
|
||||
non-zero, and an error occures - it is printed in the _s_.
|
||||
|
||||
The _tep_print_func_field()_ function prints a function field with given format
|
||||
string. A search is performed in the _event_ for a field with _name_. If such
|
||||
field is found, its value is extracted from the _record_. The value is assumed
|
||||
to be a function address, and a search is perform to find the name of this
|
||||
function. The function name (if found) and its address are printed in the _s_,
|
||||
according to the given format string _fmt_. If the argument _err_ is non-zero,
|
||||
and an error occures - it is printed in _s_.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_print_num_field()_ and _tep_print_func_field()_ functions return 1
|
||||
on success, -1 in case of an error or 0 if the print buffer _s_ is full.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
#include <trace-seq.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
struct trace_seq seq;
|
||||
trace_seq_init(&seq);
|
||||
struct tep_event *event = tep_find_event_by_name(tep, "timer", "hrtimer_start");
|
||||
...
|
||||
void process_record(struct tep_record *record)
|
||||
{
|
||||
struct tep_format_field *field_pid = tep_find_common_field(event, "common_pid");
|
||||
|
||||
trace_seq_reset(&seq);
|
||||
|
||||
/* Print the value of "common_pid" */
|
||||
tep_print_field(&seq, record->data, field_pid);
|
||||
|
||||
/* Print all fields of the "hrtimer_start" event */
|
||||
tep_print_fields(&seq, record->data, record->size, event);
|
||||
|
||||
/* Print the value of "expires" field with custom format string */
|
||||
tep_print_num_field(&seq, " timer expires in %llu ", event, "expires", record, 0);
|
||||
|
||||
/* Print the address and the name of "function" field with custom format string */
|
||||
tep_print_func_field(&seq, " timer function is %s ", event, "function", record, 0);
|
||||
}
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*trace-seq.h*
|
||||
Header file to include in order to have access to trace sequences related APIs.
|
||||
Trace sequences are used to allow a function to call several other functions
|
||||
to create a string of data to use.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,81 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_read_number_field - Reads a number from raw data.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
int *tep_read_number_field*(struct tep_format_field pass:[*]_field_, const void pass:[*]_data_, unsigned long long pass:[*]_value_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The _tep_read_number_field()_ function reads the value of the _field_ from the
|
||||
raw _data_ and stores it in the _value_. The function sets the _value_ according
|
||||
to the endianness of the raw data and the current machine and stores it in
|
||||
_value_.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_read_number_field()_ function retunrs 0 in case of success, or -1 in
|
||||
case of an error.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
struct tep_event *event = tep_find_event_by_name(tep, "timer", "hrtimer_start");
|
||||
...
|
||||
void process_record(struct tep_record *record)
|
||||
{
|
||||
unsigned long long pid;
|
||||
struct tep_format_field *field_pid = tep_find_common_field(event, "common_pid");
|
||||
|
||||
if (tep_read_number_field(field_pid, record->data, &pid) != 0) {
|
||||
/* Failed to get "common_pid" value */
|
||||
}
|
||||
}
|
||||
...
|
||||
--
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,105 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_event_common_fields, tep_event_fields - Get a list of fields for an event.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
struct tep_format_field pass:[*]pass:[*]*tep_event_common_fields*(struct tep_event pass:[*]_event_);
|
||||
struct tep_format_field pass:[*]pass:[*]*tep_event_fields*(struct tep_event pass:[*]_event_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The _tep_event_common_fields()_ function returns an array of pointers to common
|
||||
fields for the _event_. The array is allocated in the function and must be freed
|
||||
by free(). The last element of the array is NULL.
|
||||
|
||||
The _tep_event_fields()_ function returns an array of pointers to event specific
|
||||
fields for the _event_. The array is allocated in the function and must be freed
|
||||
by free(). The last element of the array is NULL.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
Both _tep_event_common_fields()_ and _tep_event_fields()_ functions return
|
||||
an array of pointers to tep_format_field structures in case of success, or
|
||||
NULL in case of an error.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
int i;
|
||||
struct tep_format_field **fields;
|
||||
struct tep_event *event = tep_find_event_by_name(tep, "kvm", "kvm_exit");
|
||||
if (event != NULL) {
|
||||
fields = tep_event_common_fields(event);
|
||||
if (fields != NULL) {
|
||||
i = 0;
|
||||
while (fields[i]) {
|
||||
/*
|
||||
walk through the list of the common fields
|
||||
of the kvm_exit event
|
||||
*/
|
||||
i++;
|
||||
}
|
||||
free(fields);
|
||||
}
|
||||
fields = tep_event_fields(event);
|
||||
if (fields != NULL) {
|
||||
i = 0;
|
||||
while (fields[i]) {
|
||||
/*
|
||||
walk through the list of the event specific
|
||||
fields of the kvm_exit event
|
||||
*/
|
||||
i++;
|
||||
}
|
||||
free(fields);
|
||||
}
|
||||
}
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,91 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_is_file_bigendian, tep_set_file_bigendian - Get / set the endianness of the
|
||||
raw data being accessed by the tep handler.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
enum *tep_endian* {
|
||||
TEP_LITTLE_ENDIAN = 0,
|
||||
TEP_BIG_ENDIAN
|
||||
};
|
||||
|
||||
bool *tep_is_file_bigendian*(struct tep_handle pass:[*]_tep_);
|
||||
void *tep_set_file_bigendian*(struct tep_handle pass:[*]_tep_, enum tep_endian _endian_);
|
||||
|
||||
--
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The _tep_is_file_bigendian()_ function gets the endianness of the raw data,
|
||||
being accessed by the tep handler. The _tep_ argument is trace event parser
|
||||
context.
|
||||
|
||||
The _tep_set_file_bigendian()_ function sets the endianness of raw data being
|
||||
accessed by the tep handler. The _tep_ argument is trace event parser context.
|
||||
[verse]
|
||||
--
|
||||
The _endian_ argument is the endianness:
|
||||
_TEP_LITTLE_ENDIAN_ - the raw data is in little endian format,
|
||||
_TEP_BIG_ENDIAN_ - the raw data is in big endian format.
|
||||
--
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_is_file_bigendian()_ function returns true if the data is in bigendian
|
||||
format, false otherwise.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
tep_set_file_bigendian(tep, TEP_LITTLE_ENDIAN);
|
||||
...
|
||||
if (tep_is_file_bigendian(tep)) {
|
||||
/* The raw data is in big endian */
|
||||
} else {
|
||||
/* The raw data is in little endian */
|
||||
}
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,209 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_filter_alloc, tep_filter_free, tep_filter_reset, tep_filter_make_string,
|
||||
tep_filter_copy, tep_filter_compare, tep_filter_match, tep_event_filtered,
|
||||
tep_filter_remove_event, tep_filter_strerror, tep_filter_add_filter_str -
|
||||
Event filter related APIs.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
struct tep_event_filter pass:[*]*tep_filter_alloc*(struct tep_handle pass:[*]_tep_);
|
||||
void *tep_filter_free*(struct tep_event_filter pass:[*]_filter_);
|
||||
void *tep_filter_reset*(struct tep_event_filter pass:[*]_filter_);
|
||||
enum tep_errno *tep_filter_add_filter_str*(struct tep_event_filter pass:[*]_filter_, const char pass:[*]_filter_str_);
|
||||
int *tep_event_filtered*(struct tep_event_filter pass:[*]_filter_, int _event_id_);
|
||||
int *tep_filter_remove_event*(struct tep_event_filter pass:[*]_filter_, int _event_id_);
|
||||
enum tep_errno *tep_filter_match*(struct tep_event_filter pass:[*]_filter_, struct tep_record pass:[*]_record_);
|
||||
int *tep_filter_copy*(struct tep_event_filter pass:[*]_dest_, struct tep_event_filter pass:[*]_source_);
|
||||
int *tep_filter_compare*(struct tep_event_filter pass:[*]_filter1_, struct tep_event_filter pass:[*]_filter2_);
|
||||
char pass:[*]*tep_filter_make_string*(struct tep_event_filter pass:[*]_filter_, int _event_id_);
|
||||
int *tep_filter_strerror*(struct tep_event_filter pass:[*]_filter_, enum tep_errno _err_, char pass:[*]buf, size_t _buflen_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Filters can be attached to traced events. They can be used to filter out various
|
||||
events when outputting them. Each event can be filtered based on its parameters,
|
||||
described in the event's format file. This set of functions can be used to
|
||||
create, delete, modify and attach event filters.
|
||||
|
||||
The _tep_filter_alloc()_ function creates a new event filter. The _tep_ argument
|
||||
is the trace event parser context.
|
||||
|
||||
The _tep_filter_free()_ function frees an event filter and all resources that it
|
||||
had used.
|
||||
|
||||
The _tep_filter_reset()_ function removes all rules from an event filter and
|
||||
resets it.
|
||||
|
||||
The _tep_filter_add_filter_str()_ function adds a new rule to the _filter_. The
|
||||
_filter_str_ argument is the filter string, that contains the rule.
|
||||
|
||||
The _tep_event_filtered()_ function checks if the event with _event_id_ has
|
||||
_filter_.
|
||||
|
||||
The _tep_filter_remove_event()_ function removes a _filter_ for an event with
|
||||
_event_id_.
|
||||
|
||||
The _tep_filter_match()_ function tests if a _record_ matches given _filter_.
|
||||
|
||||
The _tep_filter_copy()_ function copies a _source_ filter into a _dest_ filter.
|
||||
|
||||
The _tep_filter_compare()_ function compares two filers - _filter1_ and _filter2_.
|
||||
|
||||
The _tep_filter_make_string()_ function constructs a string, displaying
|
||||
the _filter_ contents for given _event_id_.
|
||||
|
||||
The _tep_filter_strerror()_ function copies the _filter_ error buffer into the
|
||||
given _buf_ with the size _buflen_. If the error buffer is empty, in the _buf_
|
||||
is copied a string, describing the error _err_.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_filter_alloc()_ function returns a pointer to the newly created event
|
||||
filter, or NULL in case of an error.
|
||||
|
||||
The _tep_filter_add_filter_str()_ function returns 0 if the rule was
|
||||
successfully added or a negative error code. Use _tep_filter_strerror()_ to see
|
||||
actual error message in case of an error.
|
||||
|
||||
The _tep_event_filtered()_ function returns 1 if the filter is found for given
|
||||
event, or 0 otherwise.
|
||||
|
||||
The _tep_filter_remove_event()_ function returns 1 if the vent was removed, or
|
||||
0 if the event was not found.
|
||||
|
||||
The _tep_filter_match()_ function returns _tep_errno_, according to the result:
|
||||
[verse]
|
||||
--
|
||||
_pass:[TEP_ERRNO__FILTER_MATCH]_ - filter found for event, the record matches.
|
||||
_pass:[TEP_ERRNO__FILTER_MISS]_ - filter found for event, the record does not match.
|
||||
_pass:[TEP_ERRNO__FILTER_NOT_FOUND]_ - no filter found for record's event.
|
||||
_pass:[TEP_ERRNO__NO_FILTER]_ - no rules in the filter.
|
||||
--
|
||||
or any other _tep_errno_, if an error occurred during the test.
|
||||
|
||||
The _tep_filter_copy()_ function returns 0 on success or -1 if not all rules
|
||||
were copied.
|
||||
|
||||
The _tep_filter_compare()_ function returns 1 if the two filters hold the same
|
||||
content, or 0 if they do not.
|
||||
|
||||
The _tep_filter_make_string()_ function returns a string, which must be freed
|
||||
with free(), or NULL in case of an error.
|
||||
|
||||
The _tep_filter_strerror()_ function returns 0 if message was filled
|
||||
successfully, or -1 in case of an error.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
char errstr[200];
|
||||
int ret;
|
||||
|
||||
struct tep_event_filter *filter = tep_filter_alloc(tep);
|
||||
struct tep_event_filter *filter1 = tep_filter_alloc(tep);
|
||||
ret = tep_filter_add_filter_str(filter, "sched/sched_wakeup:target_cpu==1");
|
||||
if(ret < 0) {
|
||||
tep_filter_strerror(filter, ret, errstr, sizeof(errstr));
|
||||
/* Failed to add a new rule to the filter, the error string is in errstr */
|
||||
}
|
||||
if (tep_filter_copy(filter1, filter) != 0) {
|
||||
/* Failed to copy filter in filter1 */
|
||||
}
|
||||
...
|
||||
if (tep_filter_compare(filter, filter1) != 1) {
|
||||
/* Both filters are different */
|
||||
}
|
||||
...
|
||||
void process_record(struct tep_handle *tep, struct tep_record *record)
|
||||
{
|
||||
struct tep_event *event;
|
||||
char *fstring;
|
||||
|
||||
event = tep_find_event_by_record(tep, record);
|
||||
|
||||
if (tep_event_filtered(filter, event->id) == 1) {
|
||||
/* The event has filter */
|
||||
fstring = tep_filter_make_string(filter, event->id);
|
||||
if (fstring != NULL) {
|
||||
/* The filter for the event is in fstring */
|
||||
free(fstring);
|
||||
}
|
||||
}
|
||||
|
||||
switch (tep_filter_match(filter, record)) {
|
||||
case TEP_ERRNO__FILTER_MATCH:
|
||||
/* The filter matches the record */
|
||||
break;
|
||||
case TEP_ERRNO__FILTER_MISS:
|
||||
/* The filter does not match the record */
|
||||
break;
|
||||
case TEP_ERRNO__FILTER_NOT_FOUND:
|
||||
/* No filter found for record's event */
|
||||
break;
|
||||
case TEP_ERRNO__NO_FILTER:
|
||||
/* There are no rules in the filter */
|
||||
break
|
||||
default:
|
||||
/* An error occurred during the test */
|
||||
break;
|
||||
}
|
||||
|
||||
if (tep_filter_remove_event(filter, event->id) == 1) {
|
||||
/* The event was removed from the filter */
|
||||
}
|
||||
}
|
||||
|
||||
...
|
||||
tep_filter_reset(filter);
|
||||
...
|
||||
tep_filter_free(filter);
|
||||
tep_filter_free(filter1);
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,183 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_find_function, tep_find_function_address, tep_set_function_resolver,
|
||||
tep_reset_function_resolver, tep_register_function, tep_register_print_string -
|
||||
function related tep APIs
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
typedef char pass:[*](*tep_func_resolver_t*)(void pass:[*]_priv_, unsigned long long pass:[*]_addrp_, char pass:[**]_modp_);
|
||||
int *tep_set_function_resolver*(struct tep_handle pass:[*]_tep_, tep_func_resolver_t pass:[*]_func_, void pass:[*]_priv_);
|
||||
void *tep_reset_function_resolver*(struct tep_handle pass:[*]_tep_);
|
||||
const char pass:[*]*tep_find_function*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_);
|
||||
unsigned long long *tep_find_function_address*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_);
|
||||
int *tep_register_function*(struct tep_handle pass:[*]_tep_, char pass:[*]_name_, unsigned long long _addr_, char pass:[*]_mod_);
|
||||
int *tep_register_print_string*(struct tep_handle pass:[*]_tep_, const char pass:[*]_fmt_, unsigned long long _addr_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Some tools may have already a way to resolve the kernel functions. These APIs
|
||||
allow them to keep using it instead of duplicating all the entries inside.
|
||||
|
||||
The _tep_func_resolver_t_ type is the prototype of the alternative kernel
|
||||
functions resolver. This function receives a pointer to its custom context
|
||||
(set with the _tep_set_function_resolver()_ call ) and the address of a kernel
|
||||
function, which has to be resolved. In case of success, it should return
|
||||
the name of the function and its module (if any) in _modp_.
|
||||
|
||||
The _tep_set_function_resolver()_ function registers _func_ as an alternative
|
||||
kernel functions resolver. The _tep_ argument is trace event parser context.
|
||||
The _priv_ argument is a custom context of the _func_ function. The function
|
||||
resolver is used by the APIs _tep_find_function()_,
|
||||
_tep_find_function_address()_, and _tep_print_func_field()_ to resolve
|
||||
a function address to a function name.
|
||||
|
||||
The _tep_reset_function_resolver()_ function resets the kernel functions
|
||||
resolver to the default function. The _tep_ argument is trace event parser
|
||||
context.
|
||||
|
||||
|
||||
These APIs can be used to find function name and start address, by given
|
||||
address. The given address does not have to be exact, it will select
|
||||
the function that would contain it.
|
||||
|
||||
The _tep_find_function()_ function returns the function name, which contains the
|
||||
given address _addr_. The _tep_ argument is the trace event parser context.
|
||||
|
||||
The _tep_find_function_address()_ function returns the function start address,
|
||||
by given address _addr_. The _addr_ does not have to be exact, it will select
|
||||
the function that would contain it. The _tep_ argument is the trace event
|
||||
parser context.
|
||||
|
||||
The _tep_register_function()_ function registers a function name mapped to an
|
||||
address and (optional) module. This mapping is used in case the function tracer
|
||||
or events have "%pS" parameter in its format string. It is common to pass in
|
||||
the kallsyms function names with their corresponding addresses with this
|
||||
function. The _tep_ argument is the trace event parser context. The _name_ is
|
||||
the name of the function, the string is copied internally. The _addr_ is the
|
||||
start address of the function. The _mod_ is the kernel module the function may
|
||||
be in (NULL for none).
|
||||
|
||||
The _tep_register_print_string()_ function registers a string by the address
|
||||
it was stored in the kernel. Some strings internal to the kernel with static
|
||||
address are passed to certain events. The "%s" in the event's format field
|
||||
which has an address needs to know what string would be at that address. The
|
||||
tep_register_print_string() supplies the parsing with the mapping between kernel
|
||||
addresses and those strings. The _tep_ argument is the trace event parser
|
||||
context. The _fmt_ is the string to register, it is copied internally.
|
||||
The _addr_ is the address the string was located at.
|
||||
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_set_function_resolver()_ function returns 0 in case of success, or -1
|
||||
in case of an error.
|
||||
|
||||
The _tep_find_function()_ function returns the function name, or NULL in case
|
||||
it cannot be found.
|
||||
|
||||
The _tep_find_function_address()_ function returns the function start address,
|
||||
or 0 in case it cannot be found.
|
||||
|
||||
The _tep_register_function()_ function returns 0 in case of success. In case of
|
||||
an error -1 is returned, and errno is set to the appropriate error number.
|
||||
|
||||
The _tep_register_print_string()_ function returns 0 in case of success. In case
|
||||
of an error -1 is returned, and errno is set to the appropriate error number.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
char *my_resolve_kernel_addr(void *context,
|
||||
unsigned long long *addrp, char **modp)
|
||||
{
|
||||
struct db *function_database = context;
|
||||
struct symbol *sym = sql_lookup(function_database, *addrp);
|
||||
|
||||
if (!sym)
|
||||
return NULL;
|
||||
|
||||
*modp = sym->module_name;
|
||||
return sym->name;
|
||||
}
|
||||
|
||||
void show_function( unsigned long long addr)
|
||||
{
|
||||
unsigned long long fstart;
|
||||
const char *fname;
|
||||
|
||||
if (tep_set_function_resolver(tep, my_resolve_kernel_addr,
|
||||
function_database) != 0) {
|
||||
/* failed to register my_resolve_kernel_addr */
|
||||
}
|
||||
|
||||
/* These APIs use my_resolve_kernel_addr() to resolve the addr */
|
||||
fname = tep_find_function(tep, addr);
|
||||
fstart = tep_find_function_address(tep, addr);
|
||||
|
||||
/*
|
||||
addr is in function named fname, starting at fstart address,
|
||||
at offset (addr - fstart)
|
||||
*/
|
||||
|
||||
tep_reset_function_resolver(tep);
|
||||
|
||||
}
|
||||
...
|
||||
if (tep_register_function(tep, "kvm_exit",
|
||||
(unsigned long long) 0x12345678, "kvm") != 0) {
|
||||
/* Failed to register kvm_exit address mapping */
|
||||
}
|
||||
...
|
||||
if (tep_register_print_string(tep, "print string",
|
||||
(unsigned long long) 0x87654321, NULL) != 0) {
|
||||
/* Failed to register "print string" address mapping */
|
||||
}
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,88 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_find_function,tep_find_function_address - Find function name / start address.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
const char pass:[*]*tep_find_function*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_);
|
||||
unsigned long long *tep_find_function_address*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
These functions can be used to find function name and start address, by given
|
||||
address. The given address does not have to be exact, it will select the function
|
||||
that would contain it.
|
||||
|
||||
The _tep_find_function()_ function returns the function name, which contains the
|
||||
given address _addr_. The _tep_ argument is the trace event parser context.
|
||||
|
||||
The _tep_find_function_address()_ function returns the function start address,
|
||||
by given address _addr_. The _addr_ does not have to be exact, it will select the
|
||||
function that would contain it. The _tep_ argument is the trace event parser context.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_find_function()_ function returns the function name, or NULL in case
|
||||
it cannot be found.
|
||||
|
||||
The _tep_find_function_address()_ function returns the function start address,
|
||||
or 0 in case it cannot be found.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
void show_function( unsigned long long addr)
|
||||
{
|
||||
const char *fname = tep_find_function(tep, addr);
|
||||
unsigned long long fstart = tep_find_function_address(tep, addr);
|
||||
|
||||
/* addr is in function named fname, starting at fstart address, at offset (addr - fstart) */
|
||||
}
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,101 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_alloc, tep_free,tep_ref, tep_unref,tep_get_ref - Create, destroy, manage
|
||||
references of trace event parser context.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
struct tep_handle pass:[*]*tep_alloc*(void);
|
||||
void *tep_free*(struct tep_handle pass:[*]_tep_);
|
||||
void *tep_ref*(struct tep_handle pass:[*]_tep_);
|
||||
void *tep_unref*(struct tep_handle pass:[*]_tep_);
|
||||
int *tep_get_ref*(struct tep_handle pass:[*]_tep_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
These are the main functions to create and destroy tep_handle - the main
|
||||
structure, representing the trace event parser context. This context is used as
|
||||
the input parameter of most library APIs.
|
||||
|
||||
The _tep_alloc()_ function allocates and initializes the tep context.
|
||||
|
||||
The _tep_free()_ function will decrement the reference of the _tep_ handler.
|
||||
When there is no more references, then it will free the handler, as well
|
||||
as clean up all its resources that it had used. The argument _tep_ is
|
||||
the pointer to the trace event parser context.
|
||||
|
||||
The _tep_ref()_ function adds a reference to the _tep_ handler.
|
||||
|
||||
The _tep_unref()_ function removes a reference from the _tep_ handler. When
|
||||
the last reference is removed, the _tep_ is destroyed, and all resources that
|
||||
it had used are cleaned up.
|
||||
|
||||
The _tep_ref_get()_ functions gets the current references of the _tep_ handler.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
_tep_alloc()_ returns a pointer to a newly created tep_handle structure.
|
||||
NULL is returned in case there is not enough free memory to allocate it.
|
||||
|
||||
_tep_ref_get()_ returns the current references of _tep_.
|
||||
If _tep_ is NULL, 0 is returned.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
int ref = tep_get_ref(tep);
|
||||
tep_ref(tep);
|
||||
if ( (ref+1) != tep_get_ref(tep)) {
|
||||
/* Something wrong happened, the counter is not incremented by 1 */
|
||||
}
|
||||
tep_unref(tep);
|
||||
...
|
||||
tep_free(tep);
|
||||
...
|
||||
--
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,102 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_get_header_page_size, tep_get_header_timestamp_size, tep_is_old_format -
|
||||
Get the data stored in the header page, in kernel context.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
int *tep_get_header_page_size*(struct tep_handle pass:[*]_tep_);
|
||||
int *tep_get_header_timestamp_size*(struct tep_handle pass:[*]_tep_);
|
||||
bool *tep_is_old_format*(struct tep_handle pass:[*]_tep_);
|
||||
--
|
||||
DESCRIPTION
|
||||
-----------
|
||||
These functions retrieve information from kernel context, stored in tracefs
|
||||
events/header_page. Old kernels do not have header page info, so default values
|
||||
from user space context are used.
|
||||
|
||||
The _tep_get_header_page_size()_ function returns the size of a long integer,
|
||||
in kernel context. The _tep_ argument is trace event parser context.
|
||||
This information is retrieved from tracefs events/header_page, "commit" field.
|
||||
|
||||
The _tep_get_header_timestamp_size()_ function returns the size of timestamps,
|
||||
in kernel context. The _tep_ argument is trace event parser context. This
|
||||
information is retrieved from tracefs events/header_page, "timestamp" field.
|
||||
|
||||
The _tep_is_old_format()_ function returns true if the kernel predates
|
||||
the addition of events/header_page, otherwise it returns false.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_get_header_page_size()_ function returns the size of a long integer,
|
||||
in bytes.
|
||||
|
||||
The _tep_get_header_timestamp_size()_ function returns the size of timestamps,
|
||||
in bytes.
|
||||
|
||||
The _tep_is_old_format()_ function returns true, if an old kernel is used to
|
||||
generate the tracing data, which has no event/header_page. If the kernel is new,
|
||||
or _tep_ is NULL, false is returned.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
int longsize;
|
||||
int timesize;
|
||||
bool old;
|
||||
|
||||
longsize = tep_get_header_page_size(tep);
|
||||
timesize = tep_get_header_timestamp_size(tep);
|
||||
old = tep_is_old_format(tep);
|
||||
|
||||
printf ("%s kernel is used to generate the tracing data.\n",
|
||||
old?"Old":"New");
|
||||
printf("The size of a long integer is %d bytes.\n", longsize);
|
||||
printf("The timestamps size is %d bytes.\n", timesize);
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,104 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_is_bigendian, tep_is_local_bigendian, tep_set_local_bigendian - Get / set
|
||||
the endianness of the local machine.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
enum *tep_endian* {
|
||||
TEP_LITTLE_ENDIAN = 0,
|
||||
TEP_BIG_ENDIAN
|
||||
};
|
||||
|
||||
int *tep_is_bigendian*(void);
|
||||
bool *tep_is_local_bigendian*(struct tep_handle pass:[*]_tep_);
|
||||
void *tep_set_local_bigendian*(struct tep_handle pass:[*]_tep_, enum tep_endian _endian_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
The _tep_is_bigendian()_ gets the endianness of the machine, executing
|
||||
the function.
|
||||
|
||||
The _tep_is_local_bigendian()_ function gets the endianness of the local
|
||||
machine, saved in the _tep_ handler. The _tep_ argument is the trace event
|
||||
parser context. This API is a bit faster than _tep_is_bigendian()_, as it
|
||||
returns cached endianness of the local machine instead of checking it each time.
|
||||
|
||||
The _tep_set_local_bigendian()_ function sets the endianness of the local
|
||||
machine in the _tep_ handler. The _tep_ argument is trace event parser context.
|
||||
The _endian_ argument is the endianness:
|
||||
[verse]
|
||||
--
|
||||
_TEP_LITTLE_ENDIAN_ - the machine is little endian,
|
||||
_TEP_BIG_ENDIAN_ - the machine is big endian.
|
||||
--
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_is_bigendian()_ function returns non zero if the endianness of the
|
||||
machine, executing the code, is big endian and zero otherwise.
|
||||
|
||||
The _tep_is_local_bigendian()_ function returns true, if the endianness of the
|
||||
local machine, saved in the _tep_ handler, is big endian, or false otherwise.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
if (tep_is_bigendian())
|
||||
tep_set_local_bigendian(tep, TEP_BIG_ENDIAN);
|
||||
else
|
||||
tep_set_local_bigendian(tep, TEP_LITTLE_ENDIAN);
|
||||
...
|
||||
if (tep_is_local_bigendian(tep))
|
||||
printf("This machine you are running on is bigendian\n");
|
||||
else
|
||||
printf("This machine you are running on is little endian\n");
|
||||
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,78 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_get_long_size, tep_set_long_size - Get / set the size of a long integer on
|
||||
the machine, where the trace is generated, in bytes
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
int *tep_get_long_size*(strucqt tep_handle pass:[*]_tep_);
|
||||
void *tep_set_long_size*(struct tep_handle pass:[*]_tep_, int _long_size_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The _tep_get_long_size()_ function returns the size of a long integer on the machine,
|
||||
where the trace is generated. The _tep_ argument is trace event parser context.
|
||||
|
||||
The _tep_set_long_size()_ function sets the size of a long integer on the machine,
|
||||
where the trace is generated. The _tep_ argument is trace event parser context.
|
||||
The _long_size_ is the size of a long integer, in bytes.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_get_long_size()_ function returns the size of a long integer on the machine,
|
||||
where the trace is generated, in bytes.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
tep_set_long_size(tep, 4);
|
||||
...
|
||||
int long_size = tep_get_long_size(tep);
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,82 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_get_page_size, tep_set_page_size - Get / set the size of a memory page on
|
||||
the machine, where the trace is generated
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
int *tep_get_page_size*(struct tep_handle pass:[*]_tep_);
|
||||
void *tep_set_page_size*(struct tep_handle pass:[*]_tep_, int _page_size_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The _tep_get_page_size()_ function returns the size of a memory page on
|
||||
the machine, where the trace is generated. The _tep_ argument is trace
|
||||
event parser context.
|
||||
|
||||
The _tep_set_page_size()_ function stores in the _tep_ context the size of a
|
||||
memory page on the machine, where the trace is generated.
|
||||
The _tep_ argument is trace event parser context.
|
||||
The _page_size_ argument is the size of a memory page, in bytes.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_get_page_size()_ function returns size of the memory page, in bytes.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <unistd.h>
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
int page_size = getpagesize();
|
||||
|
||||
tep_set_page_size(tep, page_size);
|
||||
|
||||
printf("The page size for this machine is %d\n", tep_get_page_size(tep));
|
||||
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,90 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_parse_event, tep_parse_format - Parse the event format information
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
enum tep_errno *tep_parse_event*(struct tep_handle pass:[*]_tep_, const char pass:[*]_buf_, unsigned long _size_, const char pass:[*]_sys_);
|
||||
enum tep_errno *tep_parse_format*(struct tep_handle pass:[*]_tep_, struct tep_event pass:[*]pass:[*]_eventp_, const char pass:[*]_buf_, unsigned long _size_, const char pass:[*]_sys_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The _tep_parse_event()_ function parses the event format and creates an event
|
||||
structure to quickly parse raw data for a given event. The _tep_ argument is
|
||||
the trace event parser context. The created event structure is stored in the
|
||||
_tep_ context. The _buf_ argument is a buffer with _size_, where the event
|
||||
format data is. The event format data can be taken from
|
||||
tracefs/events/.../.../format files. The _sys_ argument is the system of
|
||||
the event.
|
||||
|
||||
The _tep_parse_format()_ function does the same as _tep_parse_event()_. The only
|
||||
difference is in the extra _eventp_ argument, where the newly created event
|
||||
structure is returned.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
Both _tep_parse_event()_ and _tep_parse_format()_ functions return 0 on success,
|
||||
or TEP_ERRNO__... in case of an error.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
char *buf;
|
||||
int size;
|
||||
struct tep_event *event = NULL;
|
||||
buf = read_file("/sys/kernel/tracing/events/ftrace/print/format", &size);
|
||||
if (tep_parse_event(tep, buf, size, "ftrace") != 0) {
|
||||
/* Failed to parse the ftrace print format */
|
||||
}
|
||||
|
||||
if (tep_parse_format(tep, &event, buf, size, "ftrace") != 0) {
|
||||
/* Failed to parse the ftrace print format */
|
||||
}
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,82 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_parse_header_page - Parses the data stored in the header page.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
int *tep_parse_header_page*(struct tep_handle pass:[*]_tep_, char pass:[*]_buf_, unsigned long _size_, int _long_size_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The _tep_parse_header_page()_ function parses the header page data from _buf_,
|
||||
and initializes the _tep_, trace event parser context, with it. The buffer
|
||||
_buf_ is with _size_, and is supposed to be copied from
|
||||
tracefs/events/header_page.
|
||||
|
||||
Some old kernels do not have header page info, in this case the
|
||||
_tep_parse_header_page()_ function can be called with _size_ equal to 0. The
|
||||
_tep_ context is initialized with default values. The _long_size_ can be used in
|
||||
this use case, to set the size of a long integer to be used.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_parse_header_page()_ function returns 0 in case of success, or -1
|
||||
in case of an error.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
char *buf;
|
||||
int size;
|
||||
buf = read_file("/sys/kernel/tracing/events/header_page", &size);
|
||||
if (tep_parse_header_page(tep, buf, size, sizeof(unsigned long)) != 0) {
|
||||
/* Failed to parse the header page */
|
||||
}
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,122 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_load_plugins, tep_unload_plugins, tep_load_plugins_hook - Load / unload traceevent plugins.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
struct tep_plugin_list pass:[*]*tep_load_plugins*(struct tep_handle pass:[*]_tep_);
|
||||
void *tep_unload_plugins*(struct tep_plugin_list pass:[*]_plugin_list_, struct tep_handle pass:[*]_tep_);
|
||||
void *tep_load_plugins_hook*(struct tep_handle pass:[*]_tep_, const char pass:[*]_suffix_,
|
||||
void (pass:[*]_load_plugin_)(struct tep_handle pass:[*]tep,
|
||||
const char pass:[*]path,
|
||||
const char pass:[*]name,
|
||||
void pass:[*]data),
|
||||
void pass:[*]_data_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The _tep_load_plugins()_ function loads all plugins, located in the plugin
|
||||
directories. The _tep_ argument is trace event parser context.
|
||||
The plugin directories are :
|
||||
[verse]
|
||||
--
|
||||
- Directories, specified in _tep_->plugins_dir with priority TEP_PLUGIN_FIRST
|
||||
- System's plugin directory, defined at the library compile time. It
|
||||
depends on the library installation prefix and usually is
|
||||
_(install_preffix)/lib/traceevent/plugins_
|
||||
- Directory, defined by the environment variable _TRACEEVENT_PLUGIN_DIR_
|
||||
- User's plugin directory, located at _~/.local/lib/traceevent/plugins_
|
||||
- Directories, specified in _tep_->plugins_dir with priority TEP_PLUGIN_LAST
|
||||
--
|
||||
Loading of plugins can be controlled by the _tep_flags_, using the
|
||||
_tep_set_flag()_ API:
|
||||
[verse]
|
||||
--
|
||||
_TEP_DISABLE_SYS_PLUGINS_ - do not load plugins, located in
|
||||
the system's plugin directory.
|
||||
_TEP_DISABLE_PLUGINS_ - do not load any plugins.
|
||||
--
|
||||
The _tep_set_flag()_ API needs to be called before _tep_load_plugins()_, if
|
||||
loading of all plugins is not the desired case.
|
||||
|
||||
The _tep_unload_plugins()_ function unloads the plugins, previously loaded by
|
||||
_tep_load_plugins()_. The _tep_ argument is trace event parser context. The
|
||||
_plugin_list_ is the list of loaded plugins, returned by
|
||||
the _tep_load_plugins()_ function.
|
||||
|
||||
The _tep_load_plugins_hook_ function walks through all directories with plugins
|
||||
and calls user specified _load_plugin()_ hook for each plugin file. Only files
|
||||
with given _suffix_ are considered to be plugins. The _data_ is a user specified
|
||||
context, passed to _load_plugin()_. Directories and the walk order are the same
|
||||
as in _tep_load_plugins()_ API.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_load_plugins()_ function returns a list of successfully loaded plugins,
|
||||
or NULL in case no plugins are loaded.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
struct tep_plugin_list *plugins = tep_load_plugins(tep);
|
||||
if (plugins == NULL) {
|
||||
/* no plugins are loaded */
|
||||
}
|
||||
...
|
||||
tep_unload_plugins(plugins, tep);
|
||||
...
|
||||
void print_plugin(struct tep_handle *tep, const char *path,
|
||||
const char *name, void *data)
|
||||
{
|
||||
pritnf("Found libtraceevent plugin %s/%s\n", path, name);
|
||||
}
|
||||
...
|
||||
tep_load_plugins_hook(tep, ".so", print_plugin, NULL);
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
Linker switch to add when building a program that uses the library.
|
||||
--
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
_libtraceevent(3)_, _trace-cmd(1)_, _tep_set_flag(3)_
|
||||
|
||||
AUTHOR
|
||||
------
|
||||
[verse]
|
||||
--
|
||||
*Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,137 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_data_type, tep_data_pid,tep_data_preempt_count, tep_data_flags -
|
||||
Extract common fields from a record.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
enum *trace_flag_type* {
|
||||
_TRACE_FLAG_IRQS_OFF_,
|
||||
_TRACE_FLAG_IRQS_NOSUPPORT_,
|
||||
_TRACE_FLAG_NEED_RESCHED_,
|
||||
_TRACE_FLAG_HARDIRQ_,
|
||||
_TRACE_FLAG_SOFTIRQ_,
|
||||
};
|
||||
|
||||
int *tep_data_type*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_);
|
||||
int *tep_data_pid*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_);
|
||||
int *tep_data_preempt_count*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_);
|
||||
int *tep_data_flags*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
This set of functions can be used to extract common fields from a record.
|
||||
|
||||
The _tep_data_type()_ function gets the event id from the record _rec_.
|
||||
It reads the "common_type" field. The _tep_ argument is the trace event parser
|
||||
context.
|
||||
|
||||
The _tep_data_pid()_ function gets the process id from the record _rec_.
|
||||
It reads the "common_pid" field. The _tep_ argument is the trace event parser
|
||||
context.
|
||||
|
||||
The _tep_data_preempt_count()_ function gets the preemption count from the
|
||||
record _rec_. It reads the "common_preempt_count" field. The _tep_ argument is
|
||||
the trace event parser context.
|
||||
|
||||
The _tep_data_flags()_ function gets the latency flags from the record _rec_.
|
||||
It reads the "common_flags" field. The _tep_ argument is the trace event parser
|
||||
context. Supported latency flags are:
|
||||
[verse]
|
||||
--
|
||||
_TRACE_FLAG_IRQS_OFF_, Interrupts are disabled.
|
||||
_TRACE_FLAG_IRQS_NOSUPPORT_, Reading IRQ flag is not supported by the architecture.
|
||||
_TRACE_FLAG_NEED_RESCHED_, Task needs rescheduling.
|
||||
_TRACE_FLAG_HARDIRQ_, Hard IRQ is running.
|
||||
_TRACE_FLAG_SOFTIRQ_, Soft IRQ is running.
|
||||
--
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_data_type()_ function returns an integer, representing the event id.
|
||||
|
||||
The _tep_data_pid()_ function returns an integer, representing the process id
|
||||
|
||||
The _tep_data_preempt_count()_ function returns an integer, representing the
|
||||
preemption count.
|
||||
|
||||
The _tep_data_flags()_ function returns an integer, representing the latency
|
||||
flags. Look at the _trace_flag_type_ enum for supported flags.
|
||||
|
||||
All these functions in case of an error return a negative integer.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
void process_record(struct tep_record *record)
|
||||
{
|
||||
int data;
|
||||
|
||||
data = tep_data_type(tep, record);
|
||||
if (data >= 0) {
|
||||
/* Got the ID of the event */
|
||||
}
|
||||
|
||||
data = tep_data_pid(tep, record);
|
||||
if (data >= 0) {
|
||||
/* Got the process ID */
|
||||
}
|
||||
|
||||
data = tep_data_preempt_count(tep, record);
|
||||
if (data >= 0) {
|
||||
/* Got the preemption count */
|
||||
}
|
||||
|
||||
data = tep_data_flags(tep, record);
|
||||
if (data >= 0) {
|
||||
/* Got the latency flags */
|
||||
}
|
||||
}
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,156 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_register_event_handler, tep_unregister_event_handler - Register /
|
||||
unregisters a callback function to parse an event information.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
enum *tep_reg_handler* {
|
||||
_TEP_REGISTER_SUCCESS_,
|
||||
_TEP_REGISTER_SUCCESS_OVERWRITE_,
|
||||
};
|
||||
|
||||
int *tep_register_event_handler*(struct tep_handle pass:[*]_tep_, int _id_, const char pass:[*]_sys_name_, const char pass:[*]_event_name_, tep_event_handler_func _func_, void pass:[*]_context_);
|
||||
int *tep_unregister_event_handler*(struct tep_handle pass:[*]tep, int id, const char pass:[*]sys_name, const char pass:[*]event_name, tep_event_handler_func func, void pass:[*]_context_);
|
||||
|
||||
typedef int (*pass:[*]tep_event_handler_func*)(struct trace_seq pass:[*]s, struct tep_record pass:[*]record, struct tep_event pass:[*]event, void pass:[*]context);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The _tep_register_event_handler()_ function registers a handler function,
|
||||
which is going to be called to parse the information for a given event.
|
||||
The _tep_ argument is the trace event parser context. The _id_ argument is
|
||||
the id of the event. The _sys_name_ argument is the name of the system,
|
||||
the event belongs to. The _event_name_ argument is the name of the event.
|
||||
If _id_ is >= 0, it is used to find the event, otherwise _sys_name_ and
|
||||
_event_name_ are used. The _func_ is a pointer to the function, which is going
|
||||
to be called to parse the event information. The _context_ argument is a pointer
|
||||
to the context data, which will be passed to the _func_. If a handler function
|
||||
for the same event is already registered, it will be overridden with the new
|
||||
one. This mechanism allows a developer to override the parsing of a given event.
|
||||
If for some reason the default print format is not sufficient, the developer
|
||||
can register a function for an event to be used to parse the data instead.
|
||||
|
||||
The _tep_unregister_event_handler()_ function unregisters the handler function,
|
||||
previously registered with _tep_register_event_handler()_. The _tep_ argument
|
||||
is the trace event parser context. The _id_, _sys_name_, _event_name_, _func_,
|
||||
and _context_ are the same arguments, as when the callback function _func_ was
|
||||
registered.
|
||||
|
||||
The _tep_event_handler_func_ is the type of the custom event handler
|
||||
function. The _s_ argument is the trace sequence, it can be used to create a
|
||||
custom string, describing the event. A _record_ to get the event from is passed
|
||||
as input parameter and also the _event_ - the handle to the record's event. The
|
||||
_context_ is custom context, set when the custom event handler is registered.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_register_event_handler()_ function returns _TEP_REGISTER_SUCCESS_
|
||||
if the new handler is registered successfully or
|
||||
_TEP_REGISTER_SUCCESS_OVERWRITE_ if an existing handler is overwritten.
|
||||
If there is not enough memory to complete the registration,
|
||||
TEP_ERRNO__MEM_ALLOC_FAILED is returned.
|
||||
|
||||
The _tep_unregister_event_handler()_ function returns 0 if _func_ was removed
|
||||
successful or, -1 if the event was not found.
|
||||
|
||||
The _tep_event_handler_func_ should return -1 in case of an error,
|
||||
or 0 otherwise.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
#include <trace-seq.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
int timer_expire_handler(struct trace_seq *s, struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
trace_seq_printf(s, "hrtimer=");
|
||||
|
||||
if (tep_print_num_field(s, "0x%llx", event, "timer", record, 0) == -1)
|
||||
tep_print_num_field(s, "0x%llx", event, "hrtimer", record, 1);
|
||||
|
||||
trace_seq_printf(s, " now=");
|
||||
|
||||
tep_print_num_field(s, "%llu", event, "now", record, 1);
|
||||
|
||||
tep_print_func_field(s, " function=%s", event, "function", record, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
...
|
||||
int ret;
|
||||
|
||||
ret = tep_register_event_handler(tep, -1, "timer", "hrtimer_expire_entry",
|
||||
timer_expire_handler, NULL);
|
||||
if (ret < 0) {
|
||||
char buf[32];
|
||||
|
||||
tep_strerror(tep, ret, buf, 32)
|
||||
printf("Failed to register handler for hrtimer_expire_entry: %s\n", buf);
|
||||
} else {
|
||||
switch (ret) {
|
||||
case TEP_REGISTER_SUCCESS:
|
||||
printf ("Registered handler for hrtimer_expire_entry\n");
|
||||
break;
|
||||
case TEP_REGISTER_SUCCESS_OVERWRITE:
|
||||
printf ("Overwrote handler for hrtimer_expire_entry\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
...
|
||||
ret = tep_unregister_event_handler(tep, -1, "timer", "hrtimer_expire_entry",
|
||||
timer_expire_handler, NULL);
|
||||
if ( ret )
|
||||
printf ("Failed to unregister handler for hrtimer_expire_entry\n");
|
||||
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*trace-seq.h*
|
||||
Header file to include in order to have access to trace sequences
|
||||
related APIs. Trace sequences are used to allow a function to call
|
||||
several other functions to create a string of data to use.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,155 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_register_print_function,tep_unregister_print_function -
|
||||
Registers / Unregisters a helper function.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
enum *tep_func_arg_type* {
|
||||
TEP_FUNC_ARG_VOID,
|
||||
TEP_FUNC_ARG_INT,
|
||||
TEP_FUNC_ARG_LONG,
|
||||
TEP_FUNC_ARG_STRING,
|
||||
TEP_FUNC_ARG_PTR,
|
||||
TEP_FUNC_ARG_MAX_TYPES
|
||||
};
|
||||
|
||||
typedef unsigned long long (*pass:[*]tep_func_handler*)(struct trace_seq pass:[*]s, unsigned long long pass:[*]args);
|
||||
|
||||
int *tep_register_print_function*(struct tep_handle pass:[*]_tep_, tep_func_handler _func_, enum tep_func_arg_type _ret_type_, char pass:[*]_name_, _..._);
|
||||
int *tep_unregister_print_function*(struct tep_handle pass:[*]_tep_, tep_func_handler _func_, char pass:[*]_name_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Some events may have helper functions in the print format arguments.
|
||||
This allows a plugin to dynamically create a way to process one of
|
||||
these functions.
|
||||
|
||||
The _tep_register_print_function()_ registers such helper function. The _tep_
|
||||
argument is the trace event parser context. The _func_ argument is a pointer
|
||||
to the helper function. The _ret_type_ argument is the return type of the
|
||||
helper function, value from the _tep_func_arg_type_ enum. The _name_ is the name
|
||||
of the helper function, as seen in the print format arguments. The _..._ is a
|
||||
variable list of _tep_func_arg_type_ enums, the _func_ function arguments.
|
||||
This list must end with _TEP_FUNC_ARG_VOID_. See 'EXAMPLE' section.
|
||||
|
||||
The _tep_unregister_print_function()_ unregisters a helper function, previously
|
||||
registered with _tep_register_print_function()_. The _tep_ argument is the
|
||||
trace event parser context. The _func_ and _name_ arguments are the same, used
|
||||
when the helper function was registered.
|
||||
|
||||
The _tep_func_handler_ is the type of the helper function. The _s_ argument is
|
||||
the trace sequence, it can be used to create a custom string.
|
||||
The _args_ is a list of arguments, defined when the helper function was
|
||||
registered.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_register_print_function()_ function returns 0 in case of success.
|
||||
In case of an error, TEP_ERRNO_... code is returned.
|
||||
|
||||
The _tep_unregister_print_function()_ returns 0 in case of success, or -1 in
|
||||
case of an error.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
Some events have internal functions calls, that appear in the print format
|
||||
output. For example "tracefs/events/i915/g4x_wm/format" has:
|
||||
[source,c]
|
||||
--
|
||||
print fmt: "pipe %c, frame=%u, scanline=%u, wm %d/%d/%d, sr %s/%d/%d/%d, hpll %s/%d/%d/%d, fbc %s",
|
||||
((REC->pipe) + 'A'), REC->frame, REC->scanline, REC->primary,
|
||||
REC->sprite, REC->cursor, yesno(REC->cxsr), REC->sr_plane,
|
||||
REC->sr_cursor, REC->sr_fbc, yesno(REC->hpll), REC->hpll_plane,
|
||||
REC->hpll_cursor, REC->hpll_fbc, yesno(REC->fbc)
|
||||
--
|
||||
Notice the call to function _yesno()_ in the print arguments. In the kernel
|
||||
context, this function has the following implementation:
|
||||
[source,c]
|
||||
--
|
||||
static const char *yesno(int x)
|
||||
{
|
||||
static const char *yes = "yes";
|
||||
static const char *no = "no";
|
||||
|
||||
return x ? yes : no;
|
||||
}
|
||||
--
|
||||
The user space event parser has no idea how to handle this _yesno()_ function.
|
||||
The _tep_register_print_function()_ API can be used to register a user space
|
||||
helper function, mapped to the kernel's _yesno()_:
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
#include <trace-seq.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
static const char *yes_no_helper(int x)
|
||||
{
|
||||
return x ? "yes" : "no";
|
||||
}
|
||||
...
|
||||
if ( tep_register_print_function(tep,
|
||||
yes_no_helper,
|
||||
TEP_FUNC_ARG_STRING,
|
||||
"yesno",
|
||||
TEP_FUNC_ARG_INT,
|
||||
TEP_FUNC_ARG_VOID) != 0) {
|
||||
/* Failed to register yes_no_helper function */
|
||||
}
|
||||
|
||||
/*
|
||||
Now, when the event parser encounters this yesno() function, it will know
|
||||
how to handle it.
|
||||
*/
|
||||
...
|
||||
if (tep_unregister_print_function(tep, yes_no_helper, "yesno") != 0) {
|
||||
/* Failed to unregister yes_no_helper function */
|
||||
}
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*trace-seq.h*
|
||||
Header file to include in order to have access to trace sequences
|
||||
related APIs. Trace sequences are used to allow a function to call
|
||||
several other functions to create a string of data to use.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,104 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_set_flag, tep_clear_flag, tep_test_flag -
|
||||
Manage flags of trace event parser context.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
enum *tep_flag* {
|
||||
_TEP_NSEC_OUTPUT_,
|
||||
_TEP_DISABLE_SYS_PLUGINS_,
|
||||
_TEP_DISABLE_PLUGINS_
|
||||
};
|
||||
void *tep_set_flag*(struct tep_handle pass:[*]_tep_, enum tep_flag _flag_);
|
||||
void *tep_clear_flag*(struct tep_handle pass:[*]_tep_, enum tep_flag _flag_);
|
||||
bool *tep_test_flag*(struct tep_handle pass:[*]_tep_, enum tep_flag _flag_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Trace event parser context flags are defined in *enum tep_flag*:
|
||||
[verse]
|
||||
--
|
||||
_TEP_NSEC_OUTPUT_ - print event's timestamp in nano seconds, instead of micro seconds.
|
||||
_TEP_DISABLE_SYS_PLUGINS_ - disable plugins, located in system's plugin
|
||||
directory. This directory is defined at library compile
|
||||
time, and usually depends on library installation
|
||||
prefix: (install_preffix)/lib/traceevent/plugins
|
||||
_TEP_DISABLE_PLUGINS_ - disable all library plugins:
|
||||
- in system's plugin directory
|
||||
- in directory, defined by the environment variable _TRACEEVENT_PLUGIN_DIR_
|
||||
- in user's home directory, _~/.traceevent/plugins_
|
||||
--
|
||||
Note: plugin related flags must me set before calling _tep_load_plugins()_ API.
|
||||
|
||||
The _tep_set_flag()_ function sets _flag_ to _tep_ context.
|
||||
|
||||
The _tep_clear_flag()_ function clears _flag_ from _tep_ context.
|
||||
|
||||
The _tep_test_flag()_ function tests if _flag_ is set to _tep_ context.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
_tep_test_flag()_ function returns true if _flag_ is set, false otherwise.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
/* Print timestamps in nanoseconds */
|
||||
tep_set_flag(tep, TEP_NSEC_OUTPUT);
|
||||
...
|
||||
if (tep_test_flag(tep, TEP_NSEC_OUTPUT)) {
|
||||
/* print timestamps in nanoseconds */
|
||||
} else {
|
||||
/* print timestamps in microseconds */
|
||||
}
|
||||
...
|
||||
/* Print timestamps in microseconds */
|
||||
tep_clear_flag(tep, TEP_NSEC_OUTPUT);
|
||||
...
|
||||
--
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,85 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
tep_strerror - Returns a string describing regular errno and tep error number.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
int *tep_strerror*(struct tep_handle pass:[*]_tep_, enum tep_errno _errnum_, char pass:[*]_buf_, size_t _buflen_);
|
||||
|
||||
--
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The _tep_strerror()_ function converts tep error number into a human
|
||||
readable string.
|
||||
The _tep_ argument is trace event parser context. The _errnum_ is a regular
|
||||
errno, defined in errno.h, or a tep error number. The string, describing this
|
||||
error number is copied in the _buf_ argument. The _buflen_ argument is
|
||||
the size of the _buf_.
|
||||
|
||||
It as a thread safe wrapper around strerror_r(). The library function has two
|
||||
different behaviors - POSIX and GNU specific. The _tep_strerror()_ API always
|
||||
behaves as the POSIX version - the error string is copied in the user supplied
|
||||
buffer.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _tep_strerror()_ function returns 0, if a valid _errnum_ is passed and the
|
||||
string is copied into _buf_. If _errnum_ is not a valid error number,
|
||||
-1 is returned and _buf_ is not modified.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
...
|
||||
struct tep_handle *tep = tep_alloc();
|
||||
...
|
||||
char buf[32];
|
||||
char *pool = calloc(1, 128);
|
||||
if (tep == NULL) {
|
||||
tep_strerror(tep, TEP_ERRNO__MEM_ALLOC_FAILED, buf, 32);
|
||||
printf ("The pool is not initialized, %s", buf);
|
||||
}
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,158 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
trace_seq_init, trace_seq_destroy, trace_seq_reset, trace_seq_terminate,
|
||||
trace_seq_putc, trace_seq_puts, trace_seq_printf, trace_seq_vprintf,
|
||||
trace_seq_do_fprintf, trace_seq_do_printf -
|
||||
Initialize / destroy a trace sequence.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
*#include <trace-seq.h>*
|
||||
|
||||
void *trace_seq_init*(struct trace_seq pass:[*]_s_);
|
||||
void *trace_seq_destroy*(struct trace_seq pass:[*]_s_);
|
||||
void *trace_seq_reset*(struct trace_seq pass:[*]_s_);
|
||||
void *trace_seq_terminate*(struct trace_seq pass:[*]_s_);
|
||||
int *trace_seq_putc*(struct trace_seq pass:[*]_s_, unsigned char _c_);
|
||||
int *trace_seq_puts*(struct trace_seq pass:[*]_s_, const char pass:[*]_str_);
|
||||
int *trace_seq_printf*(struct trace_seq pass:[*]_s_, const char pass:[*]_fmt_, _..._);
|
||||
int *trace_seq_vprintf*(struct trace_seq pass:[*]_s_, const char pass:[*]_fmt_, va_list _args_);
|
||||
int *trace_seq_do_printf*(struct trace_seq pass:[*]_s_);
|
||||
int *trace_seq_do_fprintf*(struct trace_seq pass:[*]_s_, FILE pass:[*]_fp_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Trace sequences are used to allow a function to call several other functions
|
||||
to create a string of data to use.
|
||||
|
||||
The _trace_seq_init()_ function initializes the trace sequence _s_.
|
||||
|
||||
The _trace_seq_destroy()_ function destroys the trace sequence _s_ and frees
|
||||
all its resources that it had used.
|
||||
|
||||
The _trace_seq_reset()_ function re-initializes the trace sequence _s_. All
|
||||
characters already written in _s_ will be deleted.
|
||||
|
||||
The _trace_seq_terminate()_ function terminates the trace sequence _s_. It puts
|
||||
the null character pass:['\0'] at the end of the buffer.
|
||||
|
||||
The _trace_seq_putc()_ function puts a single character _c_ in the trace
|
||||
sequence _s_.
|
||||
|
||||
The _trace_seq_puts()_ function puts a NULL terminated string _str_ in the
|
||||
trace sequence _s_.
|
||||
|
||||
The _trace_seq_printf()_ function puts a formated string _fmt _with
|
||||
variable arguments _..._ in the trace sequence _s_.
|
||||
|
||||
The _trace_seq_vprintf()_ function puts a formated string _fmt _with
|
||||
list of arguments _args_ in the trace sequence _s_.
|
||||
|
||||
The _trace_seq_do_printf()_ function prints the buffer of trace sequence _s_ to
|
||||
the standard output stdout.
|
||||
|
||||
The _trace_seq_do_fprintf()_ function prints the buffer of trace sequence _s_
|
||||
to the given file _fp_.
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
Both _trace_seq_putc()_ and _trace_seq_puts()_ functions return the number of
|
||||
characters put in the trace sequence, or 0 in case of an error
|
||||
|
||||
Both _trace_seq_printf()_ and _trace_seq_vprintf()_ functions return 0 if the
|
||||
trace oversizes the buffer's free space, the number of characters printed, or
|
||||
a negative value in case of an error.
|
||||
|
||||
Both _trace_seq_do_printf()_ and _trace_seq_do_fprintf()_ functions return the
|
||||
number of printed characters, or -1 in case of an error.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
[source,c]
|
||||
--
|
||||
#include <event-parse.h>
|
||||
#include <trace-seq.h>
|
||||
...
|
||||
struct trace_seq seq;
|
||||
trace_seq_init(&seq);
|
||||
...
|
||||
void foo_seq_print(struct trace_seq *tseq, char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
if (trace_seq_vprintf(tseq, format, ap) <= 0) {
|
||||
/* Failed to print in the trace sequence */
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
trace_seq_reset(&seq);
|
||||
|
||||
char *str = " MAN page example";
|
||||
if (trace_seq_puts(&seq, str) != strlen(str)) {
|
||||
/* Failed to put str in the trace sequence */
|
||||
}
|
||||
if (trace_seq_putc(&seq, ':') != 1) {
|
||||
/* Failed to put ':' in the trace sequence */
|
||||
}
|
||||
if (trace_seq_printf(&seq, " trace sequence: %d", 1) <= 0) {
|
||||
/* Failed to print in the trace sequence */
|
||||
}
|
||||
foo_seq_print( &seq, " %d\n", 2);
|
||||
|
||||
trace_seq_terminate(&seq);
|
||||
...
|
||||
|
||||
if (trace_seq_do_printf(&seq) < 0 ) {
|
||||
/* Failed to print the sequence buffer to the standard output */
|
||||
}
|
||||
FILE *fp = fopen("trace.txt", "w");
|
||||
if (trace_seq_do_fprintf(&seq, fp) < 0 ) [
|
||||
/* Failed to print the sequence buffer to the trace.txt file */
|
||||
}
|
||||
|
||||
trace_seq_destroy(&seq);
|
||||
...
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*trace-seq.h*
|
||||
Header file to include in order to have access to trace sequences related APIs.
|
||||
*-ltraceevent*
|
||||
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>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,192 +0,0 @@
|
||||
libtraceevent(3)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
libtraceevent - Linux kernel trace event library
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
--
|
||||
*#include <event-parse.h>*
|
||||
|
||||
Management of tep handler data structure and access of its members:
|
||||
struct tep_handle pass:[*]*tep_alloc*(void);
|
||||
void *tep_free*(struct tep_handle pass:[*]_tep_);
|
||||
void *tep_ref*(struct tep_handle pass:[*]_tep_);
|
||||
void *tep_unref*(struct tep_handle pass:[*]_tep_);
|
||||
int *tep_get_ref*(struct tep_handle pass:[*]_tep_);
|
||||
void *tep_set_flag*(struct tep_handle pass:[*]_tep_, enum tep_flag _flag_);
|
||||
void *tep_clear_flag*(struct tep_handle pass:[*]_tep_, enum tep_flag _flag_);
|
||||
bool *tep_test_flag*(struct tep_handle pass:[*]_tep_, enum tep_flag _flags_);
|
||||
int *tep_get_cpus*(struct tep_handle pass:[*]_tep_);
|
||||
void *tep_set_cpus*(struct tep_handle pass:[*]_tep_, int _cpus_);
|
||||
int *tep_get_long_size*(strucqt tep_handle pass:[*]_tep_);
|
||||
void *tep_set_long_size*(struct tep_handle pass:[*]_tep_, int _long_size_);
|
||||
int *tep_get_page_size*(struct tep_handle pass:[*]_tep_);
|
||||
void *tep_set_page_size*(struct tep_handle pass:[*]_tep_, int _page_size_);
|
||||
int *tep_get_header_page_size*(struct tep_handle pass:[*]_tep_);
|
||||
int *tep_get_header_timestamp_size*(struct tep_handle pass:[*]_tep_);
|
||||
bool *tep_is_old_format*(struct tep_handle pass:[*]_tep_);
|
||||
int *tep_strerror*(struct tep_handle pass:[*]_tep_, enum tep_errno _errnum_, char pass:[*]_buf_, size_t _buflen_);
|
||||
|
||||
Register / unregister APIs:
|
||||
int *tep_register_function*(struct tep_handle pass:[*]_tep_, char pass:[*]_name_, unsigned long long _addr_, char pass:[*]_mod_);
|
||||
int *tep_register_event_handler*(struct tep_handle pass:[*]_tep_, int _id_, const char pass:[*]_sys_name_, const char pass:[*]_event_name_, tep_event_handler_func _func_, void pass:[*]_context_);
|
||||
int *tep_unregister_event_handler*(struct tep_handle pass:[*]tep, int id, const char pass:[*]sys_name, const char pass:[*]event_name, tep_event_handler_func func, void pass:[*]_context_);
|
||||
int *tep_register_print_string*(struct tep_handle pass:[*]_tep_, const char pass:[*]_fmt_, unsigned long long _addr_);
|
||||
int *tep_register_print_function*(struct tep_handle pass:[*]_tep_, tep_func_handler _func_, enum tep_func_arg_type _ret_type_, char pass:[*]_name_, _..._);
|
||||
int *tep_unregister_print_function*(struct tep_handle pass:[*]_tep_, tep_func_handler _func_, char pass:[*]_name_);
|
||||
|
||||
Plugins management:
|
||||
struct tep_plugin_list pass:[*]*tep_load_plugins*(struct tep_handle pass:[*]_tep_);
|
||||
void *tep_unload_plugins*(struct tep_plugin_list pass:[*]_plugin_list_, struct tep_handle pass:[*]_tep_);
|
||||
char pass:[*]pass:[*]*tep_plugin_list_options*(void);
|
||||
void *tep_plugin_free_options_list*(char pass:[*]pass:[*]_list_);
|
||||
int *tep_plugin_add_options*(const char pass:[*]_name_, struct tep_plugin_option pass:[*]_options_);
|
||||
void *tep_plugin_remove_options*(struct tep_plugin_option pass:[*]_options_);
|
||||
void *tep_print_plugins*(struct trace_seq pass:[*]_s_, const char pass:[*]_prefix_, const char pass:[*]_suffix_, const struct tep_plugin_list pass:[*]_list_);
|
||||
|
||||
Event related APIs:
|
||||
struct tep_event pass:[*]*tep_get_event*(struct tep_handle pass:[*]_tep_, int _index_);
|
||||
struct tep_event pass:[*]*tep_get_first_event*(struct tep_handle pass:[*]_tep_);
|
||||
int *tep_get_events_count*(struct tep_handle pass:[*]_tep_);
|
||||
struct tep_event pass:[*]pass:[*]*tep_list_events*(struct tep_handle pass:[*]_tep_, enum tep_event_sort_type _sort_type_);
|
||||
struct tep_event pass:[*]pass:[*]*tep_list_events_copy*(struct tep_handle pass:[*]_tep_, enum tep_event_sort_type _sort_type_);
|
||||
void *tep_print_event*(struct tep_handle pass:[*]_tep_, struct trace_seq pass:[*]_s_, struct tep_record pass:[*]_record_, const char pass:[*]_fmt_, _..._);
|
||||
|
||||
Event finding:
|
||||
struct tep_event pass:[*]*tep_find_event*(struct tep_handle pass:[*]_tep_, int _id_);
|
||||
struct tep_event pass:[*]*tep_find_event_by_name*(struct tep_handle pass:[*]_tep_, const char pass:[*]_sys_, const char pass:[*]_name_);
|
||||
struct tep_event pass:[*]*tep_find_event_by_record*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_record_);
|
||||
|
||||
Parsing of event files:
|
||||
int *tep_parse_header_page*(struct tep_handle pass:[*]_tep_, char pass:[*]_buf_, unsigned long _size_, int _long_size_);
|
||||
enum tep_errno *tep_parse_event*(struct tep_handle pass:[*]_tep_, const char pass:[*]_buf_, unsigned long _size_, const char pass:[*]_sys_);
|
||||
enum tep_errno *tep_parse_format*(struct tep_handle pass:[*]_tep_, struct tep_event pass:[*]pass:[*]_eventp_, const char pass:[*]_buf_, unsigned long _size_, const char pass:[*]_sys_);
|
||||
|
||||
APIs related to fields from event's format files:
|
||||
struct tep_format_field pass:[*]pass:[*]*tep_event_common_fields*(struct tep_event pass:[*]_event_);
|
||||
struct tep_format_field pass:[*]pass:[*]*tep_event_fields*(struct tep_event pass:[*]_event_);
|
||||
void pass:[*]*tep_get_field_raw*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, int pass:[*]_len_, int _err_);
|
||||
int *tep_get_field_val*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, unsigned long long pass:[*]_val_, int _err_);
|
||||
int *tep_get_common_field_val*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, unsigned long long pass:[*]_val_, int _err_);
|
||||
int *tep_get_any_field_val*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, unsigned long long pass:[*]_val_, int _err_);
|
||||
int *tep_read_number_field*(struct tep_format_field pass:[*]_field_, const void pass:[*]_data_, unsigned long long pass:[*]_value_);
|
||||
|
||||
Event fields printing:
|
||||
void *tep_print_field*(struct trace_seq pass:[*]_s_, void pass:[*]_data_, struct tep_format_field pass:[*]_field_);
|
||||
void *tep_print_fields*(struct trace_seq pass:[*]_s_, void pass:[*]_data_, int _size_, struct tep_event pass:[*]_event_);
|
||||
int *tep_print_num_field*(struct trace_seq pass:[*]_s_, const char pass:[*]_fmt_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, int _err_);
|
||||
int *tep_print_func_field*(struct trace_seq pass:[*]_s_, const char pass:[*]_fmt_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, int _err_);
|
||||
|
||||
Event fields finding:
|
||||
struct tep_format_field pass:[*]*tep_find_common_field*(struct tep_event pass:[*]_event_, const char pass:[*]_name_);
|
||||
struct tep_format_field pass:[*]*tep_find_field*(struct tep_event_ormat pass:[*]_event_, const char pass:[*]_name_);
|
||||
struct tep_format_field pass:[*]*tep_find_any_field*(struct tep_event pass:[*]_event_, const char pass:[*]_name_);
|
||||
|
||||
Functions resolver:
|
||||
int *tep_set_function_resolver*(struct tep_handle pass:[*]_tep_, tep_func_resolver_t pass:[*]_func_, void pass:[*]_priv_);
|
||||
void *tep_reset_function_resolver*(struct tep_handle pass:[*]_tep_);
|
||||
const char pass:[*]*tep_find_function*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_);
|
||||
unsigned long long *tep_find_function_address*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_);
|
||||
|
||||
Filter management:
|
||||
struct tep_event_filter pass:[*]*tep_filter_alloc*(struct tep_handle pass:[*]_tep_);
|
||||
enum tep_errno *tep_filter_add_filter_str*(struct tep_event_filter pass:[*]_filter_, const char pass:[*]_filter_str_);
|
||||
enum tep_errno *tep_filter_match*(struct tep_event_filter pass:[*]_filter_, struct tep_record pass:[*]_record_);
|
||||
int *tep_filter_strerror*(struct tep_event_filter pass:[*]_filter_, enum tep_errno _err_, char pass:[*]buf, size_t _buflen_);
|
||||
int *tep_event_filtered*(struct tep_event_filter pass:[*]_filter_, int _event_id_);
|
||||
void *tep_filter_reset*(struct tep_event_filter pass:[*]_filter_);
|
||||
void *tep_filter_free*(struct tep_event_filter pass:[*]_filter_);
|
||||
char pass:[*]*tep_filter_make_string*(struct tep_event_filter pass:[*]_filter_, int _event_id_);
|
||||
int *tep_filter_remove_event*(struct tep_event_filter pass:[*]_filter_, int _event_id_);
|
||||
int *tep_filter_copy*(struct tep_event_filter pass:[*]_dest_, struct tep_event_filter pass:[*]_source_);
|
||||
int *tep_filter_compare*(struct tep_event_filter pass:[*]_filter1_, struct tep_event_filter pass:[*]_filter2_);
|
||||
|
||||
Parsing various data from the records:
|
||||
int *tep_data_type*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_);
|
||||
int *tep_data_pid*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_);
|
||||
int *tep_data_preempt_count*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_);
|
||||
int *tep_data_flags*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_);
|
||||
|
||||
Command and task related APIs:
|
||||
const char pass:[*]*tep_data_comm_from_pid*(struct tep_handle pass:[*]_tep_, int _pid_);
|
||||
struct cmdline pass:[*]*tep_data_pid_from_comm*(struct tep_handle pass:[*]_tep_, const char pass:[*]_comm_, struct cmdline pass:[*]_next_);
|
||||
int *tep_register_comm*(struct tep_handle pass:[*]_tep_, const char pass:[*]_comm_, int _pid_);
|
||||
int *tep_override_comm*(struct tep_handle pass:[*]_tep_, const char pass:[*]_comm_, int _pid_);
|
||||
bool *tep_is_pid_registered*(struct tep_handle pass:[*]_tep_, int _pid_);
|
||||
int *tep_cmdline_pid*(struct tep_handle pass:[*]_tep_, struct cmdline pass:[*]_cmdline_);
|
||||
|
||||
Endian related APIs:
|
||||
int *tep_is_bigendian*(void);
|
||||
unsigned long long *tep_read_number*(struct tep_handle pass:[*]_tep_, const void pass:[*]_ptr_, int _size_);
|
||||
bool *tep_is_file_bigendian*(struct tep_handle pass:[*]_tep_);
|
||||
void *tep_set_file_bigendian*(struct tep_handle pass:[*]_tep_, enum tep_endian _endian_);
|
||||
bool *tep_is_local_bigendian*(struct tep_handle pass:[*]_tep_);
|
||||
void *tep_set_local_bigendian*(struct tep_handle pass:[*]_tep_, enum tep_endian _endian_);
|
||||
|
||||
Trace sequences:
|
||||
*#include <trace-seq.h>*
|
||||
void *trace_seq_init*(struct trace_seq pass:[*]_s_);
|
||||
void *trace_seq_reset*(struct trace_seq pass:[*]_s_);
|
||||
void *trace_seq_destroy*(struct trace_seq pass:[*]_s_);
|
||||
int *trace_seq_printf*(struct trace_seq pass:[*]_s_, const char pass:[*]_fmt_, ...);
|
||||
int *trace_seq_vprintf*(struct trace_seq pass:[*]_s_, const char pass:[*]_fmt_, va_list _args_);
|
||||
int *trace_seq_puts*(struct trace_seq pass:[*]_s_, const char pass:[*]_str_);
|
||||
int *trace_seq_putc*(struct trace_seq pass:[*]_s_, unsigned char _c_);
|
||||
void *trace_seq_terminate*(struct trace_seq pass:[*]_s_);
|
||||
int *trace_seq_do_fprintf*(struct trace_seq pass:[*]_s_, FILE pass:[*]_fp_);
|
||||
int *trace_seq_do_printf*(struct trace_seq pass:[*]_s_);
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The libtraceevent(3) library provides APIs to access kernel tracepoint events,
|
||||
located in the tracefs file system under the events directory.
|
||||
|
||||
ENVIRONMENT
|
||||
-----------
|
||||
[verse]
|
||||
--
|
||||
TRACEEVENT_PLUGIN_DIR
|
||||
Additional plugin directory. All shared object files, located in this directory will be loaded as traceevent plugins.
|
||||
--
|
||||
|
||||
FILES
|
||||
-----
|
||||
[verse]
|
||||
--
|
||||
*event-parse.h*
|
||||
Header file to include in order to have access to the library APIs.
|
||||
*trace-seq.h*
|
||||
Header file to include in order to have access to trace sequences related APIs.
|
||||
Trace sequences are used to allow a function to call several other functions
|
||||
to create a string of data to use.
|
||||
*-ltraceevent*
|
||||
Linker switch to add when building a program that uses the library.
|
||||
--
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
_trace-cmd(1)_
|
||||
|
||||
AUTHOR
|
||||
------
|
||||
[verse]
|
||||
--
|
||||
*Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*.
|
||||
*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page.
|
||||
--
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report bugs to <linux-trace-devel@vger.kernel.org>
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
libtraceevent is Free Software licensed under the GNU LGPL 2.1
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
@ -1,14 +0,0 @@
|
||||
<!-- 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">▓</xsl:param>
|
||||
<xsl:param name="git.docbook.dot" >⌂</xsl:param>
|
||||
|
||||
</xsl:stylesheet>
|
@ -1,35 +0,0 @@
|
||||
<!-- 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 </xsl:text>
|
||||
<xsl:apply-templates/>
|
||||
<xsl:text> </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 </xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
@ -1,17 +0,0 @@
|
||||
<!-- 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>
|
@ -1,13 +0,0 @@
|
||||
<!-- 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>
|
@ -1,21 +0,0 @@
|
||||
<!-- 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> </xsl:text>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
@ -1,300 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# trace-cmd version
|
||||
EP_VERSION = 1
|
||||
EP_PATCHLEVEL = 1
|
||||
EP_EXTRAVERSION = 0
|
||||
|
||||
# file format version
|
||||
FILE_VERSION = 6
|
||||
|
||||
MAKEFLAGS += --no-print-directory
|
||||
|
||||
|
||||
# Makefiles suck: This macro sets a default value of $(2) for the
|
||||
# variable named by $(1), unless the variable has been set by
|
||||
# environment or command line. This is necessary for CC and AR
|
||||
# because make sets default values, so the simpler ?= approach
|
||||
# won't work as expected.
|
||||
define allow-override
|
||||
$(if $(or $(findstring environment,$(origin $(1))),\
|
||||
$(findstring command line,$(origin $(1)))),,\
|
||||
$(eval $(1) = $(2)))
|
||||
endef
|
||||
|
||||
# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix.
|
||||
$(call allow-override,CC,$(CROSS_COMPILE)gcc)
|
||||
$(call allow-override,AR,$(CROSS_COMPILE)ar)
|
||||
$(call allow-override,NM,$(CROSS_COMPILE)nm)
|
||||
$(call allow-override,PKG_CONFIG,pkg-config)
|
||||
|
||||
EXT = -std=gnu99
|
||||
INSTALL = install
|
||||
|
||||
# Use DESTDIR for installing into a different root directory.
|
||||
# This is useful for building a package. The program will be
|
||||
# installed in this directory as if it was the root directory.
|
||||
# Then the build tool can move it later.
|
||||
DESTDIR ?=
|
||||
DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))'
|
||||
|
||||
LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1)
|
||||
ifeq ($(LP64), 1)
|
||||
libdir_relative_temp = lib64
|
||||
else
|
||||
libdir_relative_temp = lib
|
||||
endif
|
||||
|
||||
libdir_relative ?= $(libdir_relative_temp)
|
||||
prefix ?= /usr/local
|
||||
libdir = $(prefix)/$(libdir_relative)
|
||||
man_dir = $(prefix)/share/man
|
||||
man_dir_SQ = '$(subst ','\'',$(man_dir))'
|
||||
pkgconfig_dir ?= $(word 1,$(shell $(PKG_CONFIG) \
|
||||
--variable pc_path pkg-config | tr ":" " "))
|
||||
includedir_relative = traceevent
|
||||
includedir = $(prefix)/include/$(includedir_relative)
|
||||
includedir_SQ = '$(subst ','\'',$(includedir))'
|
||||
|
||||
export man_dir man_dir_SQ INSTALL
|
||||
export DESTDIR DESTDIR_SQ
|
||||
export EVENT_PARSE_VERSION
|
||||
|
||||
include ../../scripts/Makefile.include
|
||||
|
||||
# copy a bit from Linux kbuild
|
||||
|
||||
ifeq ("$(origin V)", "command line")
|
||||
VERBOSE = $(V)
|
||||
endif
|
||||
ifndef VERBOSE
|
||||
VERBOSE = 0
|
||||
endif
|
||||
|
||||
ifeq ($(srctree),)
|
||||
srctree := $(patsubst %/,%,$(dir $(CURDIR)))
|
||||
srctree := $(patsubst %/,%,$(dir $(srctree)))
|
||||
srctree := $(patsubst %/,%,$(dir $(srctree)))
|
||||
#$(info Determined 'srctree' to be $(srctree))
|
||||
endif
|
||||
|
||||
export prefix libdir src obj
|
||||
|
||||
# Shell quotes
|
||||
libdir_SQ = $(subst ','\'',$(libdir))
|
||||
libdir_relative_SQ = $(subst ','\'',$(libdir_relative))
|
||||
|
||||
CONFIG_INCLUDES =
|
||||
CONFIG_LIBS =
|
||||
CONFIG_FLAGS =
|
||||
|
||||
VERSION = $(EP_VERSION)
|
||||
PATCHLEVEL = $(EP_PATCHLEVEL)
|
||||
EXTRAVERSION = $(EP_EXTRAVERSION)
|
||||
|
||||
OBJ = $@
|
||||
N =
|
||||
|
||||
EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION)
|
||||
|
||||
LIB_TARGET = libtraceevent.a libtraceevent.so.$(EVENT_PARSE_VERSION)
|
||||
LIB_INSTALL = libtraceevent.a libtraceevent.so*
|
||||
LIB_INSTALL := $(addprefix $(OUTPUT),$(LIB_INSTALL))
|
||||
|
||||
INCLUDES = -I. -I $(srctree)/tools/include $(CONFIG_INCLUDES)
|
||||
|
||||
# Set compile option CFLAGS
|
||||
ifdef EXTRA_CFLAGS
|
||||
CFLAGS := $(EXTRA_CFLAGS)
|
||||
else
|
||||
CFLAGS := -g -Wall
|
||||
endif
|
||||
|
||||
# Append required CFLAGS
|
||||
override CFLAGS += -fPIC
|
||||
override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ)
|
||||
override CFLAGS += $(udis86-flags) -D_GNU_SOURCE
|
||||
|
||||
ifeq ($(VERBOSE),1)
|
||||
Q =
|
||||
else
|
||||
Q = @
|
||||
endif
|
||||
|
||||
# Disable command line variables (CFLAGS) override from top
|
||||
# level Makefile (perf), otherwise build Makefile will get
|
||||
# the same command line setup.
|
||||
MAKEOVERRIDES=
|
||||
|
||||
export srctree OUTPUT CC LD CFLAGS V
|
||||
build := -f $(srctree)/tools/build/Makefile.build dir=. obj
|
||||
|
||||
TE_IN := $(OUTPUT)libtraceevent-in.o
|
||||
LIB_TARGET := $(addprefix $(OUTPUT),$(LIB_TARGET))
|
||||
|
||||
CMD_TARGETS = $(LIB_TARGET)
|
||||
|
||||
TARGETS = $(CMD_TARGETS)
|
||||
|
||||
all: all_cmd plugins
|
||||
|
||||
all_cmd: $(CMD_TARGETS)
|
||||
|
||||
$(TE_IN): force
|
||||
$(Q)$(MAKE) $(build)=libtraceevent
|
||||
|
||||
$(OUTPUT)libtraceevent.so.$(EVENT_PARSE_VERSION): $(TE_IN)
|
||||
$(QUIET_LINK)$(CC) --shared $(LDFLAGS) $^ -Wl,-soname,libtraceevent.so.$(EP_VERSION) -o $@
|
||||
@ln -sf $(@F) $(OUTPUT)libtraceevent.so
|
||||
@ln -sf $(@F) $(OUTPUT)libtraceevent.so.$(EP_VERSION)
|
||||
|
||||
$(OUTPUT)libtraceevent.a: $(TE_IN)
|
||||
$(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^
|
||||
|
||||
$(OUTPUT)%.so: $(OUTPUT)%-in.o
|
||||
$(QUIET_LINK)$(CC) $(CFLAGS) -shared $(LDFLAGS) -nostartfiles -o $@ $^
|
||||
|
||||
define make_version.h
|
||||
(echo '/* This file is automatically generated. Do not modify. */'; \
|
||||
echo \#define VERSION_CODE $(shell \
|
||||
expr $(VERSION) \* 256 + $(PATCHLEVEL)); \
|
||||
echo '#define EXTRAVERSION ' $(EXTRAVERSION); \
|
||||
echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \
|
||||
echo '#define FILE_VERSION '$(FILE_VERSION); \
|
||||
) > $1
|
||||
endef
|
||||
|
||||
define update_version.h
|
||||
($(call make_version.h, $@.tmp); \
|
||||
if [ -r $@ ] && cmp -s $@ $@.tmp; then \
|
||||
rm -f $@.tmp; \
|
||||
else \
|
||||
echo ' UPDATE $@'; \
|
||||
mv -f $@.tmp $@; \
|
||||
fi);
|
||||
endef
|
||||
|
||||
ep_version.h: force
|
||||
$(Q)$(N)$(call update_version.h)
|
||||
|
||||
VERSION_FILES = ep_version.h
|
||||
|
||||
define update_dir
|
||||
(echo $1 > $@.tmp; \
|
||||
if [ -r $@ ] && cmp -s $@ $@.tmp; then \
|
||||
rm -f $@.tmp; \
|
||||
else \
|
||||
echo ' UPDATE $@'; \
|
||||
mv -f $@.tmp $@; \
|
||||
fi);
|
||||
endef
|
||||
|
||||
tags: force
|
||||
$(RM) tags
|
||||
find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \
|
||||
--regex-c++='/_PE\(([^,)]*).*/TEP_ERRNO__\1/'
|
||||
|
||||
TAGS: force
|
||||
$(RM) TAGS
|
||||
find . -name '*.[ch]' | xargs etags \
|
||||
--regex='/_PE(\([^,)]*\).*/TEP_ERRNO__\1/'
|
||||
|
||||
define do_install_mkdir
|
||||
if [ ! -d '$(DESTDIR_SQ)$1' ]; then \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$1'; \
|
||||
fi
|
||||
endef
|
||||
|
||||
define do_install
|
||||
$(call do_install_mkdir,$2); \
|
||||
$(INSTALL) $(if $3,-m $3,) $1 '$(DESTDIR_SQ)$2'
|
||||
endef
|
||||
|
||||
PKG_CONFIG_SOURCE_FILE = libtraceevent.pc
|
||||
PKG_CONFIG_FILE := $(addprefix $(OUTPUT),$(PKG_CONFIG_SOURCE_FILE))
|
||||
define do_install_pkgconfig_file
|
||||
if [ -n "${pkgconfig_dir}" ]; then \
|
||||
cp -f ${PKG_CONFIG_SOURCE_FILE}.template ${PKG_CONFIG_FILE}; \
|
||||
sed -i "s|INSTALL_PREFIX|${1}|g" ${PKG_CONFIG_FILE}; \
|
||||
sed -i "s|LIB_VERSION|${EVENT_PARSE_VERSION}|g" ${PKG_CONFIG_FILE}; \
|
||||
sed -i "s|LIB_DIR|${libdir}|g" ${PKG_CONFIG_FILE}; \
|
||||
sed -i "s|HEADER_DIR|$(includedir)|g" ${PKG_CONFIG_FILE}; \
|
||||
$(call do_install,$(PKG_CONFIG_FILE),$(pkgconfig_dir),644); \
|
||||
else \
|
||||
(echo Failed to locate pkg-config directory) 1>&2; \
|
||||
fi
|
||||
endef
|
||||
|
||||
install_lib: all_cmd install_plugins install_headers install_pkgconfig
|
||||
$(call QUIET_INSTALL, $(LIB_TARGET)) \
|
||||
$(call do_install_mkdir,$(libdir_SQ)); \
|
||||
cp -fpR $(LIB_INSTALL) $(DESTDIR)$(libdir_SQ)
|
||||
|
||||
install_pkgconfig:
|
||||
$(call QUIET_INSTALL, $(PKG_CONFIG_FILE)) \
|
||||
$(call do_install_pkgconfig_file,$(prefix))
|
||||
|
||||
install_headers:
|
||||
$(call QUIET_INSTALL, traceevent_headers) \
|
||||
$(call do_install,event-parse.h,$(includedir_SQ),644); \
|
||||
$(call do_install,event-utils.h,$(includedir_SQ),644); \
|
||||
$(call do_install,trace-seq.h,$(includedir_SQ),644); \
|
||||
$(call do_install,kbuffer.h,$(includedir_SQ),644);
|
||||
|
||||
install: install_lib
|
||||
|
||||
clean: clean_plugins
|
||||
$(call QUIET_CLEAN, libtraceevent) \
|
||||
$(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d .*.cmd; \
|
||||
$(RM) TRACEEVENT-CFLAGS tags TAGS; \
|
||||
$(RM) $(PKG_CONFIG_FILE)
|
||||
|
||||
PHONY += doc
|
||||
doc:
|
||||
$(call descend,Documentation)
|
||||
|
||||
PHONY += doc-clean
|
||||
doc-clean:
|
||||
$(call descend,Documentation,clean)
|
||||
|
||||
PHONY += doc-install
|
||||
doc-install:
|
||||
$(call descend,Documentation,install)
|
||||
|
||||
PHONY += doc-uninstall
|
||||
doc-uninstall:
|
||||
$(call descend,Documentation,uninstall)
|
||||
|
||||
PHONY += help
|
||||
help:
|
||||
@echo 'Possible targets:'
|
||||
@echo''
|
||||
@echo ' all - default, compile the library and the'\
|
||||
'plugins'
|
||||
@echo ' plugins - compile the plugins'
|
||||
@echo ' install - install the library, the plugins,'\
|
||||
'the header and pkgconfig files'
|
||||
@echo ' clean - clean the library and the plugins object files'
|
||||
@echo ' doc - compile the documentation files - man'\
|
||||
'and html pages, in the Documentation directory'
|
||||
@echo ' doc-clean - clean the documentation files'
|
||||
@echo ' doc-install - install the man pages'
|
||||
@echo ' doc-uninstall - uninstall the man pages'
|
||||
@echo''
|
||||
|
||||
PHONY += plugins
|
||||
plugins:
|
||||
$(call descend,plugins)
|
||||
|
||||
PHONY += install_plugins
|
||||
install_plugins:
|
||||
$(call descend,plugins,install)
|
||||
|
||||
PHONY += clean_plugins
|
||||
clean_plugins:
|
||||
$(call descend,plugins,clean)
|
||||
|
||||
force:
|
||||
|
||||
# Declare the contents of the .PHONY variable as phony. We keep that
|
||||
# information in a variable so we can use it in if_changed and friends.
|
||||
.PHONY: $(PHONY)
|
@ -1,333 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "event-parse.h"
|
||||
#include "event-parse-local.h"
|
||||
#include "event-utils.h"
|
||||
|
||||
/**
|
||||
* tep_get_event - returns the event with the given index
|
||||
* @tep: a handle to the tep_handle
|
||||
* @index: index of the requested event, in the range 0 .. nr_events
|
||||
*
|
||||
* This returns pointer to the element of the events array with the given index
|
||||
* If @tep is NULL, or @index is not in the range 0 .. nr_events, NULL is returned.
|
||||
*/
|
||||
struct tep_event *tep_get_event(struct tep_handle *tep, int index)
|
||||
{
|
||||
if (tep && tep->events && index < tep->nr_events)
|
||||
return tep->events[index];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_get_first_event - returns the first event in the events array
|
||||
* @tep: a handle to the tep_handle
|
||||
*
|
||||
* This returns pointer to the first element of the events array
|
||||
* If @tep is NULL, NULL is returned.
|
||||
*/
|
||||
struct tep_event *tep_get_first_event(struct tep_handle *tep)
|
||||
{
|
||||
return tep_get_event(tep, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_get_events_count - get the number of defined events
|
||||
* @tep: a handle to the tep_handle
|
||||
*
|
||||
* This returns number of elements in event array
|
||||
* If @tep is NULL, 0 is returned.
|
||||
*/
|
||||
int tep_get_events_count(struct tep_handle *tep)
|
||||
{
|
||||
if (tep)
|
||||
return tep->nr_events;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_set_flag - set event parser flag
|
||||
* @tep: a handle to the tep_handle
|
||||
* @flag: flag, or combination of flags to be set
|
||||
* can be any combination from enum tep_flag
|
||||
*
|
||||
* This sets a flag or combination of flags from enum tep_flag
|
||||
*/
|
||||
void tep_set_flag(struct tep_handle *tep, int flag)
|
||||
{
|
||||
if (tep)
|
||||
tep->flags |= flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_clear_flag - clear event parser flag
|
||||
* @tep: a handle to the tep_handle
|
||||
* @flag: flag to be cleared
|
||||
*
|
||||
* This clears a tep flag
|
||||
*/
|
||||
void tep_clear_flag(struct tep_handle *tep, enum tep_flag flag)
|
||||
{
|
||||
if (tep)
|
||||
tep->flags &= ~flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_test_flag - check the state of event parser flag
|
||||
* @tep: a handle to the tep_handle
|
||||
* @flag: flag to be checked
|
||||
*
|
||||
* This returns the state of the requested tep flag.
|
||||
* Returns: true if the flag is set, false otherwise.
|
||||
*/
|
||||
bool tep_test_flag(struct tep_handle *tep, enum tep_flag flag)
|
||||
{
|
||||
if (tep)
|
||||
return tep->flags & flag;
|
||||
return false;
|
||||
}
|
||||
|
||||
__hidden unsigned short data2host2(struct tep_handle *tep, unsigned short data)
|
||||
{
|
||||
unsigned short swap;
|
||||
|
||||
if (!tep || tep->host_bigendian == tep->file_bigendian)
|
||||
return data;
|
||||
|
||||
swap = ((data & 0xffULL) << 8) |
|
||||
((data & (0xffULL << 8)) >> 8);
|
||||
|
||||
return swap;
|
||||
}
|
||||
|
||||
__hidden unsigned int data2host4(struct tep_handle *tep, unsigned int data)
|
||||
{
|
||||
unsigned int swap;
|
||||
|
||||
if (!tep || tep->host_bigendian == tep->file_bigendian)
|
||||
return data;
|
||||
|
||||
swap = ((data & 0xffULL) << 24) |
|
||||
((data & (0xffULL << 8)) << 8) |
|
||||
((data & (0xffULL << 16)) >> 8) |
|
||||
((data & (0xffULL << 24)) >> 24);
|
||||
|
||||
return swap;
|
||||
}
|
||||
|
||||
__hidden unsigned long long
|
||||
data2host8(struct tep_handle *tep, unsigned long long data)
|
||||
{
|
||||
unsigned long long swap;
|
||||
|
||||
if (!tep || tep->host_bigendian == tep->file_bigendian)
|
||||
return data;
|
||||
|
||||
swap = ((data & 0xffULL) << 56) |
|
||||
((data & (0xffULL << 8)) << 40) |
|
||||
((data & (0xffULL << 16)) << 24) |
|
||||
((data & (0xffULL << 24)) << 8) |
|
||||
((data & (0xffULL << 32)) >> 8) |
|
||||
((data & (0xffULL << 40)) >> 24) |
|
||||
((data & (0xffULL << 48)) >> 40) |
|
||||
((data & (0xffULL << 56)) >> 56);
|
||||
|
||||
return swap;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_get_header_page_size - get size of the header page
|
||||
* @tep: a handle to the tep_handle
|
||||
*
|
||||
* This returns size of the header page
|
||||
* If @tep is NULL, 0 is returned.
|
||||
*/
|
||||
int tep_get_header_page_size(struct tep_handle *tep)
|
||||
{
|
||||
if (tep)
|
||||
return tep->header_page_size_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_get_header_timestamp_size - get size of the timestamp in the header page
|
||||
* @tep: a handle to the tep_handle
|
||||
*
|
||||
* This returns size of the timestamp in the header page
|
||||
* If @tep is NULL, 0 is returned.
|
||||
*/
|
||||
int tep_get_header_timestamp_size(struct tep_handle *tep)
|
||||
{
|
||||
if (tep)
|
||||
return tep->header_page_ts_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_get_cpus - get the number of CPUs
|
||||
* @tep: a handle to the tep_handle
|
||||
*
|
||||
* This returns the number of CPUs
|
||||
* If @tep is NULL, 0 is returned.
|
||||
*/
|
||||
int tep_get_cpus(struct tep_handle *tep)
|
||||
{
|
||||
if (tep)
|
||||
return tep->cpus;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_set_cpus - set the number of CPUs
|
||||
* @tep: a handle to the tep_handle
|
||||
*
|
||||
* This sets the number of CPUs
|
||||
*/
|
||||
void tep_set_cpus(struct tep_handle *tep, int cpus)
|
||||
{
|
||||
if (tep)
|
||||
tep->cpus = cpus;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_get_long_size - get the size of a long integer on the traced machine
|
||||
* @tep: a handle to the tep_handle
|
||||
*
|
||||
* This returns the size of a long integer on the traced machine
|
||||
* If @tep is NULL, 0 is returned.
|
||||
*/
|
||||
int tep_get_long_size(struct tep_handle *tep)
|
||||
{
|
||||
if (tep)
|
||||
return tep->long_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_set_long_size - set the size of a long integer on the traced machine
|
||||
* @tep: a handle to the tep_handle
|
||||
* @size: size, in bytes, of a long integer
|
||||
*
|
||||
* This sets the size of a long integer on the traced machine
|
||||
*/
|
||||
void tep_set_long_size(struct tep_handle *tep, int long_size)
|
||||
{
|
||||
if (tep)
|
||||
tep->long_size = long_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_get_page_size - get the size of a memory page on the traced machine
|
||||
* @tep: a handle to the tep_handle
|
||||
*
|
||||
* This returns the size of a memory page on the traced machine
|
||||
* If @tep is NULL, 0 is returned.
|
||||
*/
|
||||
int tep_get_page_size(struct tep_handle *tep)
|
||||
{
|
||||
if (tep)
|
||||
return tep->page_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_set_page_size - set the size of a memory page on the traced machine
|
||||
* @tep: a handle to the tep_handle
|
||||
* @_page_size: size of a memory page, in bytes
|
||||
*
|
||||
* This sets the size of a memory page on the traced machine
|
||||
*/
|
||||
void tep_set_page_size(struct tep_handle *tep, int _page_size)
|
||||
{
|
||||
if (tep)
|
||||
tep->page_size = _page_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_is_file_bigendian - return the endian of the file
|
||||
* @tep: a handle to the tep_handle
|
||||
*
|
||||
* This returns true if the file is in big endian order
|
||||
* If @tep is NULL, false is returned.
|
||||
*/
|
||||
bool tep_is_file_bigendian(struct tep_handle *tep)
|
||||
{
|
||||
if (tep)
|
||||
return (tep->file_bigendian == TEP_BIG_ENDIAN);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_set_file_bigendian - set if the file is in big endian order
|
||||
* @tep: a handle to the tep_handle
|
||||
* @endian: non zero, if the file is in big endian order
|
||||
*
|
||||
* This sets if the file is in big endian order
|
||||
*/
|
||||
void tep_set_file_bigendian(struct tep_handle *tep, enum tep_endian endian)
|
||||
{
|
||||
if (tep)
|
||||
tep->file_bigendian = endian;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_is_local_bigendian - return the endian of the saved local machine
|
||||
* @tep: a handle to the tep_handle
|
||||
*
|
||||
* This returns true if the saved local machine in @tep is big endian.
|
||||
* If @tep is NULL, false is returned.
|
||||
*/
|
||||
bool tep_is_local_bigendian(struct tep_handle *tep)
|
||||
{
|
||||
if (tep)
|
||||
return (tep->host_bigendian == TEP_BIG_ENDIAN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_set_local_bigendian - set the stored local machine endian order
|
||||
* @tep: a handle to the tep_handle
|
||||
* @endian: non zero, if the local host has big endian order
|
||||
*
|
||||
* This sets the endian order for the local machine.
|
||||
*/
|
||||
void tep_set_local_bigendian(struct tep_handle *tep, enum tep_endian endian)
|
||||
{
|
||||
if (tep)
|
||||
tep->host_bigendian = endian;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_is_old_format - get if an old kernel is used
|
||||
* @tep: a handle to the tep_handle
|
||||
*
|
||||
* This returns true, if an old kernel is used to generate the tracing events or
|
||||
* false if a new kernel is used. Old kernels did not have header page info.
|
||||
* If @tep is NULL, false is returned.
|
||||
*/
|
||||
bool tep_is_old_format(struct tep_handle *tep)
|
||||
{
|
||||
if (tep)
|
||||
return tep->old_format;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_set_test_filters - set a flag to test a filter string
|
||||
* @tep: a handle to the tep_handle
|
||||
* @test_filters: the new value of the test_filters flag
|
||||
*
|
||||
* This sets a flag to test a filter string. If this flag is set, when
|
||||
* tep_filter_add_filter_str() API as called,it will print the filter string
|
||||
* instead of adding it.
|
||||
*/
|
||||
void tep_set_test_filters(struct tep_handle *tep, int test_filters)
|
||||
{
|
||||
if (tep)
|
||||
tep->test_filters = test_filters;
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PARSE_EVENTS_INT_H
|
||||
#define _PARSE_EVENTS_INT_H
|
||||
|
||||
struct tep_cmdline;
|
||||
struct cmdline_list;
|
||||
struct func_map;
|
||||
struct func_list;
|
||||
struct event_handler;
|
||||
struct func_resolver;
|
||||
struct tep_plugins_dir;
|
||||
|
||||
#define __hidden __attribute__((visibility ("hidden")))
|
||||
|
||||
struct tep_handle {
|
||||
int ref_count;
|
||||
|
||||
int header_page_ts_offset;
|
||||
int header_page_ts_size;
|
||||
int header_page_size_offset;
|
||||
int header_page_size_size;
|
||||
int header_page_data_offset;
|
||||
int header_page_data_size;
|
||||
int header_page_overwrite;
|
||||
|
||||
enum tep_endian file_bigendian;
|
||||
enum tep_endian host_bigendian;
|
||||
|
||||
int old_format;
|
||||
|
||||
int cpus;
|
||||
int long_size;
|
||||
int page_size;
|
||||
|
||||
struct tep_cmdline *cmdlines;
|
||||
struct cmdline_list *cmdlist;
|
||||
int cmdline_count;
|
||||
|
||||
struct func_map *func_map;
|
||||
struct func_resolver *func_resolver;
|
||||
struct func_list *funclist;
|
||||
unsigned int func_count;
|
||||
|
||||
struct printk_map *printk_map;
|
||||
struct printk_list *printklist;
|
||||
unsigned int printk_count;
|
||||
|
||||
struct tep_event **events;
|
||||
int nr_events;
|
||||
struct tep_event **sort_events;
|
||||
enum tep_event_sort_type last_type;
|
||||
|
||||
int type_offset;
|
||||
int type_size;
|
||||
|
||||
int pid_offset;
|
||||
int pid_size;
|
||||
|
||||
int pc_offset;
|
||||
int pc_size;
|
||||
|
||||
int flags_offset;
|
||||
int flags_size;
|
||||
|
||||
int ld_offset;
|
||||
int ld_size;
|
||||
|
||||
int test_filters;
|
||||
|
||||
int flags;
|
||||
|
||||
struct tep_format_field *bprint_ip_field;
|
||||
struct tep_format_field *bprint_fmt_field;
|
||||
struct tep_format_field *bprint_buf_field;
|
||||
|
||||
struct event_handler *handlers;
|
||||
struct tep_function_handler *func_handlers;
|
||||
|
||||
/* cache */
|
||||
struct tep_event *last_event;
|
||||
|
||||
struct tep_plugins_dir *plugins_dir;
|
||||
};
|
||||
|
||||
enum tep_print_parse_type {
|
||||
PRINT_FMT_STRING,
|
||||
PRINT_FMT_ARG_DIGIT,
|
||||
PRINT_FMT_ARG_POINTER,
|
||||
PRINT_FMT_ARG_STRING,
|
||||
};
|
||||
|
||||
struct tep_print_parse {
|
||||
struct tep_print_parse *next;
|
||||
|
||||
char *format;
|
||||
int ls;
|
||||
enum tep_print_parse_type type;
|
||||
struct tep_print_arg *arg;
|
||||
struct tep_print_arg *len_as_arg;
|
||||
};
|
||||
|
||||
void free_tep_event(struct tep_event *event);
|
||||
void free_tep_format_field(struct tep_format_field *field);
|
||||
void free_tep_plugin_paths(struct tep_handle *tep);
|
||||
|
||||
unsigned short data2host2(struct tep_handle *tep, unsigned short data);
|
||||
unsigned int data2host4(struct tep_handle *tep, unsigned int data);
|
||||
unsigned long long data2host8(struct tep_handle *tep, unsigned long long data);
|
||||
|
||||
/* access to the internal parser */
|
||||
int peek_char(void);
|
||||
void init_input_buf(const char *buf, unsigned long long size);
|
||||
unsigned long long get_input_buf_ptr(void);
|
||||
const char *get_input_buf(void);
|
||||
enum tep_event_type read_token(char **tok);
|
||||
void free_token(char *tok);
|
||||
|
||||
#endif /* _PARSE_EVENTS_INT_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,750 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1 */
|
||||
/*
|
||||
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*
|
||||
*/
|
||||
#ifndef _PARSE_EVENTS_H
|
||||
#define _PARSE_EVENTS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <regex.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "trace-seq.h"
|
||||
|
||||
#ifndef __maybe_unused
|
||||
#define __maybe_unused __attribute__((unused))
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_RECORD
|
||||
#define DEBUG_RECORD 0
|
||||
#endif
|
||||
|
||||
struct tep_record {
|
||||
unsigned long long ts;
|
||||
unsigned long long offset;
|
||||
long long missed_events; /* buffer dropped events before */
|
||||
int record_size; /* size of binary record */
|
||||
int size; /* size of data */
|
||||
void *data;
|
||||
int cpu;
|
||||
int ref_count;
|
||||
int locked; /* Do not free, even if ref_count is zero */
|
||||
void *priv;
|
||||
#if DEBUG_RECORD
|
||||
struct tep_record *prev;
|
||||
struct tep_record *next;
|
||||
long alloc_addr;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* ----------------------- tep ----------------------- */
|
||||
|
||||
struct tep_handle;
|
||||
struct tep_event;
|
||||
|
||||
typedef int (*tep_event_handler_func)(struct trace_seq *s,
|
||||
struct tep_record *record,
|
||||
struct tep_event *event,
|
||||
void *context);
|
||||
|
||||
typedef int (*tep_plugin_load_func)(struct tep_handle *tep);
|
||||
typedef int (*tep_plugin_unload_func)(struct tep_handle *tep);
|
||||
|
||||
struct tep_plugin_option {
|
||||
struct tep_plugin_option *next;
|
||||
void *handle;
|
||||
char *file;
|
||||
char *name;
|
||||
char *plugin_alias;
|
||||
char *description;
|
||||
const char *value;
|
||||
void *priv;
|
||||
int set;
|
||||
};
|
||||
|
||||
/*
|
||||
* Plugin hooks that can be called:
|
||||
*
|
||||
* TEP_PLUGIN_LOADER: (required)
|
||||
* The function name to initialized the plugin.
|
||||
*
|
||||
* int TEP_PLUGIN_LOADER(struct tep_handle *tep)
|
||||
*
|
||||
* TEP_PLUGIN_UNLOADER: (optional)
|
||||
* The function called just before unloading
|
||||
*
|
||||
* int TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
|
||||
*
|
||||
* TEP_PLUGIN_OPTIONS: (optional)
|
||||
* Plugin options that can be set before loading
|
||||
*
|
||||
* struct tep_plugin_option TEP_PLUGIN_OPTIONS[] = {
|
||||
* {
|
||||
* .name = "option-name",
|
||||
* .plugin_alias = "override-file-name", (optional)
|
||||
* .description = "description of option to show users",
|
||||
* },
|
||||
* {
|
||||
* .name = NULL,
|
||||
* },
|
||||
* };
|
||||
*
|
||||
* Array must end with .name = NULL;
|
||||
*
|
||||
*
|
||||
* .plugin_alias is used to give a shorter name to access
|
||||
* the vairable. Useful if a plugin handles more than one event.
|
||||
*
|
||||
* If .value is not set, then it is considered a boolean and only
|
||||
* .set will be processed. If .value is defined, then it is considered
|
||||
* a string option and .set will be ignored.
|
||||
*
|
||||
* TEP_PLUGIN_ALIAS: (optional)
|
||||
* The name to use for finding options (uses filename if not defined)
|
||||
*/
|
||||
#define TEP_PLUGIN_LOADER tep_plugin_loader
|
||||
#define TEP_PLUGIN_UNLOADER tep_plugin_unloader
|
||||
#define TEP_PLUGIN_OPTIONS tep_plugin_options
|
||||
#define TEP_PLUGIN_ALIAS tep_plugin_alias
|
||||
#define _MAKE_STR(x) #x
|
||||
#define MAKE_STR(x) _MAKE_STR(x)
|
||||
#define TEP_PLUGIN_LOADER_NAME MAKE_STR(TEP_PLUGIN_LOADER)
|
||||
#define TEP_PLUGIN_UNLOADER_NAME MAKE_STR(TEP_PLUGIN_UNLOADER)
|
||||
#define TEP_PLUGIN_OPTIONS_NAME MAKE_STR(TEP_PLUGIN_OPTIONS)
|
||||
#define TEP_PLUGIN_ALIAS_NAME MAKE_STR(TEP_PLUGIN_ALIAS)
|
||||
|
||||
enum tep_format_flags {
|
||||
TEP_FIELD_IS_ARRAY = 1,
|
||||
TEP_FIELD_IS_POINTER = 2,
|
||||
TEP_FIELD_IS_SIGNED = 4,
|
||||
TEP_FIELD_IS_STRING = 8,
|
||||
TEP_FIELD_IS_DYNAMIC = 16,
|
||||
TEP_FIELD_IS_LONG = 32,
|
||||
TEP_FIELD_IS_FLAG = 64,
|
||||
TEP_FIELD_IS_SYMBOLIC = 128,
|
||||
TEP_FIELD_IS_RELATIVE = 256,
|
||||
};
|
||||
|
||||
struct tep_format_field {
|
||||
struct tep_format_field *next;
|
||||
struct tep_event *event;
|
||||
char *type;
|
||||
char *name;
|
||||
char *alias;
|
||||
int offset;
|
||||
int size;
|
||||
unsigned int arraylen;
|
||||
unsigned int elementsize;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
struct tep_format {
|
||||
int nr_common;
|
||||
int nr_fields;
|
||||
struct tep_format_field *common_fields;
|
||||
struct tep_format_field *fields;
|
||||
};
|
||||
|
||||
struct tep_print_arg_atom {
|
||||
char *atom;
|
||||
};
|
||||
|
||||
struct tep_print_arg_string {
|
||||
char *string;
|
||||
struct tep_format_field *field;
|
||||
};
|
||||
|
||||
struct tep_print_arg_bitmask {
|
||||
char *bitmask;
|
||||
struct tep_format_field *field;
|
||||
};
|
||||
|
||||
struct tep_print_arg_field {
|
||||
char *name;
|
||||
struct tep_format_field *field;
|
||||
};
|
||||
|
||||
struct tep_print_flag_sym {
|
||||
struct tep_print_flag_sym *next;
|
||||
char *value;
|
||||
char *str;
|
||||
};
|
||||
|
||||
struct tep_print_arg_typecast {
|
||||
char *type;
|
||||
struct tep_print_arg *item;
|
||||
};
|
||||
|
||||
struct tep_print_arg_flags {
|
||||
struct tep_print_arg *field;
|
||||
char *delim;
|
||||
struct tep_print_flag_sym *flags;
|
||||
};
|
||||
|
||||
struct tep_print_arg_symbol {
|
||||
struct tep_print_arg *field;
|
||||
struct tep_print_flag_sym *symbols;
|
||||
};
|
||||
|
||||
struct tep_print_arg_hex {
|
||||
struct tep_print_arg *field;
|
||||
struct tep_print_arg *size;
|
||||
};
|
||||
|
||||
struct tep_print_arg_int_array {
|
||||
struct tep_print_arg *field;
|
||||
struct tep_print_arg *count;
|
||||
struct tep_print_arg *el_size;
|
||||
};
|
||||
|
||||
struct tep_print_arg_dynarray {
|
||||
struct tep_format_field *field;
|
||||
struct tep_print_arg *index;
|
||||
};
|
||||
|
||||
struct tep_print_arg;
|
||||
|
||||
struct tep_print_arg_op {
|
||||
char *op;
|
||||
int prio;
|
||||
struct tep_print_arg *left;
|
||||
struct tep_print_arg *right;
|
||||
};
|
||||
|
||||
struct tep_function_handler;
|
||||
|
||||
struct tep_print_arg_func {
|
||||
struct tep_function_handler *func;
|
||||
struct tep_print_arg *args;
|
||||
};
|
||||
|
||||
enum tep_print_arg_type {
|
||||
TEP_PRINT_NULL,
|
||||
TEP_PRINT_ATOM,
|
||||
TEP_PRINT_FIELD,
|
||||
TEP_PRINT_FLAGS,
|
||||
TEP_PRINT_SYMBOL,
|
||||
TEP_PRINT_HEX,
|
||||
TEP_PRINT_INT_ARRAY,
|
||||
TEP_PRINT_TYPE,
|
||||
TEP_PRINT_STRING,
|
||||
TEP_PRINT_BSTRING,
|
||||
TEP_PRINT_DYNAMIC_ARRAY,
|
||||
TEP_PRINT_OP,
|
||||
TEP_PRINT_FUNC,
|
||||
TEP_PRINT_BITMASK,
|
||||
TEP_PRINT_DYNAMIC_ARRAY_LEN,
|
||||
TEP_PRINT_HEX_STR,
|
||||
};
|
||||
|
||||
struct tep_print_arg {
|
||||
struct tep_print_arg *next;
|
||||
enum tep_print_arg_type type;
|
||||
union {
|
||||
struct tep_print_arg_atom atom;
|
||||
struct tep_print_arg_field field;
|
||||
struct tep_print_arg_typecast typecast;
|
||||
struct tep_print_arg_flags flags;
|
||||
struct tep_print_arg_symbol symbol;
|
||||
struct tep_print_arg_hex hex;
|
||||
struct tep_print_arg_int_array int_array;
|
||||
struct tep_print_arg_func func;
|
||||
struct tep_print_arg_string string;
|
||||
struct tep_print_arg_bitmask bitmask;
|
||||
struct tep_print_arg_op op;
|
||||
struct tep_print_arg_dynarray dynarray;
|
||||
};
|
||||
};
|
||||
|
||||
struct tep_print_parse;
|
||||
|
||||
struct tep_print_fmt {
|
||||
char *format;
|
||||
struct tep_print_arg *args;
|
||||
struct tep_print_parse *print_cache;
|
||||
};
|
||||
|
||||
struct tep_event {
|
||||
struct tep_handle *tep;
|
||||
char *name;
|
||||
int id;
|
||||
int flags;
|
||||
struct tep_format format;
|
||||
struct tep_print_fmt print_fmt;
|
||||
char *system;
|
||||
tep_event_handler_func handler;
|
||||
void *context;
|
||||
};
|
||||
|
||||
enum {
|
||||
TEP_EVENT_FL_ISFTRACE = 0x01,
|
||||
TEP_EVENT_FL_ISPRINT = 0x02,
|
||||
TEP_EVENT_FL_ISBPRINT = 0x04,
|
||||
TEP_EVENT_FL_ISFUNCENT = 0x10,
|
||||
TEP_EVENT_FL_ISFUNCRET = 0x20,
|
||||
TEP_EVENT_FL_NOHANDLE = 0x40,
|
||||
TEP_EVENT_FL_PRINTRAW = 0x80,
|
||||
|
||||
TEP_EVENT_FL_FAILED = 0x80000000
|
||||
};
|
||||
|
||||
enum tep_event_sort_type {
|
||||
TEP_EVENT_SORT_ID,
|
||||
TEP_EVENT_SORT_NAME,
|
||||
TEP_EVENT_SORT_SYSTEM,
|
||||
};
|
||||
|
||||
enum tep_event_type {
|
||||
TEP_EVENT_ERROR,
|
||||
TEP_EVENT_NONE,
|
||||
TEP_EVENT_SPACE,
|
||||
TEP_EVENT_NEWLINE,
|
||||
TEP_EVENT_OP,
|
||||
TEP_EVENT_DELIM,
|
||||
TEP_EVENT_ITEM,
|
||||
TEP_EVENT_DQUOTE,
|
||||
TEP_EVENT_SQUOTE,
|
||||
};
|
||||
|
||||
typedef unsigned long long (*tep_func_handler)(struct trace_seq *s,
|
||||
unsigned long long *args);
|
||||
|
||||
enum tep_func_arg_type {
|
||||
TEP_FUNC_ARG_VOID,
|
||||
TEP_FUNC_ARG_INT,
|
||||
TEP_FUNC_ARG_LONG,
|
||||
TEP_FUNC_ARG_STRING,
|
||||
TEP_FUNC_ARG_PTR,
|
||||
TEP_FUNC_ARG_MAX_TYPES
|
||||
};
|
||||
|
||||
enum tep_flag {
|
||||
TEP_NSEC_OUTPUT = 1, /* output in NSECS */
|
||||
TEP_DISABLE_SYS_PLUGINS = 1 << 1,
|
||||
TEP_DISABLE_PLUGINS = 1 << 2,
|
||||
};
|
||||
|
||||
#define TEP_ERRORS \
|
||||
_PE(MEM_ALLOC_FAILED, "failed to allocate memory"), \
|
||||
_PE(PARSE_EVENT_FAILED, "failed to parse event"), \
|
||||
_PE(READ_ID_FAILED, "failed to read event id"), \
|
||||
_PE(READ_FORMAT_FAILED, "failed to read event format"), \
|
||||
_PE(READ_PRINT_FAILED, "failed to read event print fmt"), \
|
||||
_PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\
|
||||
_PE(INVALID_ARG_TYPE, "invalid argument type"), \
|
||||
_PE(INVALID_EXP_TYPE, "invalid expression type"), \
|
||||
_PE(INVALID_OP_TYPE, "invalid operator type"), \
|
||||
_PE(INVALID_EVENT_NAME, "invalid event name"), \
|
||||
_PE(EVENT_NOT_FOUND, "no event found"), \
|
||||
_PE(SYNTAX_ERROR, "syntax error"), \
|
||||
_PE(ILLEGAL_RVALUE, "illegal rvalue"), \
|
||||
_PE(ILLEGAL_LVALUE, "illegal lvalue for string comparison"), \
|
||||
_PE(INVALID_REGEX, "regex did not compute"), \
|
||||
_PE(ILLEGAL_STRING_CMP, "illegal comparison for string"), \
|
||||
_PE(ILLEGAL_INTEGER_CMP,"illegal comparison for integer"), \
|
||||
_PE(REPARENT_NOT_OP, "cannot reparent other than OP"), \
|
||||
_PE(REPARENT_FAILED, "failed to reparent filter OP"), \
|
||||
_PE(BAD_FILTER_ARG, "bad arg in filter tree"), \
|
||||
_PE(UNEXPECTED_TYPE, "unexpected type (not a value)"), \
|
||||
_PE(ILLEGAL_TOKEN, "illegal token"), \
|
||||
_PE(INVALID_PAREN, "open parenthesis cannot come here"), \
|
||||
_PE(UNBALANCED_PAREN, "unbalanced number of parenthesis"), \
|
||||
_PE(UNKNOWN_TOKEN, "unknown token"), \
|
||||
_PE(FILTER_NOT_FOUND, "no filter found"), \
|
||||
_PE(NOT_A_NUMBER, "must have number field"), \
|
||||
_PE(NO_FILTER, "no filters exists"), \
|
||||
_PE(FILTER_MISS, "record does not match to filter")
|
||||
|
||||
#undef _PE
|
||||
#define _PE(__code, __str) TEP_ERRNO__ ## __code
|
||||
enum tep_errno {
|
||||
TEP_ERRNO__SUCCESS = 0,
|
||||
TEP_ERRNO__FILTER_MATCH = TEP_ERRNO__SUCCESS,
|
||||
|
||||
/*
|
||||
* Choose an arbitrary negative big number not to clash with standard
|
||||
* errno since SUS requires the errno has distinct positive values.
|
||||
* See 'Issue 6' in the link below.
|
||||
*
|
||||
* https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
|
||||
*/
|
||||
__TEP_ERRNO__START = -100000,
|
||||
|
||||
TEP_ERRORS,
|
||||
|
||||
__TEP_ERRNO__END,
|
||||
};
|
||||
#undef _PE
|
||||
|
||||
struct tep_plugin_list;
|
||||
|
||||
#define INVALID_PLUGIN_LIST_OPTION ((char **)((unsigned long)-1))
|
||||
|
||||
enum tep_plugin_load_priority {
|
||||
TEP_PLUGIN_FIRST,
|
||||
TEP_PLUGIN_LAST,
|
||||
};
|
||||
|
||||
int tep_add_plugin_path(struct tep_handle *tep, char *path,
|
||||
enum tep_plugin_load_priority prio);
|
||||
struct tep_plugin_list *tep_load_plugins(struct tep_handle *tep);
|
||||
void tep_unload_plugins(struct tep_plugin_list *plugin_list,
|
||||
struct tep_handle *tep);
|
||||
void tep_load_plugins_hook(struct tep_handle *tep, const char *suffix,
|
||||
void (*load_plugin)(struct tep_handle *tep,
|
||||
const char *path,
|
||||
const char *name,
|
||||
void *data),
|
||||
void *data);
|
||||
char **tep_plugin_list_options(void);
|
||||
void tep_plugin_free_options_list(char **list);
|
||||
int tep_plugin_add_options(const char *name,
|
||||
struct tep_plugin_option *options);
|
||||
int tep_plugin_add_option(const char *name, const char *val);
|
||||
void tep_plugin_remove_options(struct tep_plugin_option *options);
|
||||
void tep_plugin_print_options(struct trace_seq *s);
|
||||
void tep_print_plugins(struct trace_seq *s,
|
||||
const char *prefix, const char *suffix,
|
||||
const struct tep_plugin_list *list);
|
||||
|
||||
/* tep_handle */
|
||||
typedef char *(tep_func_resolver_t)(void *priv,
|
||||
unsigned long long *addrp, char **modp);
|
||||
void tep_set_flag(struct tep_handle *tep, int flag);
|
||||
void tep_clear_flag(struct tep_handle *tep, enum tep_flag flag);
|
||||
bool tep_test_flag(struct tep_handle *tep, enum tep_flag flags);
|
||||
|
||||
static inline int tep_is_bigendian(void)
|
||||
{
|
||||
unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 };
|
||||
unsigned int val;
|
||||
|
||||
memcpy(&val, str, 4);
|
||||
return val == 0x01020304;
|
||||
}
|
||||
|
||||
/* taken from kernel/trace/trace.h */
|
||||
enum trace_flag_type {
|
||||
TRACE_FLAG_IRQS_OFF = 0x01,
|
||||
TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
|
||||
TRACE_FLAG_NEED_RESCHED = 0x04,
|
||||
TRACE_FLAG_HARDIRQ = 0x08,
|
||||
TRACE_FLAG_SOFTIRQ = 0x10,
|
||||
};
|
||||
|
||||
int tep_set_function_resolver(struct tep_handle *tep,
|
||||
tep_func_resolver_t *func, void *priv);
|
||||
void tep_reset_function_resolver(struct tep_handle *tep);
|
||||
int tep_register_comm(struct tep_handle *tep, const char *comm, int pid);
|
||||
int tep_override_comm(struct tep_handle *tep, const char *comm, int pid);
|
||||
int tep_register_function(struct tep_handle *tep, char *name,
|
||||
unsigned long long addr, char *mod);
|
||||
int tep_register_print_string(struct tep_handle *tep, const char *fmt,
|
||||
unsigned long long addr);
|
||||
bool tep_is_pid_registered(struct tep_handle *tep, int pid);
|
||||
|
||||
struct tep_event *tep_get_event(struct tep_handle *tep, int index);
|
||||
|
||||
#define TEP_PRINT_INFO "INFO"
|
||||
#define TEP_PRINT_INFO_RAW "INFO_RAW"
|
||||
#define TEP_PRINT_COMM "COMM"
|
||||
#define TEP_PRINT_LATENCY "LATENCY"
|
||||
#define TEP_PRINT_NAME "NAME"
|
||||
#define TEP_PRINT_PID 1U
|
||||
#define TEP_PRINT_TIME 2U
|
||||
#define TEP_PRINT_CPU 3U
|
||||
|
||||
void tep_print_event(struct tep_handle *tep, struct trace_seq *s,
|
||||
struct tep_record *record, const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 4, 5)));
|
||||
|
||||
int tep_parse_header_page(struct tep_handle *tep, char *buf, unsigned long size,
|
||||
int long_size);
|
||||
|
||||
enum tep_errno tep_parse_event(struct tep_handle *tep, const char *buf,
|
||||
unsigned long size, const char *sys);
|
||||
enum tep_errno tep_parse_format(struct tep_handle *tep,
|
||||
struct tep_event **eventp,
|
||||
const char *buf,
|
||||
unsigned long size, const char *sys);
|
||||
|
||||
void *tep_get_field_raw(struct trace_seq *s, struct tep_event *event,
|
||||
const char *name, struct tep_record *record,
|
||||
int *len, int err);
|
||||
|
||||
int tep_get_field_val(struct trace_seq *s, struct tep_event *event,
|
||||
const char *name, struct tep_record *record,
|
||||
unsigned long long *val, int err);
|
||||
int tep_get_common_field_val(struct trace_seq *s, struct tep_event *event,
|
||||
const char *name, struct tep_record *record,
|
||||
unsigned long long *val, int err);
|
||||
int tep_get_any_field_val(struct trace_seq *s, struct tep_event *event,
|
||||
const char *name, struct tep_record *record,
|
||||
unsigned long long *val, int err);
|
||||
|
||||
int tep_print_num_field(struct trace_seq *s, const char *fmt,
|
||||
struct tep_event *event, const char *name,
|
||||
struct tep_record *record, int err);
|
||||
|
||||
int tep_print_func_field(struct trace_seq *s, const char *fmt,
|
||||
struct tep_event *event, const char *name,
|
||||
struct tep_record *record, int err);
|
||||
|
||||
enum tep_reg_handler {
|
||||
TEP_REGISTER_SUCCESS = 0,
|
||||
TEP_REGISTER_SUCCESS_OVERWRITE,
|
||||
};
|
||||
|
||||
int tep_register_event_handler(struct tep_handle *tep, int id,
|
||||
const char *sys_name, const char *event_name,
|
||||
tep_event_handler_func func, void *context);
|
||||
int tep_unregister_event_handler(struct tep_handle *tep, int id,
|
||||
const char *sys_name, const char *event_name,
|
||||
tep_event_handler_func func, void *context);
|
||||
int tep_register_print_function(struct tep_handle *tep,
|
||||
tep_func_handler func,
|
||||
enum tep_func_arg_type ret_type,
|
||||
char *name, ...);
|
||||
int tep_unregister_print_function(struct tep_handle *tep,
|
||||
tep_func_handler func, char *name);
|
||||
|
||||
struct tep_format_field *tep_find_common_field(struct tep_event *event, const char *name);
|
||||
struct tep_format_field *tep_find_field(struct tep_event *event, const char *name);
|
||||
struct tep_format_field *tep_find_any_field(struct tep_event *event, const char *name);
|
||||
|
||||
const char *tep_find_function(struct tep_handle *tep, unsigned long long addr);
|
||||
unsigned long long
|
||||
tep_find_function_address(struct tep_handle *tep, unsigned long long addr);
|
||||
unsigned long long tep_read_number(struct tep_handle *tep, const void *ptr, int size);
|
||||
int tep_read_number_field(struct tep_format_field *field, const void *data,
|
||||
unsigned long long *value);
|
||||
|
||||
struct tep_event *tep_get_first_event(struct tep_handle *tep);
|
||||
int tep_get_events_count(struct tep_handle *tep);
|
||||
struct tep_event *tep_find_event(struct tep_handle *tep, int id);
|
||||
|
||||
struct tep_event *
|
||||
tep_find_event_by_name(struct tep_handle *tep, const char *sys, const char *name);
|
||||
struct tep_event *
|
||||
tep_find_event_by_record(struct tep_handle *tep, struct tep_record *record);
|
||||
|
||||
int tep_data_type(struct tep_handle *tep, struct tep_record *rec);
|
||||
int tep_data_pid(struct tep_handle *tep, struct tep_record *rec);
|
||||
int tep_data_preempt_count(struct tep_handle *tep, struct tep_record *rec);
|
||||
int tep_data_flags(struct tep_handle *tep, struct tep_record *rec);
|
||||
const char *tep_data_comm_from_pid(struct tep_handle *tep, int pid);
|
||||
struct tep_cmdline;
|
||||
struct tep_cmdline *tep_data_pid_from_comm(struct tep_handle *tep, const char *comm,
|
||||
struct tep_cmdline *next);
|
||||
int tep_cmdline_pid(struct tep_handle *tep, struct tep_cmdline *cmdline);
|
||||
|
||||
void tep_print_field(struct trace_seq *s, void *data,
|
||||
struct tep_format_field *field);
|
||||
void tep_print_fields(struct trace_seq *s, void *data,
|
||||
int size __maybe_unused, struct tep_event *event);
|
||||
int tep_strerror(struct tep_handle *tep, enum tep_errno errnum,
|
||||
char *buf, size_t buflen);
|
||||
|
||||
struct tep_event **tep_list_events(struct tep_handle *tep, enum tep_event_sort_type);
|
||||
struct tep_event **tep_list_events_copy(struct tep_handle *tep,
|
||||
enum tep_event_sort_type);
|
||||
struct tep_format_field **tep_event_common_fields(struct tep_event *event);
|
||||
struct tep_format_field **tep_event_fields(struct tep_event *event);
|
||||
|
||||
enum tep_endian {
|
||||
TEP_LITTLE_ENDIAN = 0,
|
||||
TEP_BIG_ENDIAN
|
||||
};
|
||||
int tep_get_cpus(struct tep_handle *tep);
|
||||
void tep_set_cpus(struct tep_handle *tep, int cpus);
|
||||
int tep_get_long_size(struct tep_handle *tep);
|
||||
void tep_set_long_size(struct tep_handle *tep, int long_size);
|
||||
int tep_get_page_size(struct tep_handle *tep);
|
||||
void tep_set_page_size(struct tep_handle *tep, int _page_size);
|
||||
bool tep_is_file_bigendian(struct tep_handle *tep);
|
||||
void tep_set_file_bigendian(struct tep_handle *tep, enum tep_endian endian);
|
||||
bool tep_is_local_bigendian(struct tep_handle *tep);
|
||||
void tep_set_local_bigendian(struct tep_handle *tep, enum tep_endian endian);
|
||||
int tep_get_header_page_size(struct tep_handle *tep);
|
||||
int tep_get_header_timestamp_size(struct tep_handle *tep);
|
||||
bool tep_is_old_format(struct tep_handle *tep);
|
||||
void tep_set_test_filters(struct tep_handle *tep, int test_filters);
|
||||
|
||||
struct tep_handle *tep_alloc(void);
|
||||
void tep_free(struct tep_handle *tep);
|
||||
void tep_ref(struct tep_handle *tep);
|
||||
void tep_unref(struct tep_handle *tep);
|
||||
int tep_get_ref(struct tep_handle *tep);
|
||||
|
||||
/* for debugging */
|
||||
void tep_print_funcs(struct tep_handle *tep);
|
||||
void tep_print_printk(struct tep_handle *tep);
|
||||
|
||||
/* ----------------------- filtering ----------------------- */
|
||||
|
||||
enum tep_filter_boolean_type {
|
||||
TEP_FILTER_FALSE,
|
||||
TEP_FILTER_TRUE,
|
||||
};
|
||||
|
||||
enum tep_filter_op_type {
|
||||
TEP_FILTER_OP_AND = 1,
|
||||
TEP_FILTER_OP_OR,
|
||||
TEP_FILTER_OP_NOT,
|
||||
};
|
||||
|
||||
enum tep_filter_cmp_type {
|
||||
TEP_FILTER_CMP_NONE,
|
||||
TEP_FILTER_CMP_EQ,
|
||||
TEP_FILTER_CMP_NE,
|
||||
TEP_FILTER_CMP_GT,
|
||||
TEP_FILTER_CMP_LT,
|
||||
TEP_FILTER_CMP_GE,
|
||||
TEP_FILTER_CMP_LE,
|
||||
TEP_FILTER_CMP_MATCH,
|
||||
TEP_FILTER_CMP_NOT_MATCH,
|
||||
TEP_FILTER_CMP_REGEX,
|
||||
TEP_FILTER_CMP_NOT_REGEX,
|
||||
};
|
||||
|
||||
enum tep_filter_exp_type {
|
||||
TEP_FILTER_EXP_NONE,
|
||||
TEP_FILTER_EXP_ADD,
|
||||
TEP_FILTER_EXP_SUB,
|
||||
TEP_FILTER_EXP_MUL,
|
||||
TEP_FILTER_EXP_DIV,
|
||||
TEP_FILTER_EXP_MOD,
|
||||
TEP_FILTER_EXP_RSHIFT,
|
||||
TEP_FILTER_EXP_LSHIFT,
|
||||
TEP_FILTER_EXP_AND,
|
||||
TEP_FILTER_EXP_OR,
|
||||
TEP_FILTER_EXP_XOR,
|
||||
TEP_FILTER_EXP_NOT,
|
||||
};
|
||||
|
||||
enum tep_filter_arg_type {
|
||||
TEP_FILTER_ARG_NONE,
|
||||
TEP_FILTER_ARG_BOOLEAN,
|
||||
TEP_FILTER_ARG_VALUE,
|
||||
TEP_FILTER_ARG_FIELD,
|
||||
TEP_FILTER_ARG_EXP,
|
||||
TEP_FILTER_ARG_OP,
|
||||
TEP_FILTER_ARG_NUM,
|
||||
TEP_FILTER_ARG_STR,
|
||||
};
|
||||
|
||||
enum tep_filter_value_type {
|
||||
TEP_FILTER_NUMBER,
|
||||
TEP_FILTER_STRING,
|
||||
TEP_FILTER_CHAR
|
||||
};
|
||||
|
||||
struct tep_filter_arg;
|
||||
|
||||
struct tep_filter_arg_boolean {
|
||||
enum tep_filter_boolean_type value;
|
||||
};
|
||||
|
||||
struct tep_filter_arg_field {
|
||||
struct tep_format_field *field;
|
||||
};
|
||||
|
||||
struct tep_filter_arg_value {
|
||||
enum tep_filter_value_type type;
|
||||
union {
|
||||
char *str;
|
||||
unsigned long long val;
|
||||
};
|
||||
};
|
||||
|
||||
struct tep_filter_arg_op {
|
||||
enum tep_filter_op_type type;
|
||||
struct tep_filter_arg *left;
|
||||
struct tep_filter_arg *right;
|
||||
};
|
||||
|
||||
struct tep_filter_arg_exp {
|
||||
enum tep_filter_exp_type type;
|
||||
struct tep_filter_arg *left;
|
||||
struct tep_filter_arg *right;
|
||||
};
|
||||
|
||||
struct tep_filter_arg_num {
|
||||
enum tep_filter_cmp_type type;
|
||||
struct tep_filter_arg *left;
|
||||
struct tep_filter_arg *right;
|
||||
};
|
||||
|
||||
struct tep_filter_arg_str {
|
||||
enum tep_filter_cmp_type type;
|
||||
struct tep_format_field *field;
|
||||
char *val;
|
||||
char *buffer;
|
||||
regex_t reg;
|
||||
};
|
||||
|
||||
struct tep_filter_arg {
|
||||
enum tep_filter_arg_type type;
|
||||
union {
|
||||
struct tep_filter_arg_boolean boolean;
|
||||
struct tep_filter_arg_field field;
|
||||
struct tep_filter_arg_value value;
|
||||
struct tep_filter_arg_op op;
|
||||
struct tep_filter_arg_exp exp;
|
||||
struct tep_filter_arg_num num;
|
||||
struct tep_filter_arg_str str;
|
||||
};
|
||||
};
|
||||
|
||||
struct tep_filter_type {
|
||||
int event_id;
|
||||
struct tep_event *event;
|
||||
struct tep_filter_arg *filter;
|
||||
};
|
||||
|
||||
#define TEP_FILTER_ERROR_BUFSZ 1024
|
||||
|
||||
struct tep_event_filter {
|
||||
struct tep_handle *tep;
|
||||
int filters;
|
||||
struct tep_filter_type *event_filters;
|
||||
char error_buffer[TEP_FILTER_ERROR_BUFSZ];
|
||||
};
|
||||
|
||||
struct tep_event_filter *tep_filter_alloc(struct tep_handle *tep);
|
||||
|
||||
/* for backward compatibility */
|
||||
#define FILTER_NONE TEP_ERRNO__NO_FILTER
|
||||
#define FILTER_NOEXIST TEP_ERRNO__FILTER_NOT_FOUND
|
||||
#define FILTER_MISS TEP_ERRNO__FILTER_MISS
|
||||
#define FILTER_MATCH TEP_ERRNO__FILTER_MATCH
|
||||
|
||||
enum tep_errno tep_filter_add_filter_str(struct tep_event_filter *filter,
|
||||
const char *filter_str);
|
||||
|
||||
enum tep_errno tep_filter_match(struct tep_event_filter *filter,
|
||||
struct tep_record *record);
|
||||
|
||||
int tep_filter_strerror(struct tep_event_filter *filter, enum tep_errno err,
|
||||
char *buf, size_t buflen);
|
||||
|
||||
int tep_event_filtered(struct tep_event_filter *filter,
|
||||
int event_id);
|
||||
|
||||
void tep_filter_reset(struct tep_event_filter *filter);
|
||||
|
||||
void tep_filter_free(struct tep_event_filter *filter);
|
||||
|
||||
char *tep_filter_make_string(struct tep_event_filter *filter, int event_id);
|
||||
|
||||
int tep_filter_remove_event(struct tep_event_filter *filter,
|
||||
int event_id);
|
||||
|
||||
int tep_filter_copy(struct tep_event_filter *dest, struct tep_event_filter *source);
|
||||
|
||||
int tep_filter_compare(struct tep_event_filter *filter1, struct tep_event_filter *filter2);
|
||||
|
||||
#endif /* _PARSE_EVENTS_H */
|
@ -1,711 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include "event-parse.h"
|
||||
#include "event-parse-local.h"
|
||||
#include "event-utils.h"
|
||||
#include "trace-seq.h"
|
||||
|
||||
#define LOCAL_PLUGIN_DIR ".local/lib/traceevent/plugins/"
|
||||
|
||||
static struct registered_plugin_options {
|
||||
struct registered_plugin_options *next;
|
||||
struct tep_plugin_option *options;
|
||||
} *registered_options;
|
||||
|
||||
static struct trace_plugin_options {
|
||||
struct trace_plugin_options *next;
|
||||
char *plugin;
|
||||
char *option;
|
||||
char *value;
|
||||
} *trace_plugin_options;
|
||||
|
||||
struct tep_plugin_list {
|
||||
struct tep_plugin_list *next;
|
||||
char *name;
|
||||
void *handle;
|
||||
};
|
||||
|
||||
struct tep_plugins_dir {
|
||||
struct tep_plugins_dir *next;
|
||||
char *path;
|
||||
enum tep_plugin_load_priority prio;
|
||||
};
|
||||
|
||||
static void lower_case(char *str)
|
||||
{
|
||||
if (!str)
|
||||
return;
|
||||
for (; *str; str++)
|
||||
*str = tolower(*str);
|
||||
}
|
||||
|
||||
static int update_option_value(struct tep_plugin_option *op, const char *val)
|
||||
{
|
||||
char *op_val;
|
||||
|
||||
if (!val) {
|
||||
/* toggle, only if option is boolean */
|
||||
if (op->value)
|
||||
/* Warn? */
|
||||
return 0;
|
||||
op->set ^= 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the option has a value then it takes a string
|
||||
* otherwise the option is a boolean.
|
||||
*/
|
||||
if (op->value) {
|
||||
op->value = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Option is boolean, must be either "1", "0", "true" or "false" */
|
||||
|
||||
op_val = strdup(val);
|
||||
if (!op_val)
|
||||
return -1;
|
||||
lower_case(op_val);
|
||||
|
||||
if (strcmp(val, "1") == 0 || strcmp(val, "true") == 0)
|
||||
op->set = 1;
|
||||
else if (strcmp(val, "0") == 0 || strcmp(val, "false") == 0)
|
||||
op->set = 0;
|
||||
free(op_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_plugin_list_options - get list of plugin options
|
||||
*
|
||||
* Returns an array of char strings that list the currently registered
|
||||
* plugin options in the format of <plugin>:<option>. This list can be
|
||||
* used by toggling the option.
|
||||
*
|
||||
* Returns NULL if there's no options registered. On error it returns
|
||||
* INVALID_PLUGIN_LIST_OPTION
|
||||
*
|
||||
* Must be freed with tep_plugin_free_options_list().
|
||||
*/
|
||||
char **tep_plugin_list_options(void)
|
||||
{
|
||||
struct registered_plugin_options *reg;
|
||||
struct tep_plugin_option *op;
|
||||
char **list = NULL;
|
||||
char *name;
|
||||
int count = 0;
|
||||
|
||||
for (reg = registered_options; reg; reg = reg->next) {
|
||||
for (op = reg->options; op->name; op++) {
|
||||
char *alias = op->plugin_alias ? op->plugin_alias : op->file;
|
||||
char **temp = list;
|
||||
int ret;
|
||||
|
||||
ret = asprintf(&name, "%s:%s", alias, op->name);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
list = realloc(list, count + 2);
|
||||
if (!list) {
|
||||
list = temp;
|
||||
free(name);
|
||||
goto err;
|
||||
}
|
||||
list[count++] = name;
|
||||
list[count] = NULL;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
|
||||
err:
|
||||
while (--count >= 0)
|
||||
free(list[count]);
|
||||
free(list);
|
||||
|
||||
return INVALID_PLUGIN_LIST_OPTION;
|
||||
}
|
||||
|
||||
void tep_plugin_free_options_list(char **list)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
if (list == INVALID_PLUGIN_LIST_OPTION)
|
||||
return;
|
||||
|
||||
for (i = 0; list[i]; i++)
|
||||
free(list[i]);
|
||||
|
||||
free(list);
|
||||
}
|
||||
|
||||
static int
|
||||
update_option(const char *file, struct tep_plugin_option *option)
|
||||
{
|
||||
struct trace_plugin_options *op;
|
||||
char *plugin;
|
||||
int ret = 0;
|
||||
|
||||
if (option->plugin_alias) {
|
||||
plugin = strdup(option->plugin_alias);
|
||||
if (!plugin)
|
||||
return -1;
|
||||
} else {
|
||||
char *p;
|
||||
plugin = strdup(file);
|
||||
if (!plugin)
|
||||
return -1;
|
||||
p = strstr(plugin, ".");
|
||||
if (p)
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
/* first look for named options */
|
||||
for (op = trace_plugin_options; op; op = op->next) {
|
||||
if (!op->plugin)
|
||||
continue;
|
||||
if (strcmp(op->plugin, plugin) != 0)
|
||||
continue;
|
||||
if (strcmp(op->option, option->name) != 0)
|
||||
continue;
|
||||
|
||||
ret = update_option_value(option, op->value);
|
||||
if (ret)
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
|
||||
/* first look for unnamed options */
|
||||
for (op = trace_plugin_options; op; op = op->next) {
|
||||
if (op->plugin)
|
||||
continue;
|
||||
if (strcmp(op->option, option->name) != 0)
|
||||
continue;
|
||||
|
||||
ret = update_option_value(option, op->value);
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
free(plugin);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_plugin_add_options - Add a set of options by a plugin
|
||||
* @name: The name of the plugin adding the options
|
||||
* @options: The set of options being loaded
|
||||
*
|
||||
* Sets the options with the values that have been added by user.
|
||||
*/
|
||||
int tep_plugin_add_options(const char *name,
|
||||
struct tep_plugin_option *options)
|
||||
{
|
||||
struct registered_plugin_options *reg;
|
||||
|
||||
reg = malloc(sizeof(*reg));
|
||||
if (!reg)
|
||||
return -1;
|
||||
reg->next = registered_options;
|
||||
reg->options = options;
|
||||
registered_options = reg;
|
||||
|
||||
while (options->name) {
|
||||
update_option(name, options);
|
||||
options++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_plugin_remove_options - remove plugin options that were registered
|
||||
* @options: Options to removed that were registered with tep_plugin_add_options
|
||||
*/
|
||||
void tep_plugin_remove_options(struct tep_plugin_option *options)
|
||||
{
|
||||
struct registered_plugin_options **last;
|
||||
struct registered_plugin_options *reg;
|
||||
|
||||
for (last = ®istered_options; *last; last = &(*last)->next) {
|
||||
if ((*last)->options == options) {
|
||||
reg = *last;
|
||||
*last = reg->next;
|
||||
free(reg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_option_name(char **option, char **plugin)
|
||||
{
|
||||
char *p;
|
||||
|
||||
*plugin = NULL;
|
||||
|
||||
if ((p = strstr(*option, ":"))) {
|
||||
*plugin = *option;
|
||||
*p = '\0';
|
||||
*option = strdup(p + 1);
|
||||
if (!*option)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct tep_plugin_option *
|
||||
find_registered_option(const char *plugin, const char *option)
|
||||
{
|
||||
struct registered_plugin_options *reg;
|
||||
struct tep_plugin_option *op;
|
||||
const char *op_plugin;
|
||||
|
||||
for (reg = registered_options; reg; reg = reg->next) {
|
||||
for (op = reg->options; op->name; op++) {
|
||||
if (op->plugin_alias)
|
||||
op_plugin = op->plugin_alias;
|
||||
else
|
||||
op_plugin = op->file;
|
||||
|
||||
if (plugin && strcmp(plugin, op_plugin) != 0)
|
||||
continue;
|
||||
if (strcmp(option, op->name) != 0)
|
||||
continue;
|
||||
|
||||
return op;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int process_option(const char *plugin, const char *option, const char *val)
|
||||
{
|
||||
struct tep_plugin_option *op;
|
||||
|
||||
op = find_registered_option(plugin, option);
|
||||
if (!op)
|
||||
return 0;
|
||||
|
||||
return update_option_value(op, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_plugin_add_option - add an option/val pair to set plugin options
|
||||
* @name: The name of the option (format: <plugin>:<option> or just <option>)
|
||||
* @val: (optional) the value for the option
|
||||
*
|
||||
* Modify a plugin option. If @val is given than the value of the option
|
||||
* is set (note, some options just take a boolean, so @val must be either
|
||||
* "1" or "0" or "true" or "false").
|
||||
*/
|
||||
int tep_plugin_add_option(const char *name, const char *val)
|
||||
{
|
||||
struct trace_plugin_options *op;
|
||||
char *option_str;
|
||||
char *plugin;
|
||||
|
||||
option_str = strdup(name);
|
||||
if (!option_str)
|
||||
return -ENOMEM;
|
||||
|
||||
if (parse_option_name(&option_str, &plugin) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
/* If the option exists, update the val */
|
||||
for (op = trace_plugin_options; op; op = op->next) {
|
||||
/* Both must be NULL or not NULL */
|
||||
if ((!plugin || !op->plugin) && plugin != op->plugin)
|
||||
continue;
|
||||
if (plugin && strcmp(plugin, op->plugin) != 0)
|
||||
continue;
|
||||
if (strcmp(op->option, option_str) != 0)
|
||||
continue;
|
||||
|
||||
/* update option */
|
||||
free(op->value);
|
||||
if (val) {
|
||||
op->value = strdup(val);
|
||||
if (!op->value)
|
||||
goto out_free;
|
||||
} else
|
||||
op->value = NULL;
|
||||
|
||||
/* plugin and option_str don't get freed at the end */
|
||||
free(plugin);
|
||||
free(option_str);
|
||||
|
||||
plugin = op->plugin;
|
||||
option_str = op->option;
|
||||
break;
|
||||
}
|
||||
|
||||
/* If not found, create */
|
||||
if (!op) {
|
||||
op = malloc(sizeof(*op));
|
||||
if (!op)
|
||||
goto out_free;
|
||||
memset(op, 0, sizeof(*op));
|
||||
op->plugin = plugin;
|
||||
op->option = option_str;
|
||||
if (val) {
|
||||
op->value = strdup(val);
|
||||
if (!op->value) {
|
||||
free(op);
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
op->next = trace_plugin_options;
|
||||
trace_plugin_options = op;
|
||||
}
|
||||
|
||||
return process_option(plugin, option_str, val);
|
||||
|
||||
out_free:
|
||||
free(plugin);
|
||||
free(option_str);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void print_op_data(struct trace_seq *s, const char *name,
|
||||
const char *op)
|
||||
{
|
||||
if (op)
|
||||
trace_seq_printf(s, "%8s:\t%s\n", name, op);
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_plugin_print_options - print out the registered plugin options
|
||||
* @s: The trace_seq descriptor to write the plugin options into
|
||||
*
|
||||
* Writes a list of options into trace_seq @s.
|
||||
*/
|
||||
void tep_plugin_print_options(struct trace_seq *s)
|
||||
{
|
||||
struct registered_plugin_options *reg;
|
||||
struct tep_plugin_option *op;
|
||||
|
||||
for (reg = registered_options; reg; reg = reg->next) {
|
||||
if (reg != registered_options)
|
||||
trace_seq_printf(s, "============\n");
|
||||
for (op = reg->options; op->name; op++) {
|
||||
if (op != reg->options)
|
||||
trace_seq_printf(s, "------------\n");
|
||||
print_op_data(s, "file", op->file);
|
||||
print_op_data(s, "plugin", op->plugin_alias);
|
||||
print_op_data(s, "option", op->name);
|
||||
print_op_data(s, "desc", op->description);
|
||||
print_op_data(s, "value", op->value);
|
||||
trace_seq_printf(s, "%8s:\t%d\n", "set", op->set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_print_plugins - print out the list of plugins loaded
|
||||
* @s: the trace_seq descripter to write to
|
||||
* @prefix: The prefix string to add before listing the option name
|
||||
* @suffix: The suffix string ot append after the option name
|
||||
* @list: The list of plugins (usually returned by tep_load_plugins()
|
||||
*
|
||||
* Writes to the trace_seq @s the list of plugins (files) that is
|
||||
* returned by tep_load_plugins(). Use @prefix and @suffix for formating:
|
||||
* @prefix = " ", @suffix = "\n".
|
||||
*/
|
||||
void tep_print_plugins(struct trace_seq *s,
|
||||
const char *prefix, const char *suffix,
|
||||
const struct tep_plugin_list *list)
|
||||
{
|
||||
while (list) {
|
||||
trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix);
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
load_plugin(struct tep_handle *tep, const char *path,
|
||||
const char *file, void *data)
|
||||
{
|
||||
struct tep_plugin_list **plugin_list = data;
|
||||
struct tep_plugin_option *options;
|
||||
tep_plugin_load_func func;
|
||||
struct tep_plugin_list *list;
|
||||
const char *alias;
|
||||
char *plugin;
|
||||
void *handle;
|
||||
int ret;
|
||||
|
||||
ret = asprintf(&plugin, "%s/%s", path, file);
|
||||
if (ret < 0) {
|
||||
warning("could not allocate plugin memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (!handle) {
|
||||
warning("could not load plugin '%s'\n%s\n",
|
||||
plugin, dlerror());
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
alias = dlsym(handle, TEP_PLUGIN_ALIAS_NAME);
|
||||
if (!alias)
|
||||
alias = file;
|
||||
|
||||
options = dlsym(handle, TEP_PLUGIN_OPTIONS_NAME);
|
||||
if (options) {
|
||||
while (options->name) {
|
||||
ret = update_option(alias, options);
|
||||
if (ret < 0)
|
||||
goto out_free;
|
||||
options++;
|
||||
}
|
||||
}
|
||||
|
||||
func = dlsym(handle, TEP_PLUGIN_LOADER_NAME);
|
||||
if (!func) {
|
||||
warning("could not find func '%s' in plugin '%s'\n%s\n",
|
||||
TEP_PLUGIN_LOADER_NAME, plugin, dlerror());
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
list = malloc(sizeof(*list));
|
||||
if (!list) {
|
||||
warning("could not allocate plugin memory\n");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
list->next = *plugin_list;
|
||||
list->handle = handle;
|
||||
list->name = plugin;
|
||||
*plugin_list = list;
|
||||
|
||||
pr_stat("registering plugin: %s", plugin);
|
||||
func(tep);
|
||||
return;
|
||||
|
||||
out_free:
|
||||
free(plugin);
|
||||
}
|
||||
|
||||
static void
|
||||
load_plugins_dir(struct tep_handle *tep, const char *suffix,
|
||||
const char *path,
|
||||
void (*load_plugin)(struct tep_handle *tep,
|
||||
const char *path,
|
||||
const char *name,
|
||||
void *data),
|
||||
void *data)
|
||||
{
|
||||
struct dirent *dent;
|
||||
struct stat st;
|
||||
DIR *dir;
|
||||
int ret;
|
||||
|
||||
ret = stat(path, &st);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
if (!S_ISDIR(st.st_mode))
|
||||
return;
|
||||
|
||||
dir = opendir(path);
|
||||
if (!dir)
|
||||
return;
|
||||
|
||||
while ((dent = readdir(dir))) {
|
||||
const char *name = dent->d_name;
|
||||
|
||||
if (strcmp(name, ".") == 0 ||
|
||||
strcmp(name, "..") == 0)
|
||||
continue;
|
||||
|
||||
/* Only load plugins that end in suffix */
|
||||
if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0)
|
||||
continue;
|
||||
|
||||
load_plugin(tep, path, name, data);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_load_plugins_hook - call a user specified callback to load a plugin
|
||||
* @tep: handler to traceevent context
|
||||
* @suffix: filter only plugin files with given suffix
|
||||
* @load_plugin: user specified callback, called for each plugin file
|
||||
* @data: custom context, passed to @load_plugin
|
||||
*
|
||||
* Searches for traceevent plugin files and calls @load_plugin for each
|
||||
* The order of plugins search is:
|
||||
* - Directories, specified in @tep->plugins_dir and priority TEP_PLUGIN_FIRST
|
||||
* - Directory, specified at compile time with PLUGIN_TRACEEVENT_DIR
|
||||
* - Directory, specified by environment variable TRACEEVENT_PLUGIN_DIR
|
||||
* - In user's home: ~/.local/lib/traceevent/plugins/
|
||||
* - Directories, specified in @tep->plugins_dir and priority TEP_PLUGIN_LAST
|
||||
*
|
||||
*/
|
||||
void tep_load_plugins_hook(struct tep_handle *tep, const char *suffix,
|
||||
void (*load_plugin)(struct tep_handle *tep,
|
||||
const char *path,
|
||||
const char *name,
|
||||
void *data),
|
||||
void *data)
|
||||
{
|
||||
struct tep_plugins_dir *dir = NULL;
|
||||
char *home;
|
||||
char *path;
|
||||
char *envdir;
|
||||
int ret;
|
||||
|
||||
if (tep && tep->flags & TEP_DISABLE_PLUGINS)
|
||||
return;
|
||||
|
||||
if (tep)
|
||||
dir = tep->plugins_dir;
|
||||
while (dir) {
|
||||
if (dir->prio == TEP_PLUGIN_FIRST)
|
||||
load_plugins_dir(tep, suffix, dir->path,
|
||||
load_plugin, data);
|
||||
dir = dir->next;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a system plugin directory was defined,
|
||||
* check that first.
|
||||
*/
|
||||
#ifdef PLUGIN_DIR
|
||||
if (!tep || !(tep->flags & TEP_DISABLE_SYS_PLUGINS))
|
||||
load_plugins_dir(tep, suffix, PLUGIN_DIR,
|
||||
load_plugin, data);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Next let the environment-set plugin directory
|
||||
* override the system defaults.
|
||||
*/
|
||||
envdir = getenv("TRACEEVENT_PLUGIN_DIR");
|
||||
if (envdir)
|
||||
load_plugins_dir(tep, suffix, envdir, load_plugin, data);
|
||||
|
||||
/*
|
||||
* Now let the home directory override the environment
|
||||
* or system defaults.
|
||||
*/
|
||||
home = getenv("HOME");
|
||||
if (!home)
|
||||
return;
|
||||
|
||||
ret = asprintf(&path, "%s/%s", home, LOCAL_PLUGIN_DIR);
|
||||
if (ret < 0) {
|
||||
warning("could not allocate plugin memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
load_plugins_dir(tep, suffix, path, load_plugin, data);
|
||||
|
||||
if (tep)
|
||||
dir = tep->plugins_dir;
|
||||
while (dir) {
|
||||
if (dir->prio == TEP_PLUGIN_LAST)
|
||||
load_plugins_dir(tep, suffix, dir->path,
|
||||
load_plugin, data);
|
||||
dir = dir->next;
|
||||
}
|
||||
|
||||
free(path);
|
||||
}
|
||||
|
||||
struct tep_plugin_list*
|
||||
tep_load_plugins(struct tep_handle *tep)
|
||||
{
|
||||
struct tep_plugin_list *list = NULL;
|
||||
|
||||
tep_load_plugins_hook(tep, ".so", load_plugin, &list);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* tep_add_plugin_path - Add a new plugin directory.
|
||||
* @tep: Trace event handler.
|
||||
* @path: Path to a directory. All plugin files in that
|
||||
* directory will be loaded.
|
||||
*@prio: Load priority of the plugins in that directory.
|
||||
*
|
||||
* Returns -1 in case of an error, 0 otherwise.
|
||||
*/
|
||||
int tep_add_plugin_path(struct tep_handle *tep, char *path,
|
||||
enum tep_plugin_load_priority prio)
|
||||
{
|
||||
struct tep_plugins_dir *dir;
|
||||
|
||||
if (!tep || !path)
|
||||
return -1;
|
||||
|
||||
dir = calloc(1, sizeof(*dir));
|
||||
if (!dir)
|
||||
return -1;
|
||||
|
||||
dir->path = strdup(path);
|
||||
if (!dir->path) {
|
||||
free(dir);
|
||||
return -1;
|
||||
}
|
||||
dir->prio = prio;
|
||||
dir->next = tep->plugins_dir;
|
||||
tep->plugins_dir = dir;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__hidden void free_tep_plugin_paths(struct tep_handle *tep)
|
||||
{
|
||||
struct tep_plugins_dir *dir;
|
||||
|
||||
if (!tep)
|
||||
return;
|
||||
|
||||
dir = tep->plugins_dir;
|
||||
while (dir) {
|
||||
tep->plugins_dir = tep->plugins_dir->next;
|
||||
free(dir->path);
|
||||
free(dir);
|
||||
dir = tep->plugins_dir;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tep_unload_plugins(struct tep_plugin_list *plugin_list, struct tep_handle *tep)
|
||||
{
|
||||
tep_plugin_unload_func func;
|
||||
struct tep_plugin_list *list;
|
||||
|
||||
while (plugin_list) {
|
||||
list = plugin_list;
|
||||
plugin_list = list->next;
|
||||
func = dlsym(list->handle, TEP_PLUGIN_UNLOADER_NAME);
|
||||
if (func)
|
||||
func(tep);
|
||||
dlclose(list->handle);
|
||||
free(list->name);
|
||||
free(list);
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1 */
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*
|
||||
*/
|
||||
#ifndef __UTIL_H
|
||||
#define __UTIL_H
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
/* Can be overridden */
|
||||
void warning(const char *fmt, ...);
|
||||
void pr_stat(const char *fmt, ...);
|
||||
void vpr_stat(const char *fmt, va_list ap);
|
||||
|
||||
/* Always available */
|
||||
void __warning(const char *fmt, ...);
|
||||
void __pr_stat(const char *fmt, ...);
|
||||
|
||||
void __vwarning(const char *fmt, ...);
|
||||
void __vpr_stat(const char *fmt, ...);
|
||||
|
||||
#define min(x, y) ({ \
|
||||
typeof(x) _min1 = (x); \
|
||||
typeof(y) _min2 = (y); \
|
||||
(void) (&_min1 == &_min2); \
|
||||
_min1 < _min2 ? _min1 : _min2; })
|
||||
|
||||
static inline char *strim(char *string)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
if (!string)
|
||||
return NULL;
|
||||
while (*string) {
|
||||
if (!isspace(*string))
|
||||
break;
|
||||
string++;
|
||||
}
|
||||
ret = string;
|
||||
|
||||
string = ret + strlen(ret) - 1;
|
||||
while (string > ret) {
|
||||
if (!isspace(*string))
|
||||
break;
|
||||
string--;
|
||||
}
|
||||
string[1] = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int has_text(const char *text)
|
||||
{
|
||||
if (!text)
|
||||
return 0;
|
||||
|
||||
while (*text) {
|
||||
if (!isspace(*text))
|
||||
return 1;
|
||||
text++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,809 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "kbuffer.h"
|
||||
|
||||
#define MISSING_EVENTS (1UL << 31)
|
||||
#define MISSING_STORED (1UL << 30)
|
||||
|
||||
#define COMMIT_MASK ((1 << 27) - 1)
|
||||
|
||||
enum {
|
||||
KBUFFER_FL_HOST_BIG_ENDIAN = (1<<0),
|
||||
KBUFFER_FL_BIG_ENDIAN = (1<<1),
|
||||
KBUFFER_FL_LONG_8 = (1<<2),
|
||||
KBUFFER_FL_OLD_FORMAT = (1<<3),
|
||||
};
|
||||
|
||||
#define ENDIAN_MASK (KBUFFER_FL_HOST_BIG_ENDIAN | KBUFFER_FL_BIG_ENDIAN)
|
||||
|
||||
/** kbuffer
|
||||
* @timestamp - timestamp of current event
|
||||
* @lost_events - # of lost events between this subbuffer and previous
|
||||
* @flags - special flags of the kbuffer
|
||||
* @subbuffer - pointer to the sub-buffer page
|
||||
* @data - pointer to the start of data on the sub-buffer page
|
||||
* @index - index from @data to the @curr event data
|
||||
* @curr - offset from @data to the start of current event
|
||||
* (includes metadata)
|
||||
* @next - offset from @data to the start of next event
|
||||
* @size - The size of data on @data
|
||||
* @start - The offset from @subbuffer where @data lives
|
||||
*
|
||||
* @read_4 - Function to read 4 raw bytes (may swap)
|
||||
* @read_8 - Function to read 8 raw bytes (may swap)
|
||||
* @read_long - Function to read a long word (4 or 8 bytes with needed swap)
|
||||
*/
|
||||
struct kbuffer {
|
||||
unsigned long long timestamp;
|
||||
long long lost_events;
|
||||
unsigned long flags;
|
||||
void *subbuffer;
|
||||
void *data;
|
||||
unsigned int index;
|
||||
unsigned int curr;
|
||||
unsigned int next;
|
||||
unsigned int size;
|
||||
unsigned int start;
|
||||
|
||||
unsigned int (*read_4)(void *ptr);
|
||||
unsigned long long (*read_8)(void *ptr);
|
||||
unsigned long long (*read_long)(struct kbuffer *kbuf, void *ptr);
|
||||
int (*next_event)(struct kbuffer *kbuf);
|
||||
};
|
||||
|
||||
static void *zmalloc(size_t size)
|
||||
{
|
||||
return calloc(1, size);
|
||||
}
|
||||
|
||||
static int host_is_bigendian(void)
|
||||
{
|
||||
unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 };
|
||||
unsigned int *ptr;
|
||||
|
||||
ptr = (unsigned int *)str;
|
||||
return *ptr == 0x01020304;
|
||||
}
|
||||
|
||||
static int do_swap(struct kbuffer *kbuf)
|
||||
{
|
||||
return ((kbuf->flags & KBUFFER_FL_HOST_BIG_ENDIAN) + kbuf->flags) &
|
||||
ENDIAN_MASK;
|
||||
}
|
||||
|
||||
static unsigned long long __read_8(void *ptr)
|
||||
{
|
||||
unsigned long long data = *(unsigned long long *)ptr;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static unsigned long long __read_8_sw(void *ptr)
|
||||
{
|
||||
unsigned long long data = *(unsigned long long *)ptr;
|
||||
unsigned long long swap;
|
||||
|
||||
swap = ((data & 0xffULL) << 56) |
|
||||
((data & (0xffULL << 8)) << 40) |
|
||||
((data & (0xffULL << 16)) << 24) |
|
||||
((data & (0xffULL << 24)) << 8) |
|
||||
((data & (0xffULL << 32)) >> 8) |
|
||||
((data & (0xffULL << 40)) >> 24) |
|
||||
((data & (0xffULL << 48)) >> 40) |
|
||||
((data & (0xffULL << 56)) >> 56);
|
||||
|
||||
return swap;
|
||||
}
|
||||
|
||||
static unsigned int __read_4(void *ptr)
|
||||
{
|
||||
unsigned int data = *(unsigned int *)ptr;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static unsigned int __read_4_sw(void *ptr)
|
||||
{
|
||||
unsigned int data = *(unsigned int *)ptr;
|
||||
unsigned int swap;
|
||||
|
||||
swap = ((data & 0xffULL) << 24) |
|
||||
((data & (0xffULL << 8)) << 8) |
|
||||
((data & (0xffULL << 16)) >> 8) |
|
||||
((data & (0xffULL << 24)) >> 24);
|
||||
|
||||
return swap;
|
||||
}
|
||||
|
||||
static unsigned long long read_8(struct kbuffer *kbuf, void *ptr)
|
||||
{
|
||||
return kbuf->read_8(ptr);
|
||||
}
|
||||
|
||||
static unsigned int read_4(struct kbuffer *kbuf, void *ptr)
|
||||
{
|
||||
return kbuf->read_4(ptr);
|
||||
}
|
||||
|
||||
static unsigned long long __read_long_8(struct kbuffer *kbuf, void *ptr)
|
||||
{
|
||||
return kbuf->read_8(ptr);
|
||||
}
|
||||
|
||||
static unsigned long long __read_long_4(struct kbuffer *kbuf, void *ptr)
|
||||
{
|
||||
return kbuf->read_4(ptr);
|
||||
}
|
||||
|
||||
static unsigned long long read_long(struct kbuffer *kbuf, void *ptr)
|
||||
{
|
||||
return kbuf->read_long(kbuf, ptr);
|
||||
}
|
||||
|
||||
static int calc_index(struct kbuffer *kbuf, void *ptr)
|
||||
{
|
||||
return (unsigned long)ptr - (unsigned long)kbuf->data;
|
||||
}
|
||||
|
||||
static int __next_event(struct kbuffer *kbuf);
|
||||
|
||||
/**
|
||||
* kbuffer_alloc - allocat a new kbuffer
|
||||
* @size; enum to denote size of word
|
||||
* @endian: enum to denote endianness
|
||||
*
|
||||
* Allocates and returns a new kbuffer.
|
||||
*/
|
||||
struct kbuffer *
|
||||
kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian)
|
||||
{
|
||||
struct kbuffer *kbuf;
|
||||
int flags = 0;
|
||||
|
||||
switch (size) {
|
||||
case KBUFFER_LSIZE_4:
|
||||
break;
|
||||
case KBUFFER_LSIZE_8:
|
||||
flags |= KBUFFER_FL_LONG_8;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (endian) {
|
||||
case KBUFFER_ENDIAN_LITTLE:
|
||||
break;
|
||||
case KBUFFER_ENDIAN_BIG:
|
||||
flags |= KBUFFER_FL_BIG_ENDIAN;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kbuf = zmalloc(sizeof(*kbuf));
|
||||
if (!kbuf)
|
||||
return NULL;
|
||||
|
||||
kbuf->flags = flags;
|
||||
|
||||
if (host_is_bigendian())
|
||||
kbuf->flags |= KBUFFER_FL_HOST_BIG_ENDIAN;
|
||||
|
||||
if (do_swap(kbuf)) {
|
||||
kbuf->read_8 = __read_8_sw;
|
||||
kbuf->read_4 = __read_4_sw;
|
||||
} else {
|
||||
kbuf->read_8 = __read_8;
|
||||
kbuf->read_4 = __read_4;
|
||||
}
|
||||
|
||||
if (kbuf->flags & KBUFFER_FL_LONG_8)
|
||||
kbuf->read_long = __read_long_8;
|
||||
else
|
||||
kbuf->read_long = __read_long_4;
|
||||
|
||||
/* May be changed by kbuffer_set_old_format() */
|
||||
kbuf->next_event = __next_event;
|
||||
|
||||
return kbuf;
|
||||
}
|
||||
|
||||
/** kbuffer_free - free an allocated kbuffer
|
||||
* @kbuf: The kbuffer to free
|
||||
*
|
||||
* Can take NULL as a parameter.
|
||||
*/
|
||||
void kbuffer_free(struct kbuffer *kbuf)
|
||||
{
|
||||
free(kbuf);
|
||||
}
|
||||
|
||||
static unsigned int type4host(struct kbuffer *kbuf,
|
||||
unsigned int type_len_ts)
|
||||
{
|
||||
if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
|
||||
return (type_len_ts >> 29) & 3;
|
||||
else
|
||||
return type_len_ts & 3;
|
||||
}
|
||||
|
||||
static unsigned int len4host(struct kbuffer *kbuf,
|
||||
unsigned int type_len_ts)
|
||||
{
|
||||
if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
|
||||
return (type_len_ts >> 27) & 7;
|
||||
else
|
||||
return (type_len_ts >> 2) & 7;
|
||||
}
|
||||
|
||||
static unsigned int type_len4host(struct kbuffer *kbuf,
|
||||
unsigned int type_len_ts)
|
||||
{
|
||||
if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
|
||||
return (type_len_ts >> 27) & ((1 << 5) - 1);
|
||||
else
|
||||
return type_len_ts & ((1 << 5) - 1);
|
||||
}
|
||||
|
||||
static unsigned int ts4host(struct kbuffer *kbuf,
|
||||
unsigned int type_len_ts)
|
||||
{
|
||||
if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
|
||||
return type_len_ts & ((1 << 27) - 1);
|
||||
else
|
||||
return type_len_ts >> 5;
|
||||
}
|
||||
|
||||
/*
|
||||
* Linux 2.6.30 and earlier (not much ealier) had a different
|
||||
* ring buffer format. It should be obsolete, but we handle it anyway.
|
||||
*/
|
||||
enum old_ring_buffer_type {
|
||||
OLD_RINGBUF_TYPE_PADDING,
|
||||
OLD_RINGBUF_TYPE_TIME_EXTEND,
|
||||
OLD_RINGBUF_TYPE_TIME_STAMP,
|
||||
OLD_RINGBUF_TYPE_DATA,
|
||||
};
|
||||
|
||||
static unsigned int old_update_pointers(struct kbuffer *kbuf)
|
||||
{
|
||||
unsigned long long extend;
|
||||
unsigned int type_len_ts;
|
||||
unsigned int type;
|
||||
unsigned int len;
|
||||
unsigned int delta;
|
||||
unsigned int length;
|
||||
void *ptr = kbuf->data + kbuf->curr;
|
||||
|
||||
type_len_ts = read_4(kbuf, ptr);
|
||||
ptr += 4;
|
||||
|
||||
type = type4host(kbuf, type_len_ts);
|
||||
len = len4host(kbuf, type_len_ts);
|
||||
delta = ts4host(kbuf, type_len_ts);
|
||||
|
||||
switch (type) {
|
||||
case OLD_RINGBUF_TYPE_PADDING:
|
||||
kbuf->next = kbuf->size;
|
||||
return 0;
|
||||
|
||||
case OLD_RINGBUF_TYPE_TIME_EXTEND:
|
||||
extend = read_4(kbuf, ptr);
|
||||
extend <<= TS_SHIFT;
|
||||
extend += delta;
|
||||
delta = extend;
|
||||
ptr += 4;
|
||||
length = 0;
|
||||
break;
|
||||
|
||||
case OLD_RINGBUF_TYPE_TIME_STAMP:
|
||||
/* should never happen! */
|
||||
kbuf->curr = kbuf->size;
|
||||
kbuf->next = kbuf->size;
|
||||
kbuf->index = kbuf->size;
|
||||
return -1;
|
||||
default:
|
||||
if (len)
|
||||
length = len * 4;
|
||||
else {
|
||||
length = read_4(kbuf, ptr);
|
||||
length -= 4;
|
||||
ptr += 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
kbuf->timestamp += delta;
|
||||
kbuf->index = calc_index(kbuf, ptr);
|
||||
kbuf->next = kbuf->index + length;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
static int __old_next_event(struct kbuffer *kbuf)
|
||||
{
|
||||
int type;
|
||||
|
||||
do {
|
||||
kbuf->curr = kbuf->next;
|
||||
if (kbuf->next >= kbuf->size)
|
||||
return -1;
|
||||
type = old_update_pointers(kbuf);
|
||||
} while (type == OLD_RINGBUF_TYPE_TIME_EXTEND || type == OLD_RINGBUF_TYPE_PADDING);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
translate_data(struct kbuffer *kbuf, void *data, void **rptr,
|
||||
unsigned long long *delta, int *length)
|
||||
{
|
||||
unsigned long long extend;
|
||||
unsigned int type_len_ts;
|
||||
unsigned int type_len;
|
||||
|
||||
type_len_ts = read_4(kbuf, data);
|
||||
data += 4;
|
||||
|
||||
type_len = type_len4host(kbuf, type_len_ts);
|
||||
*delta = ts4host(kbuf, type_len_ts);
|
||||
|
||||
switch (type_len) {
|
||||
case KBUFFER_TYPE_PADDING:
|
||||
*length = read_4(kbuf, data);
|
||||
break;
|
||||
|
||||
case KBUFFER_TYPE_TIME_EXTEND:
|
||||
case KBUFFER_TYPE_TIME_STAMP:
|
||||
extend = read_4(kbuf, data);
|
||||
data += 4;
|
||||
extend <<= TS_SHIFT;
|
||||
extend += *delta;
|
||||
*delta = extend;
|
||||
*length = 0;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
*length = read_4(kbuf, data) - 4;
|
||||
*length = (*length + 3) & ~3;
|
||||
data += 4;
|
||||
break;
|
||||
default:
|
||||
*length = type_len * 4;
|
||||
break;
|
||||
}
|
||||
|
||||
*rptr = data;
|
||||
|
||||
return type_len;
|
||||
}
|
||||
|
||||
static unsigned int update_pointers(struct kbuffer *kbuf)
|
||||
{
|
||||
unsigned long long delta;
|
||||
unsigned int type_len;
|
||||
int length;
|
||||
void *ptr = kbuf->data + kbuf->curr;
|
||||
|
||||
type_len = translate_data(kbuf, ptr, &ptr, &delta, &length);
|
||||
|
||||
if (type_len == KBUFFER_TYPE_TIME_STAMP)
|
||||
kbuf->timestamp = delta;
|
||||
else
|
||||
kbuf->timestamp += delta;
|
||||
|
||||
kbuf->index = calc_index(kbuf, ptr);
|
||||
kbuf->next = kbuf->index + length;
|
||||
|
||||
return type_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* kbuffer_translate_data - read raw data to get a record
|
||||
* @swap: Set to 1 if bytes in words need to be swapped when read
|
||||
* @data: The raw data to read
|
||||
* @size: Address to store the size of the event data.
|
||||
*
|
||||
* Returns a pointer to the event data. To determine the entire
|
||||
* record size (record metadata + data) just add the difference between
|
||||
* @data and the returned value to @size.
|
||||
*/
|
||||
void *kbuffer_translate_data(int swap, void *data, unsigned int *size)
|
||||
{
|
||||
unsigned long long delta;
|
||||
struct kbuffer kbuf;
|
||||
int type_len;
|
||||
int length;
|
||||
void *ptr;
|
||||
|
||||
if (swap) {
|
||||
kbuf.read_8 = __read_8_sw;
|
||||
kbuf.read_4 = __read_4_sw;
|
||||
kbuf.flags = host_is_bigendian() ? 0 : KBUFFER_FL_BIG_ENDIAN;
|
||||
} else {
|
||||
kbuf.read_8 = __read_8;
|
||||
kbuf.read_4 = __read_4;
|
||||
kbuf.flags = host_is_bigendian() ? KBUFFER_FL_BIG_ENDIAN: 0;
|
||||
}
|
||||
|
||||
type_len = translate_data(&kbuf, data, &ptr, &delta, &length);
|
||||
switch (type_len) {
|
||||
case KBUFFER_TYPE_PADDING:
|
||||
case KBUFFER_TYPE_TIME_EXTEND:
|
||||
case KBUFFER_TYPE_TIME_STAMP:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*size = length;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static int __next_event(struct kbuffer *kbuf)
|
||||
{
|
||||
int type;
|
||||
|
||||
do {
|
||||
kbuf->curr = kbuf->next;
|
||||
if (kbuf->next >= kbuf->size)
|
||||
return -1;
|
||||
type = update_pointers(kbuf);
|
||||
} while (type == KBUFFER_TYPE_TIME_EXTEND ||
|
||||
type == KBUFFER_TYPE_TIME_STAMP ||
|
||||
type == KBUFFER_TYPE_PADDING);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int next_event(struct kbuffer *kbuf)
|
||||
{
|
||||
return kbuf->next_event(kbuf);
|
||||
}
|
||||
|
||||
/**
|
||||
* kbuffer_next_event - increment the current pointer
|
||||
* @kbuf: The kbuffer to read
|
||||
* @ts: Address to store the next record's timestamp (may be NULL to ignore)
|
||||
*
|
||||
* Increments the pointers into the subbuffer of the kbuffer to point to the
|
||||
* next event so that the next kbuffer_read_event() will return a
|
||||
* new event.
|
||||
*
|
||||
* Returns the data of the next event if a new event exists on the subbuffer,
|
||||
* NULL otherwise.
|
||||
*/
|
||||
void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!kbuf || !kbuf->subbuffer)
|
||||
return NULL;
|
||||
|
||||
ret = next_event(kbuf);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
|
||||
if (ts)
|
||||
*ts = kbuf->timestamp;
|
||||
|
||||
return kbuf->data + kbuf->index;
|
||||
}
|
||||
|
||||
/**
|
||||
* kbuffer_load_subbuffer - load a new subbuffer into the kbuffer
|
||||
* @kbuf: The kbuffer to load
|
||||
* @subbuffer: The subbuffer to load into @kbuf.
|
||||
*
|
||||
* Load a new subbuffer (page) into @kbuf. This will reset all
|
||||
* the pointers and update the @kbuf timestamp. The next read will
|
||||
* return the first event on @subbuffer.
|
||||
*
|
||||
* Returns 0 on succes, -1 otherwise.
|
||||
*/
|
||||
int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer)
|
||||
{
|
||||
unsigned long long flags;
|
||||
void *ptr = subbuffer;
|
||||
|
||||
if (!kbuf || !subbuffer)
|
||||
return -1;
|
||||
|
||||
kbuf->subbuffer = subbuffer;
|
||||
|
||||
kbuf->timestamp = read_8(kbuf, ptr);
|
||||
ptr += 8;
|
||||
|
||||
kbuf->curr = 0;
|
||||
|
||||
if (kbuf->flags & KBUFFER_FL_LONG_8)
|
||||
kbuf->start = 16;
|
||||
else
|
||||
kbuf->start = 12;
|
||||
|
||||
kbuf->data = subbuffer + kbuf->start;
|
||||
|
||||
flags = read_long(kbuf, ptr);
|
||||
kbuf->size = (unsigned int)flags & COMMIT_MASK;
|
||||
|
||||
if (flags & MISSING_EVENTS) {
|
||||
if (flags & MISSING_STORED) {
|
||||
ptr = kbuf->data + kbuf->size;
|
||||
kbuf->lost_events = read_long(kbuf, ptr);
|
||||
} else
|
||||
kbuf->lost_events = -1;
|
||||
} else
|
||||
kbuf->lost_events = 0;
|
||||
|
||||
kbuf->index = 0;
|
||||
kbuf->next = 0;
|
||||
|
||||
next_event(kbuf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* kbuffer_subbuf_timestamp - read the timestamp from a sub buffer
|
||||
* @kbuf: The kbuffer to load
|
||||
* @subbuf: The subbuffer to read from.
|
||||
*
|
||||
* Return the timestamp from a subbuffer.
|
||||
*/
|
||||
unsigned long long kbuffer_subbuf_timestamp(struct kbuffer *kbuf, void *subbuf)
|
||||
{
|
||||
return kbuf->read_8(subbuf);
|
||||
}
|
||||
|
||||
/**
|
||||
* kbuffer_ptr_delta - read the delta field from a record
|
||||
* @kbuf: The kbuffer to load
|
||||
* @ptr: The record in the buffe.
|
||||
*
|
||||
* Return the timestamp delta from a record
|
||||
*/
|
||||
unsigned int kbuffer_ptr_delta(struct kbuffer *kbuf, void *ptr)
|
||||
{
|
||||
unsigned int type_len_ts;
|
||||
|
||||
type_len_ts = read_4(kbuf, ptr);
|
||||
return ts4host(kbuf, type_len_ts);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* kbuffer_read_event - read the next event in the kbuffer subbuffer
|
||||
* @kbuf: The kbuffer to read from
|
||||
* @ts: The address to store the timestamp of the event (may be NULL to ignore)
|
||||
*
|
||||
* Returns a pointer to the data part of the current event.
|
||||
* NULL if no event is left on the subbuffer.
|
||||
*/
|
||||
void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts)
|
||||
{
|
||||
if (!kbuf || !kbuf->subbuffer)
|
||||
return NULL;
|
||||
|
||||
if (kbuf->curr >= kbuf->size)
|
||||
return NULL;
|
||||
|
||||
if (ts)
|
||||
*ts = kbuf->timestamp;
|
||||
return kbuf->data + kbuf->index;
|
||||
}
|
||||
|
||||
/**
|
||||
* kbuffer_timestamp - Return the timestamp of the current event
|
||||
* @kbuf: The kbuffer to read from
|
||||
*
|
||||
* Returns the timestamp of the current (next) event.
|
||||
*/
|
||||
unsigned long long kbuffer_timestamp(struct kbuffer *kbuf)
|
||||
{
|
||||
return kbuf->timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* kbuffer_read_at_offset - read the event that is at offset
|
||||
* @kbuf: The kbuffer to read from
|
||||
* @offset: The offset into the subbuffer
|
||||
* @ts: The address to store the timestamp of the event (may be NULL to ignore)
|
||||
*
|
||||
* The @offset must be an index from the @kbuf subbuffer beginning.
|
||||
* If @offset is bigger than the stored subbuffer, NULL will be returned.
|
||||
*
|
||||
* Returns the data of the record that is at @offset. Note, @offset does
|
||||
* not need to be the start of the record, the offset just needs to be
|
||||
* in the record (or beginning of it).
|
||||
*
|
||||
* Note, the kbuf timestamp and pointers are updated to the
|
||||
* returned record. That is, kbuffer_read_event() will return the same
|
||||
* data and timestamp, and kbuffer_next_event() will increment from
|
||||
* this record.
|
||||
*/
|
||||
void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset,
|
||||
unsigned long long *ts)
|
||||
{
|
||||
void *data;
|
||||
|
||||
if (offset < kbuf->start)
|
||||
offset = 0;
|
||||
else
|
||||
offset -= kbuf->start;
|
||||
|
||||
/* Reset the buffer */
|
||||
kbuffer_load_subbuffer(kbuf, kbuf->subbuffer);
|
||||
data = kbuffer_read_event(kbuf, ts);
|
||||
|
||||
while (kbuf->curr < offset) {
|
||||
data = kbuffer_next_event(kbuf, ts);
|
||||
if (!data)
|
||||
break;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* kbuffer_subbuffer_size - the size of the loaded subbuffer
|
||||
* @kbuf: The kbuffer to read from
|
||||
*
|
||||
* Returns the size of the subbuffer. Note, this size is
|
||||
* where the last event resides. The stored subbuffer may actually be
|
||||
* bigger due to padding and such.
|
||||
*/
|
||||
int kbuffer_subbuffer_size(struct kbuffer *kbuf)
|
||||
{
|
||||
return kbuf->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* kbuffer_curr_index - Return the index of the record
|
||||
* @kbuf: The kbuffer to read from
|
||||
*
|
||||
* Returns the index from the start of the data part of
|
||||
* the subbuffer to the current location. Note this is not
|
||||
* from the start of the subbuffer. An index of zero will
|
||||
* point to the first record. Use kbuffer_curr_offset() for
|
||||
* the actually offset (that can be used by kbuffer_read_at_offset())
|
||||
*/
|
||||
int kbuffer_curr_index(struct kbuffer *kbuf)
|
||||
{
|
||||
return kbuf->curr;
|
||||
}
|
||||
|
||||
/**
|
||||
* kbuffer_curr_offset - Return the offset of the record
|
||||
* @kbuf: The kbuffer to read from
|
||||
*
|
||||
* Returns the offset from the start of the subbuffer to the
|
||||
* current location.
|
||||
*/
|
||||
int kbuffer_curr_offset(struct kbuffer *kbuf)
|
||||
{
|
||||
return kbuf->curr + kbuf->start;
|
||||
}
|
||||
|
||||
/**
|
||||
* kbuffer_event_size - return the size of the event data
|
||||
* @kbuf: The kbuffer to read
|
||||
*
|
||||
* Returns the size of the event data (the payload not counting
|
||||
* the meta data of the record) of the current event.
|
||||
*/
|
||||
int kbuffer_event_size(struct kbuffer *kbuf)
|
||||
{
|
||||
return kbuf->next - kbuf->index;
|
||||
}
|
||||
|
||||
/**
|
||||
* kbuffer_curr_size - return the size of the entire record
|
||||
* @kbuf: The kbuffer to read
|
||||
*
|
||||
* Returns the size of the entire record (meta data and payload)
|
||||
* of the current event.
|
||||
*/
|
||||
int kbuffer_curr_size(struct kbuffer *kbuf)
|
||||
{
|
||||
return kbuf->next - kbuf->curr;
|
||||
}
|
||||
|
||||
/**
|
||||
* kbuffer_missed_events - return the # of missed events from last event.
|
||||
* @kbuf: The kbuffer to read from
|
||||
*
|
||||
* Returns the # of missed events (if recorded) before the current
|
||||
* event. Note, only events on the beginning of a subbuffer can
|
||||
* have missed events, all other events within the buffer will be
|
||||
* zero.
|
||||
*/
|
||||
int kbuffer_missed_events(struct kbuffer *kbuf)
|
||||
{
|
||||
/* Only the first event can have missed events */
|
||||
if (kbuf->curr)
|
||||
return 0;
|
||||
|
||||
return kbuf->lost_events;
|
||||
}
|
||||
|
||||
/**
|
||||
* kbuffer_set_old_forma - set the kbuffer to use the old format parsing
|
||||
* @kbuf: The kbuffer to set
|
||||
*
|
||||
* This is obsolete (or should be). The first kernels to use the
|
||||
* new ring buffer had a slightly different ring buffer format
|
||||
* (2.6.30 and earlier). It is still somewhat supported by kbuffer,
|
||||
* but should not be counted on in the future.
|
||||
*/
|
||||
void kbuffer_set_old_format(struct kbuffer *kbuf)
|
||||
{
|
||||
kbuf->flags |= KBUFFER_FL_OLD_FORMAT;
|
||||
|
||||
kbuf->next_event = __old_next_event;
|
||||
}
|
||||
|
||||
/**
|
||||
* kbuffer_start_of_data - return offset of where data starts on subbuffer
|
||||
* @kbuf: The kbuffer
|
||||
*
|
||||
* Returns the location on the subbuffer where the data starts.
|
||||
*/
|
||||
int kbuffer_start_of_data(struct kbuffer *kbuf)
|
||||
{
|
||||
return kbuf->start;
|
||||
}
|
||||
|
||||
/**
|
||||
* kbuffer_raw_get - get raw buffer info
|
||||
* @kbuf: The kbuffer
|
||||
* @subbuf: Start of mapped subbuffer
|
||||
* @info: Info descriptor to fill in
|
||||
*
|
||||
* For debugging. This can return internals of the ring buffer.
|
||||
* Expects to have info->next set to what it will read.
|
||||
* The type, length and timestamp delta will be filled in, and
|
||||
* @info->next will be updated to the next element.
|
||||
* The @subbuf is used to know if the info is passed the end of
|
||||
* data and NULL will be returned if it is.
|
||||
*/
|
||||
struct kbuffer_raw_info *
|
||||
kbuffer_raw_get(struct kbuffer *kbuf, void *subbuf, struct kbuffer_raw_info *info)
|
||||
{
|
||||
unsigned long long flags;
|
||||
unsigned long long delta;
|
||||
unsigned int type_len;
|
||||
unsigned int size;
|
||||
int start;
|
||||
int length;
|
||||
void *ptr = info->next;
|
||||
|
||||
if (!kbuf || !subbuf)
|
||||
return NULL;
|
||||
|
||||
if (kbuf->flags & KBUFFER_FL_LONG_8)
|
||||
start = 16;
|
||||
else
|
||||
start = 12;
|
||||
|
||||
flags = read_long(kbuf, subbuf + 8);
|
||||
size = (unsigned int)flags & COMMIT_MASK;
|
||||
|
||||
if (ptr < subbuf || ptr >= subbuf + start + size)
|
||||
return NULL;
|
||||
|
||||
type_len = translate_data(kbuf, ptr, &ptr, &delta, &length);
|
||||
|
||||
info->next = ptr + length;
|
||||
|
||||
info->type = type_len;
|
||||
info->delta = delta;
|
||||
info->length = length;
|
||||
|
||||
return info;
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1 */
|
||||
/*
|
||||
* Copyright (C) 2012 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*
|
||||
*/
|
||||
#ifndef _KBUFFER_H
|
||||
#define _KBUFFER_H
|
||||
|
||||
#ifndef TS_SHIFT
|
||||
#define TS_SHIFT 27
|
||||
#endif
|
||||
|
||||
enum kbuffer_endian {
|
||||
KBUFFER_ENDIAN_BIG,
|
||||
KBUFFER_ENDIAN_LITTLE,
|
||||
};
|
||||
|
||||
enum kbuffer_long_size {
|
||||
KBUFFER_LSIZE_4,
|
||||
KBUFFER_LSIZE_8,
|
||||
};
|
||||
|
||||
enum {
|
||||
KBUFFER_TYPE_PADDING = 29,
|
||||
KBUFFER_TYPE_TIME_EXTEND = 30,
|
||||
KBUFFER_TYPE_TIME_STAMP = 31,
|
||||
};
|
||||
|
||||
struct kbuffer;
|
||||
|
||||
struct kbuffer *kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian);
|
||||
void kbuffer_free(struct kbuffer *kbuf);
|
||||
int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer);
|
||||
void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts);
|
||||
void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts);
|
||||
unsigned long long kbuffer_timestamp(struct kbuffer *kbuf);
|
||||
unsigned long long kbuffer_subbuf_timestamp(struct kbuffer *kbuf, void *subbuf);
|
||||
unsigned int kbuffer_ptr_delta(struct kbuffer *kbuf, void *ptr);
|
||||
|
||||
void *kbuffer_translate_data(int swap, void *data, unsigned int *size);
|
||||
|
||||
void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset, unsigned long long *ts);
|
||||
|
||||
int kbuffer_curr_index(struct kbuffer *kbuf);
|
||||
|
||||
int kbuffer_curr_offset(struct kbuffer *kbuf);
|
||||
int kbuffer_curr_size(struct kbuffer *kbuf);
|
||||
int kbuffer_event_size(struct kbuffer *kbuf);
|
||||
int kbuffer_missed_events(struct kbuffer *kbuf);
|
||||
int kbuffer_subbuffer_size(struct kbuffer *kbuf);
|
||||
|
||||
void kbuffer_set_old_format(struct kbuffer *kbuf);
|
||||
int kbuffer_start_of_data(struct kbuffer *kbuf);
|
||||
|
||||
/* Debugging */
|
||||
|
||||
struct kbuffer_raw_info {
|
||||
int type;
|
||||
int length;
|
||||
unsigned long long delta;
|
||||
void *next;
|
||||
};
|
||||
|
||||
/* Read raw data */
|
||||
struct kbuffer_raw_info *kbuffer_raw_get(struct kbuffer *kbuf, void *subbuf,
|
||||
struct kbuffer_raw_info *info);
|
||||
|
||||
#endif /* _K_BUFFER_H */
|
@ -1,10 +0,0 @@
|
||||
prefix=INSTALL_PREFIX
|
||||
libdir=LIB_DIR
|
||||
includedir=HEADER_DIR
|
||||
|
||||
Name: libtraceevent
|
||||
URL: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
||||
Description: Linux kernel trace event library
|
||||
Version: LIB_VERSION
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -ltraceevent
|
File diff suppressed because it is too large
Load Diff
@ -1,71 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define __weak __attribute__((weak))
|
||||
|
||||
void __vwarning(const char *fmt, va_list ap)
|
||||
{
|
||||
if (errno)
|
||||
perror("libtraceevent");
|
||||
errno = 0;
|
||||
|
||||
fprintf(stderr, " ");
|
||||
vfprintf(stderr, fmt, ap);
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void __warning(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
__vwarning(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void __weak warning(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
__vwarning(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void __vpr_stat(const char *fmt, va_list ap)
|
||||
{
|
||||
vprintf(fmt, ap);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void __pr_stat(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
__vpr_stat(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void __weak vpr_stat(const char *fmt, va_list ap)
|
||||
{
|
||||
__vpr_stat(fmt, ap);
|
||||
}
|
||||
|
||||
void __weak pr_stat(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
__vpr_stat(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
plugin_jbd2-y += plugin_jbd2.o
|
||||
plugin_hrtimer-y += plugin_hrtimer.o
|
||||
plugin_kmem-y += plugin_kmem.o
|
||||
plugin_kvm-y += plugin_kvm.o
|
||||
plugin_mac80211-y += plugin_mac80211.o
|
||||
plugin_sched_switch-y += plugin_sched_switch.o
|
||||
plugin_function-y += plugin_function.o
|
||||
plugin_futex-y += plugin_futex.o
|
||||
plugin_xen-y += plugin_xen.o
|
||||
plugin_scsi-y += plugin_scsi.o
|
||||
plugin_cfg80211-y += plugin_cfg80211.o
|
||||
plugin_tlb-y += plugin_tlb.o
|
@ -1,225 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#MAKEFLAGS += --no-print-directory
|
||||
|
||||
|
||||
# Makefiles suck: This macro sets a default value of $(2) for the
|
||||
# variable named by $(1), unless the variable has been set by
|
||||
# environment or command line. This is necessary for CC and AR
|
||||
# because make sets default values, so the simpler ?= approach
|
||||
# won't work as expected.
|
||||
define allow-override
|
||||
$(if $(or $(findstring environment,$(origin $(1))),\
|
||||
$(findstring command line,$(origin $(1)))),,\
|
||||
$(eval $(1) = $(2)))
|
||||
endef
|
||||
|
||||
# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix.
|
||||
$(call allow-override,CC,$(CROSS_COMPILE)gcc)
|
||||
$(call allow-override,AR,$(CROSS_COMPILE)ar)
|
||||
$(call allow-override,NM,$(CROSS_COMPILE)nm)
|
||||
$(call allow-override,PKG_CONFIG,pkg-config)
|
||||
|
||||
EXT = -std=gnu99
|
||||
INSTALL = install
|
||||
|
||||
# Use DESTDIR for installing into a different root directory.
|
||||
# This is useful for building a package. The program will be
|
||||
# installed in this directory as if it was the root directory.
|
||||
# Then the build tool can move it later.
|
||||
DESTDIR ?=
|
||||
DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))'
|
||||
|
||||
LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1)
|
||||
ifeq ($(LP64), 1)
|
||||
libdir_relative_tmp = lib64
|
||||
else
|
||||
libdir_relative_tmp = lib
|
||||
endif
|
||||
|
||||
libdir_relative ?= $(libdir_relative_tmp)
|
||||
prefix ?= /usr/local
|
||||
libdir = $(prefix)/$(libdir_relative)
|
||||
|
||||
set_plugin_dir := 1
|
||||
|
||||
# Set plugin_dir to preffered global plugin location
|
||||
# If we install under $HOME directory we go under
|
||||
# $(HOME)/.local/lib/traceevent/plugins
|
||||
#
|
||||
# We dont set PLUGIN_DIR in case we install under $HOME
|
||||
# directory, because by default the code looks under:
|
||||
# $(HOME)/.local/lib/traceevent/plugins by default.
|
||||
#
|
||||
ifeq ($(plugin_dir),)
|
||||
ifeq ($(prefix),$(HOME))
|
||||
override plugin_dir = $(HOME)/.local/lib/traceevent/plugins
|
||||
set_plugin_dir := 0
|
||||
else
|
||||
override plugin_dir = $(libdir)/traceevent/plugins
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(set_plugin_dir),1)
|
||||
PLUGIN_DIR = -DPLUGIN_DIR="$(plugin_dir)"
|
||||
PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))'
|
||||
endif
|
||||
|
||||
include ../../../scripts/Makefile.include
|
||||
|
||||
# copy a bit from Linux kbuild
|
||||
|
||||
ifeq ("$(origin V)", "command line")
|
||||
VERBOSE = $(V)
|
||||
endif
|
||||
ifndef VERBOSE
|
||||
VERBOSE = 0
|
||||
endif
|
||||
|
||||
ifeq ($(srctree),)
|
||||
srctree := $(patsubst %/,%,$(dir $(CURDIR)))
|
||||
srctree := $(patsubst %/,%,$(dir $(srctree)))
|
||||
srctree := $(patsubst %/,%,$(dir $(srctree)))
|
||||
srctree := $(patsubst %/,%,$(dir $(srctree)))
|
||||
#$(info Determined 'srctree' to be $(srctree))
|
||||
endif
|
||||
|
||||
export prefix libdir src obj
|
||||
|
||||
# Shell quotes
|
||||
plugin_dir_SQ = $(subst ','\'',$(plugin_dir))
|
||||
|
||||
CONFIG_INCLUDES =
|
||||
CONFIG_LIBS =
|
||||
CONFIG_FLAGS =
|
||||
|
||||
OBJ = $@
|
||||
N =
|
||||
|
||||
INCLUDES = -I. -I.. -I $(srctree)/tools/include $(CONFIG_INCLUDES)
|
||||
|
||||
# Set compile option CFLAGS
|
||||
ifdef EXTRA_CFLAGS
|
||||
CFLAGS := $(EXTRA_CFLAGS)
|
||||
else
|
||||
CFLAGS := -g -Wall
|
||||
endif
|
||||
|
||||
# Append required CFLAGS
|
||||
override CFLAGS += -fPIC
|
||||
override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ)
|
||||
override CFLAGS += $(udis86-flags) -D_GNU_SOURCE
|
||||
|
||||
ifeq ($(VERBOSE),1)
|
||||
Q =
|
||||
else
|
||||
Q = @
|
||||
endif
|
||||
|
||||
# Disable command line variables (CFLAGS) override from top
|
||||
# level Makefile (perf), otherwise build Makefile will get
|
||||
# the same command line setup.
|
||||
MAKEOVERRIDES=
|
||||
|
||||
export srctree OUTPUT CC LD CFLAGS V
|
||||
|
||||
build := -f $(srctree)/tools/build/Makefile.build dir=. obj
|
||||
|
||||
DYNAMIC_LIST_FILE := $(OUTPUT)libtraceevent-dynamic-list
|
||||
|
||||
PLUGINS = plugin_jbd2.so
|
||||
PLUGINS += plugin_hrtimer.so
|
||||
PLUGINS += plugin_kmem.so
|
||||
PLUGINS += plugin_kvm.so
|
||||
PLUGINS += plugin_mac80211.so
|
||||
PLUGINS += plugin_sched_switch.so
|
||||
PLUGINS += plugin_function.so
|
||||
PLUGINS += plugin_futex.so
|
||||
PLUGINS += plugin_xen.so
|
||||
PLUGINS += plugin_scsi.so
|
||||
PLUGINS += plugin_cfg80211.so
|
||||
PLUGINS += plugin_tlb.so
|
||||
|
||||
PLUGINS := $(addprefix $(OUTPUT),$(PLUGINS))
|
||||
PLUGINS_IN := $(PLUGINS:.so=-in.o)
|
||||
|
||||
plugins: $(PLUGINS) $(DYNAMIC_LIST_FILE)
|
||||
|
||||
__plugin_obj = $(notdir $@)
|
||||
plugin_obj = $(__plugin_obj:-in.o=)
|
||||
|
||||
$(PLUGINS_IN): force
|
||||
$(Q)$(MAKE) $(build)=$(plugin_obj)
|
||||
|
||||
$(OUTPUT)libtraceevent-dynamic-list: $(PLUGINS)
|
||||
$(QUIET_GEN)$(call do_generate_dynamic_list_file, $(PLUGINS), $@)
|
||||
|
||||
$(OUTPUT)%.so: $(OUTPUT)%-in.o
|
||||
$(QUIET_LINK)$(CC) $(CFLAGS) -shared $(LDFLAGS) -nostartfiles -o $@ $^
|
||||
|
||||
define update_dir
|
||||
(echo $1 > $@.tmp; \
|
||||
if [ -r $@ ] && cmp -s $@ $@.tmp; then \
|
||||
rm -f $@.tmp; \
|
||||
else \
|
||||
echo ' UPDATE $@'; \
|
||||
mv -f $@.tmp $@; \
|
||||
fi);
|
||||
endef
|
||||
|
||||
tags: force
|
||||
$(RM) tags
|
||||
find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \
|
||||
--regex-c++='/_PE\(([^,)]*).*/TEP_ERRNO__\1/'
|
||||
|
||||
TAGS: force
|
||||
$(RM) TAGS
|
||||
find . -name '*.[ch]' | xargs etags \
|
||||
--regex='/_PE(\([^,)]*\).*/TEP_ERRNO__\1/'
|
||||
|
||||
define do_install_mkdir
|
||||
if [ ! -d '$(DESTDIR_SQ)$1' ]; then \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$1'; \
|
||||
fi
|
||||
endef
|
||||
|
||||
define do_install
|
||||
$(call do_install_mkdir,$2); \
|
||||
$(INSTALL) $(if $3,-m $3,) $1 '$(DESTDIR_SQ)$2'
|
||||
endef
|
||||
|
||||
define do_install_plugins
|
||||
for plugin in $1; do \
|
||||
$(call do_install,$$plugin,$(plugin_dir_SQ)); \
|
||||
done
|
||||
endef
|
||||
|
||||
define do_generate_dynamic_list_file
|
||||
symbol_type=`$(NM) -u -D $1 | awk 'NF>1 {print $$1}' | \
|
||||
xargs echo "U w W" | tr 'w ' 'W\n' | sort -u | xargs echo`;\
|
||||
if [ "$$symbol_type" = "U W" ];then \
|
||||
(echo '{'; \
|
||||
$(NM) -u -D $1 | awk 'NF>1 {sub("@.*", "", $$2); print "\t"$$2";"}' | sort -u;\
|
||||
echo '};'; \
|
||||
) > $2; \
|
||||
else \
|
||||
(echo Either missing one of [$1] or bad version of $(NM)) 1>&2;\
|
||||
fi
|
||||
endef
|
||||
|
||||
install: $(PLUGINS)
|
||||
$(call QUIET_INSTALL, trace_plugins) \
|
||||
$(call do_install_plugins, $(PLUGINS))
|
||||
|
||||
clean:
|
||||
$(call QUIET_CLEAN, trace_plugins) \
|
||||
$(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d .*.cmd; \
|
||||
$(RM) $(OUTPUT)libtraceevent-dynamic-list \
|
||||
$(RM) TRACEEVENT-CFLAGS tags TAGS;
|
||||
|
||||
PHONY += force plugins
|
||||
force:
|
||||
|
||||
# Declare the contents of the .PHONY variable as phony. We keep that
|
||||
# information in a variable so we can use it in if_changed and friends.
|
||||
.PHONY: $(PHONY)
|
@ -1,43 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <endian.h>
|
||||
#include "event-parse.h"
|
||||
|
||||
/*
|
||||
* From glibc endian.h, for older systems where it is not present, e.g.: RHEL5,
|
||||
* Fedora6.
|
||||
*/
|
||||
#ifndef le16toh
|
||||
# if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
# define le16toh(x) (x)
|
||||
# else
|
||||
# define le16toh(x) __bswap_16 (x)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
static unsigned long long
|
||||
process___le16_to_cpup(struct trace_seq *s, unsigned long long *args)
|
||||
{
|
||||
uint16_t *val = (uint16_t *) (unsigned long) args[0];
|
||||
return val ? (long long) le16toh(*val) : 0;
|
||||
}
|
||||
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_register_print_function(tep,
|
||||
process___le16_to_cpup,
|
||||
TEP_FUNC_ARG_INT,
|
||||
"__le16_to_cpup",
|
||||
TEP_FUNC_ARG_PTR,
|
||||
TEP_FUNC_ARG_VOID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_unregister_print_function(tep, process___le16_to_cpup,
|
||||
"__le16_to_cpup");
|
||||
}
|
@ -1,282 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "event-parse.h"
|
||||
#include "event-utils.h"
|
||||
#include "trace-seq.h"
|
||||
|
||||
static struct func_stack {
|
||||
int size;
|
||||
char **stack;
|
||||
} *fstack;
|
||||
|
||||
static int cpus = -1;
|
||||
|
||||
#define STK_BLK 10
|
||||
|
||||
struct tep_plugin_option plugin_options[] =
|
||||
{
|
||||
{
|
||||
.name = "parent",
|
||||
.plugin_alias = "ftrace",
|
||||
.description =
|
||||
"Print parent of functions for function events",
|
||||
},
|
||||
{
|
||||
.name = "indent",
|
||||
.plugin_alias = "ftrace",
|
||||
.description =
|
||||
"Try to show function call indents, based on parents",
|
||||
.set = 1,
|
||||
},
|
||||
{
|
||||
.name = "offset",
|
||||
.plugin_alias = "ftrace",
|
||||
.description =
|
||||
"Show function names as well as their offsets",
|
||||
.set = 0,
|
||||
},
|
||||
{
|
||||
.name = NULL,
|
||||
}
|
||||
};
|
||||
|
||||
static struct tep_plugin_option *ftrace_parent = &plugin_options[0];
|
||||
static struct tep_plugin_option *ftrace_indent = &plugin_options[1];
|
||||
static struct tep_plugin_option *ftrace_offset = &plugin_options[2];
|
||||
|
||||
static void add_child(struct func_stack *stack, const char *child, int pos)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!child)
|
||||
return;
|
||||
|
||||
if (pos < stack->size)
|
||||
free(stack->stack[pos]);
|
||||
else {
|
||||
char **ptr;
|
||||
|
||||
ptr = realloc(stack->stack, sizeof(char *) *
|
||||
(stack->size + STK_BLK));
|
||||
if (!ptr) {
|
||||
warning("could not allocate plugin memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
stack->stack = ptr;
|
||||
|
||||
for (i = stack->size; i < stack->size + STK_BLK; i++)
|
||||
stack->stack[i] = NULL;
|
||||
stack->size += STK_BLK;
|
||||
}
|
||||
|
||||
stack->stack[pos] = strdup(child);
|
||||
}
|
||||
|
||||
static int add_and_get_index(const char *parent, const char *child, int cpu)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (cpu < 0)
|
||||
return 0;
|
||||
|
||||
if (cpu > cpus) {
|
||||
struct func_stack *ptr;
|
||||
|
||||
ptr = realloc(fstack, sizeof(*fstack) * (cpu + 1));
|
||||
if (!ptr) {
|
||||
warning("could not allocate plugin memory\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
fstack = ptr;
|
||||
|
||||
/* Account for holes in the cpu count */
|
||||
for (i = cpus + 1; i <= cpu; i++)
|
||||
memset(&fstack[i], 0, sizeof(fstack[i]));
|
||||
cpus = cpu;
|
||||
}
|
||||
|
||||
for (i = 0; i < fstack[cpu].size && fstack[cpu].stack[i]; i++) {
|
||||
if (strcmp(parent, fstack[cpu].stack[i]) == 0) {
|
||||
add_child(&fstack[cpu], child, i+1);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
add_child(&fstack[cpu], parent, 0);
|
||||
add_child(&fstack[cpu], child, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void show_function(struct trace_seq *s, struct tep_handle *tep,
|
||||
const char *func, unsigned long long function)
|
||||
{
|
||||
unsigned long long offset;
|
||||
|
||||
trace_seq_printf(s, "%s", func);
|
||||
if (ftrace_offset->set) {
|
||||
offset = tep_find_function_address(tep, function);
|
||||
trace_seq_printf(s, "+0x%x ", (int)(function - offset));
|
||||
}
|
||||
}
|
||||
|
||||
static int function_handler(struct trace_seq *s, struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
struct tep_handle *tep = event->tep;
|
||||
unsigned long long function;
|
||||
unsigned long long pfunction;
|
||||
const char *func;
|
||||
const char *parent;
|
||||
int index = 0;
|
||||
|
||||
if (tep_get_field_val(s, event, "ip", record, &function, 1))
|
||||
return trace_seq_putc(s, '!');
|
||||
|
||||
func = tep_find_function(tep, function);
|
||||
|
||||
if (tep_get_field_val(s, event, "parent_ip", record, &pfunction, 1))
|
||||
return trace_seq_putc(s, '!');
|
||||
|
||||
parent = tep_find_function(tep, pfunction);
|
||||
|
||||
if (parent && ftrace_indent->set)
|
||||
index = add_and_get_index(parent, func, record->cpu);
|
||||
|
||||
trace_seq_printf(s, "%*s", index*3, "");
|
||||
|
||||
if (func)
|
||||
show_function(s, tep, func, function);
|
||||
else
|
||||
trace_seq_printf(s, "0x%llx", function);
|
||||
|
||||
if (ftrace_parent->set) {
|
||||
trace_seq_printf(s, " <-- ");
|
||||
if (parent)
|
||||
show_function(s, tep, parent, pfunction);
|
||||
else
|
||||
trace_seq_printf(s, "0x%llx", pfunction);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
trace_stack_handler(struct trace_seq *s, struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
struct tep_format_field *field;
|
||||
unsigned long long addr;
|
||||
const char *func;
|
||||
int long_size;
|
||||
void *data = record->data;
|
||||
|
||||
field = tep_find_any_field(event, "caller");
|
||||
if (!field) {
|
||||
trace_seq_printf(s, "<CANT FIND FIELD %s>", "caller");
|
||||
return 0;
|
||||
}
|
||||
|
||||
trace_seq_puts(s, "<stack trace >\n");
|
||||
|
||||
long_size = tep_get_long_size(event->tep);
|
||||
|
||||
for (data += field->offset; data < record->data + record->size;
|
||||
data += long_size) {
|
||||
addr = tep_read_number(event->tep, data, long_size);
|
||||
|
||||
if ((long_size == 8 && addr == (unsigned long long)-1) ||
|
||||
((int)addr == -1))
|
||||
break;
|
||||
|
||||
func = tep_find_function(event->tep, addr);
|
||||
if (func)
|
||||
trace_seq_printf(s, "=> %s (%llx)\n", func, addr);
|
||||
else
|
||||
trace_seq_printf(s, "=> %llx\n", addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
trace_raw_data_handler(struct trace_seq *s, struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
struct tep_format_field *field;
|
||||
unsigned long long id;
|
||||
int long_size;
|
||||
void *data = record->data;
|
||||
|
||||
if (tep_get_field_val(s, event, "id", record, &id, 1))
|
||||
return trace_seq_putc(s, '!');
|
||||
|
||||
trace_seq_printf(s, "# %llx", id);
|
||||
|
||||
field = tep_find_any_field(event, "buf");
|
||||
if (!field) {
|
||||
trace_seq_printf(s, "<CANT FIND FIELD %s>", "buf");
|
||||
return 0;
|
||||
}
|
||||
|
||||
long_size = tep_get_long_size(event->tep);
|
||||
|
||||
for (data += field->offset; data < record->data + record->size;
|
||||
data += long_size) {
|
||||
int size = sizeof(long);
|
||||
int left = (record->data + record->size) - data;
|
||||
int i;
|
||||
|
||||
if (size > left)
|
||||
size = left;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
trace_seq_printf(s, " %02x", *(unsigned char *)(data + i));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_register_event_handler(tep, -1, "ftrace", "function",
|
||||
function_handler, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1, "ftrace", "kernel_stack",
|
||||
trace_stack_handler, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1, "ftrace", "raw_data",
|
||||
trace_raw_data_handler, NULL);
|
||||
|
||||
tep_plugin_add_options("ftrace", plugin_options);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
|
||||
{
|
||||
int i, x;
|
||||
|
||||
tep_unregister_event_handler(tep, -1, "ftrace", "function",
|
||||
function_handler, NULL);
|
||||
|
||||
for (i = 0; i <= cpus; i++) {
|
||||
for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++)
|
||||
free(fstack[i].stack[x]);
|
||||
free(fstack[i].stack);
|
||||
}
|
||||
|
||||
tep_plugin_remove_options(plugin_options);
|
||||
|
||||
free(fstack);
|
||||
fstack = NULL;
|
||||
cpus = -1;
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2017 National Instruments Corp.
|
||||
*
|
||||
* Author: Julia Cartwright <julia@ni.com>
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <linux/futex.h>
|
||||
|
||||
#include "event-parse.h"
|
||||
|
||||
#define ARRAY_SIZE(_a) (sizeof(_a) / sizeof((_a)[0]))
|
||||
|
||||
struct futex_args {
|
||||
unsigned long long uaddr;
|
||||
unsigned long long op;
|
||||
unsigned long long val;
|
||||
unsigned long long utime; /* or val2 */
|
||||
unsigned long long uaddr2;
|
||||
unsigned long long val3;
|
||||
};
|
||||
|
||||
struct futex_op {
|
||||
const char *name;
|
||||
const char *fmt_val;
|
||||
const char *fmt_utime;
|
||||
const char *fmt_uaddr2;
|
||||
const char *fmt_val3;
|
||||
};
|
||||
|
||||
static const struct futex_op futex_op_tbl[] = {
|
||||
{ "FUTEX_WAIT", " val=0x%08llx", " utime=0x%08llx", NULL, NULL },
|
||||
{ "FUTEX_WAKE", " val=%llu", NULL, NULL, NULL },
|
||||
{ "FUTEX_FD", " val=%llu", NULL, NULL, NULL },
|
||||
{ "FUTEX_REQUEUE", " val=%llu", " val2=%llu", " uaddr2=0x%08llx", NULL },
|
||||
{ "FUTEX_CMP_REQUEUE", " val=%llu", " val2=%llu", " uaddr2=0x%08llx", " val3=0x%08llx" },
|
||||
{ "FUTEX_WAKE_OP", " val=%llu", " val2=%llu", " uaddr2=0x%08llx", " val3=0x%08llx" },
|
||||
{ "FUTEX_LOCK_PI", NULL, " utime=0x%08llx", NULL, NULL },
|
||||
{ "FUTEX_UNLOCK_PI", NULL, NULL, NULL, NULL },
|
||||
{ "FUTEX_TRYLOCK_PI", NULL, NULL, NULL, NULL },
|
||||
{ "FUTEX_WAIT_BITSET", " val=0x%08llx", " utime=0x%08llx", NULL, " val3=0x%08llx" },
|
||||
{ "FUTEX_WAKE_BITSET", " val=%llu", NULL, NULL, " val3=0x%08llx" },
|
||||
{ "FUTEX_WAIT_REQUEUE_PI", " val=0x%08llx", " utime=0x%08llx", " uaddr2=0x%08llx", " val3=0x%08llx" },
|
||||
{ "FUTEX_CMP_REQUEUE_PI", " val=%llu", " val2=%llu", " uaddr2=0x%08llx", " val3=0x%08llx" },
|
||||
};
|
||||
|
||||
|
||||
static void futex_print(struct trace_seq *s, const struct futex_args *args,
|
||||
const struct futex_op *fop)
|
||||
{
|
||||
trace_seq_printf(s, " uaddr=0x%08llx", args->uaddr);
|
||||
|
||||
if (fop->fmt_val)
|
||||
trace_seq_printf(s, fop->fmt_val, args->val);
|
||||
|
||||
if (fop->fmt_utime)
|
||||
trace_seq_printf(s,fop->fmt_utime, args->utime);
|
||||
|
||||
if (fop->fmt_uaddr2)
|
||||
trace_seq_printf(s, fop->fmt_uaddr2, args->uaddr2);
|
||||
|
||||
if (fop->fmt_val3)
|
||||
trace_seq_printf(s, fop->fmt_val3, args->val3);
|
||||
}
|
||||
|
||||
static int futex_handler(struct trace_seq *s, struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
const struct futex_op *fop;
|
||||
struct futex_args args;
|
||||
unsigned long long cmd;
|
||||
|
||||
if (tep_get_field_val(s, event, "uaddr", record, &args.uaddr, 1))
|
||||
return 1;
|
||||
|
||||
if (tep_get_field_val(s, event, "op", record, &args.op, 1))
|
||||
return 1;
|
||||
|
||||
if (tep_get_field_val(s, event, "val", record, &args.val, 1))
|
||||
return 1;
|
||||
|
||||
if (tep_get_field_val(s, event, "utime", record, &args.utime, 1))
|
||||
return 1;
|
||||
|
||||
if (tep_get_field_val(s, event, "uaddr2", record, &args.uaddr2, 1))
|
||||
return 1;
|
||||
|
||||
if (tep_get_field_val(s, event, "val3", record, &args.val3, 1))
|
||||
return 1;
|
||||
|
||||
cmd = args.op & FUTEX_CMD_MASK;
|
||||
if (cmd >= ARRAY_SIZE(futex_op_tbl))
|
||||
return 1;
|
||||
|
||||
fop = &futex_op_tbl[cmd];
|
||||
|
||||
trace_seq_printf(s, "op=%s", fop->name);
|
||||
|
||||
if (args.op & FUTEX_PRIVATE_FLAG)
|
||||
trace_seq_puts(s, "|FUTEX_PRIVATE_FLAG");
|
||||
|
||||
if (args.op & FUTEX_CLOCK_REALTIME)
|
||||
trace_seq_puts(s, "|FUTEX_CLOCK_REALTIME");
|
||||
|
||||
futex_print(s, &args, fop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_register_event_handler(tep, -1, "syscalls", "sys_enter_futex",
|
||||
futex_handler, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_unregister_event_handler(tep, -1, "syscalls", "sys_enter_futex",
|
||||
futex_handler, NULL);
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
* Copyright (C) 2009 Johannes Berg <johannes@sipsolutions.net>
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "event-parse.h"
|
||||
#include "trace-seq.h"
|
||||
|
||||
static int timer_expire_handler(struct trace_seq *s,
|
||||
struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
trace_seq_printf(s, "hrtimer=");
|
||||
|
||||
if (tep_print_num_field(s, "0x%llx", event, "timer",
|
||||
record, 0) == -1)
|
||||
tep_print_num_field(s, "0x%llx", event, "hrtimer",
|
||||
record, 1);
|
||||
|
||||
trace_seq_printf(s, " now=");
|
||||
|
||||
tep_print_num_field(s, "%llu", event, "now", record, 1);
|
||||
|
||||
tep_print_func_field(s, " function=%s", event, "function",
|
||||
record, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int timer_start_handler(struct trace_seq *s,
|
||||
struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
trace_seq_printf(s, "hrtimer=");
|
||||
|
||||
if (tep_print_num_field(s, "0x%llx", event, "timer",
|
||||
record, 0) == -1)
|
||||
tep_print_num_field(s, "0x%llx", event, "hrtimer",
|
||||
record, 1);
|
||||
|
||||
tep_print_func_field(s, " function=%s", event, "function",
|
||||
record, 0);
|
||||
|
||||
trace_seq_printf(s, " expires=");
|
||||
tep_print_num_field(s, "%llu", event, "expires", record, 1);
|
||||
|
||||
trace_seq_printf(s, " softexpires=");
|
||||
tep_print_num_field(s, "%llu", event, "softexpires", record, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_register_event_handler(tep, -1,
|
||||
"timer", "hrtimer_expire_entry",
|
||||
timer_expire_handler, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1, "timer", "hrtimer_start",
|
||||
timer_start_handler, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_unregister_event_handler(tep, -1,
|
||||
"timer", "hrtimer_expire_entry",
|
||||
timer_expire_handler, NULL);
|
||||
|
||||
tep_unregister_event_handler(tep, -1, "timer", "hrtimer_start",
|
||||
timer_start_handler, NULL);
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "event-parse.h"
|
||||
#include "trace-seq.h"
|
||||
|
||||
#define MINORBITS 20
|
||||
#define MINORMASK ((1U << MINORBITS) - 1)
|
||||
|
||||
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
|
||||
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
|
||||
|
||||
static unsigned long long
|
||||
process_jbd2_dev_to_name(struct trace_seq *s, unsigned long long *args)
|
||||
{
|
||||
unsigned int dev = args[0];
|
||||
|
||||
trace_seq_printf(s, "%d:%d", MAJOR(dev), MINOR(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long long
|
||||
process_jiffies_to_msecs(struct trace_seq *s, unsigned long long *args)
|
||||
{
|
||||
unsigned long long jiffies = args[0];
|
||||
|
||||
trace_seq_printf(s, "%lld", jiffies);
|
||||
return jiffies;
|
||||
}
|
||||
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_register_print_function(tep,
|
||||
process_jbd2_dev_to_name,
|
||||
TEP_FUNC_ARG_STRING,
|
||||
"jbd2_dev_to_name",
|
||||
TEP_FUNC_ARG_INT,
|
||||
TEP_FUNC_ARG_VOID);
|
||||
|
||||
tep_register_print_function(tep,
|
||||
process_jiffies_to_msecs,
|
||||
TEP_FUNC_ARG_LONG,
|
||||
"jiffies_to_msecs",
|
||||
TEP_FUNC_ARG_LONG,
|
||||
TEP_FUNC_ARG_VOID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_unregister_print_function(tep, process_jbd2_dev_to_name,
|
||||
"jbd2_dev_to_name");
|
||||
|
||||
tep_unregister_print_function(tep, process_jiffies_to_msecs,
|
||||
"jiffies_to_msecs");
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "event-parse.h"
|
||||
#include "trace-seq.h"
|
||||
|
||||
static int call_site_handler(struct trace_seq *s, struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
struct tep_format_field *field;
|
||||
unsigned long long val, addr;
|
||||
void *data = record->data;
|
||||
const char *func;
|
||||
|
||||
field = tep_find_field(event, "call_site");
|
||||
if (!field)
|
||||
return 1;
|
||||
|
||||
if (tep_read_number_field(field, data, &val))
|
||||
return 1;
|
||||
|
||||
func = tep_find_function(event->tep, val);
|
||||
if (!func)
|
||||
return 1;
|
||||
|
||||
addr = tep_find_function_address(event->tep, val);
|
||||
|
||||
trace_seq_printf(s, "(%s+0x%x) ", func, (int)(val - addr));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_register_event_handler(tep, -1, "kmem", "kfree",
|
||||
call_site_handler, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1, "kmem", "kmalloc",
|
||||
call_site_handler, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1, "kmem", "kmalloc_node",
|
||||
call_site_handler, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1, "kmem", "kmem_cache_alloc",
|
||||
call_site_handler, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1, "kmem",
|
||||
"kmem_cache_alloc_node",
|
||||
call_site_handler, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1, "kmem", "kmem_cache_free",
|
||||
call_site_handler, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_unregister_event_handler(tep, -1, "kmem", "kfree",
|
||||
call_site_handler, NULL);
|
||||
|
||||
tep_unregister_event_handler(tep, -1, "kmem", "kmalloc",
|
||||
call_site_handler, NULL);
|
||||
|
||||
tep_unregister_event_handler(tep, -1, "kmem", "kmalloc_node",
|
||||
call_site_handler, NULL);
|
||||
|
||||
tep_unregister_event_handler(tep, -1, "kmem", "kmem_cache_alloc",
|
||||
call_site_handler, NULL);
|
||||
|
||||
tep_unregister_event_handler(tep, -1, "kmem",
|
||||
"kmem_cache_alloc_node",
|
||||
call_site_handler, NULL);
|
||||
|
||||
tep_unregister_event_handler(tep, -1, "kmem", "kmem_cache_free",
|
||||
call_site_handler, NULL);
|
||||
}
|
@ -1,527 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "event-parse.h"
|
||||
#include "trace-seq.h"
|
||||
|
||||
#ifdef HAVE_UDIS86
|
||||
|
||||
#include <udis86.h>
|
||||
|
||||
static ud_t ud;
|
||||
|
||||
static void init_disassembler(void)
|
||||
{
|
||||
ud_init(&ud);
|
||||
ud_set_syntax(&ud, UD_SYN_ATT);
|
||||
}
|
||||
|
||||
static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
|
||||
int cr0_pe, int eflags_vm,
|
||||
int cs_d, int cs_l)
|
||||
{
|
||||
int mode;
|
||||
|
||||
if (!cr0_pe)
|
||||
mode = 16;
|
||||
else if (eflags_vm)
|
||||
mode = 16;
|
||||
else if (cs_l)
|
||||
mode = 64;
|
||||
else if (cs_d)
|
||||
mode = 32;
|
||||
else
|
||||
mode = 16;
|
||||
|
||||
ud_set_pc(&ud, rip);
|
||||
ud_set_mode(&ud, mode);
|
||||
ud_set_input_buffer(&ud, insn, len);
|
||||
ud_disassemble(&ud);
|
||||
return ud_insn_asm(&ud);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void init_disassembler(void)
|
||||
{
|
||||
}
|
||||
|
||||
static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
|
||||
int cr0_pe, int eflags_vm,
|
||||
int cs_d, int cs_l)
|
||||
{
|
||||
static char out[15*3+1];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
sprintf(out + i * 3, "%02x ", insn[i]);
|
||||
out[len*3-1] = '\0';
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define VMX_EXIT_REASONS \
|
||||
_ER(EXCEPTION_NMI, 0) \
|
||||
_ER(EXTERNAL_INTERRUPT, 1) \
|
||||
_ER(TRIPLE_FAULT, 2) \
|
||||
_ER(PENDING_INTERRUPT, 7) \
|
||||
_ER(NMI_WINDOW, 8) \
|
||||
_ER(TASK_SWITCH, 9) \
|
||||
_ER(CPUID, 10) \
|
||||
_ER(HLT, 12) \
|
||||
_ER(INVD, 13) \
|
||||
_ER(INVLPG, 14) \
|
||||
_ER(RDPMC, 15) \
|
||||
_ER(RDTSC, 16) \
|
||||
_ER(VMCALL, 18) \
|
||||
_ER(VMCLEAR, 19) \
|
||||
_ER(VMLAUNCH, 20) \
|
||||
_ER(VMPTRLD, 21) \
|
||||
_ER(VMPTRST, 22) \
|
||||
_ER(VMREAD, 23) \
|
||||
_ER(VMRESUME, 24) \
|
||||
_ER(VMWRITE, 25) \
|
||||
_ER(VMOFF, 26) \
|
||||
_ER(VMON, 27) \
|
||||
_ER(CR_ACCESS, 28) \
|
||||
_ER(DR_ACCESS, 29) \
|
||||
_ER(IO_INSTRUCTION, 30) \
|
||||
_ER(MSR_READ, 31) \
|
||||
_ER(MSR_WRITE, 32) \
|
||||
_ER(MWAIT_INSTRUCTION, 36) \
|
||||
_ER(MONITOR_INSTRUCTION, 39) \
|
||||
_ER(PAUSE_INSTRUCTION, 40) \
|
||||
_ER(MCE_DURING_VMENTRY, 41) \
|
||||
_ER(TPR_BELOW_THRESHOLD, 43) \
|
||||
_ER(APIC_ACCESS, 44) \
|
||||
_ER(EOI_INDUCED, 45) \
|
||||
_ER(EPT_VIOLATION, 48) \
|
||||
_ER(EPT_MISCONFIG, 49) \
|
||||
_ER(INVEPT, 50) \
|
||||
_ER(PREEMPTION_TIMER, 52) \
|
||||
_ER(WBINVD, 54) \
|
||||
_ER(XSETBV, 55) \
|
||||
_ER(APIC_WRITE, 56) \
|
||||
_ER(INVPCID, 58) \
|
||||
_ER(PML_FULL, 62) \
|
||||
_ER(XSAVES, 63) \
|
||||
_ER(XRSTORS, 64)
|
||||
|
||||
#define SVM_EXIT_REASONS \
|
||||
_ER(EXIT_READ_CR0, 0x000) \
|
||||
_ER(EXIT_READ_CR3, 0x003) \
|
||||
_ER(EXIT_READ_CR4, 0x004) \
|
||||
_ER(EXIT_READ_CR8, 0x008) \
|
||||
_ER(EXIT_WRITE_CR0, 0x010) \
|
||||
_ER(EXIT_WRITE_CR3, 0x013) \
|
||||
_ER(EXIT_WRITE_CR4, 0x014) \
|
||||
_ER(EXIT_WRITE_CR8, 0x018) \
|
||||
_ER(EXIT_READ_DR0, 0x020) \
|
||||
_ER(EXIT_READ_DR1, 0x021) \
|
||||
_ER(EXIT_READ_DR2, 0x022) \
|
||||
_ER(EXIT_READ_DR3, 0x023) \
|
||||
_ER(EXIT_READ_DR4, 0x024) \
|
||||
_ER(EXIT_READ_DR5, 0x025) \
|
||||
_ER(EXIT_READ_DR6, 0x026) \
|
||||
_ER(EXIT_READ_DR7, 0x027) \
|
||||
_ER(EXIT_WRITE_DR0, 0x030) \
|
||||
_ER(EXIT_WRITE_DR1, 0x031) \
|
||||
_ER(EXIT_WRITE_DR2, 0x032) \
|
||||
_ER(EXIT_WRITE_DR3, 0x033) \
|
||||
_ER(EXIT_WRITE_DR4, 0x034) \
|
||||
_ER(EXIT_WRITE_DR5, 0x035) \
|
||||
_ER(EXIT_WRITE_DR6, 0x036) \
|
||||
_ER(EXIT_WRITE_DR7, 0x037) \
|
||||
_ER(EXIT_EXCP_DE, 0x040) \
|
||||
_ER(EXIT_EXCP_DB, 0x041) \
|
||||
_ER(EXIT_EXCP_BP, 0x043) \
|
||||
_ER(EXIT_EXCP_OF, 0x044) \
|
||||
_ER(EXIT_EXCP_BR, 0x045) \
|
||||
_ER(EXIT_EXCP_UD, 0x046) \
|
||||
_ER(EXIT_EXCP_NM, 0x047) \
|
||||
_ER(EXIT_EXCP_DF, 0x048) \
|
||||
_ER(EXIT_EXCP_TS, 0x04a) \
|
||||
_ER(EXIT_EXCP_NP, 0x04b) \
|
||||
_ER(EXIT_EXCP_SS, 0x04c) \
|
||||
_ER(EXIT_EXCP_GP, 0x04d) \
|
||||
_ER(EXIT_EXCP_PF, 0x04e) \
|
||||
_ER(EXIT_EXCP_MF, 0x050) \
|
||||
_ER(EXIT_EXCP_AC, 0x051) \
|
||||
_ER(EXIT_EXCP_MC, 0x052) \
|
||||
_ER(EXIT_EXCP_XF, 0x053) \
|
||||
_ER(EXIT_INTR, 0x060) \
|
||||
_ER(EXIT_NMI, 0x061) \
|
||||
_ER(EXIT_SMI, 0x062) \
|
||||
_ER(EXIT_INIT, 0x063) \
|
||||
_ER(EXIT_VINTR, 0x064) \
|
||||
_ER(EXIT_CR0_SEL_WRITE, 0x065) \
|
||||
_ER(EXIT_IDTR_READ, 0x066) \
|
||||
_ER(EXIT_GDTR_READ, 0x067) \
|
||||
_ER(EXIT_LDTR_READ, 0x068) \
|
||||
_ER(EXIT_TR_READ, 0x069) \
|
||||
_ER(EXIT_IDTR_WRITE, 0x06a) \
|
||||
_ER(EXIT_GDTR_WRITE, 0x06b) \
|
||||
_ER(EXIT_LDTR_WRITE, 0x06c) \
|
||||
_ER(EXIT_TR_WRITE, 0x06d) \
|
||||
_ER(EXIT_RDTSC, 0x06e) \
|
||||
_ER(EXIT_RDPMC, 0x06f) \
|
||||
_ER(EXIT_PUSHF, 0x070) \
|
||||
_ER(EXIT_POPF, 0x071) \
|
||||
_ER(EXIT_CPUID, 0x072) \
|
||||
_ER(EXIT_RSM, 0x073) \
|
||||
_ER(EXIT_IRET, 0x074) \
|
||||
_ER(EXIT_SWINT, 0x075) \
|
||||
_ER(EXIT_INVD, 0x076) \
|
||||
_ER(EXIT_PAUSE, 0x077) \
|
||||
_ER(EXIT_HLT, 0x078) \
|
||||
_ER(EXIT_INVLPG, 0x079) \
|
||||
_ER(EXIT_INVLPGA, 0x07a) \
|
||||
_ER(EXIT_IOIO, 0x07b) \
|
||||
_ER(EXIT_MSR, 0x07c) \
|
||||
_ER(EXIT_TASK_SWITCH, 0x07d) \
|
||||
_ER(EXIT_FERR_FREEZE, 0x07e) \
|
||||
_ER(EXIT_SHUTDOWN, 0x07f) \
|
||||
_ER(EXIT_VMRUN, 0x080) \
|
||||
_ER(EXIT_VMMCALL, 0x081) \
|
||||
_ER(EXIT_VMLOAD, 0x082) \
|
||||
_ER(EXIT_VMSAVE, 0x083) \
|
||||
_ER(EXIT_STGI, 0x084) \
|
||||
_ER(EXIT_CLGI, 0x085) \
|
||||
_ER(EXIT_SKINIT, 0x086) \
|
||||
_ER(EXIT_RDTSCP, 0x087) \
|
||||
_ER(EXIT_ICEBP, 0x088) \
|
||||
_ER(EXIT_WBINVD, 0x089) \
|
||||
_ER(EXIT_MONITOR, 0x08a) \
|
||||
_ER(EXIT_MWAIT, 0x08b) \
|
||||
_ER(EXIT_MWAIT_COND, 0x08c) \
|
||||
_ER(EXIT_XSETBV, 0x08d) \
|
||||
_ER(EXIT_NPF, 0x400) \
|
||||
_ER(EXIT_AVIC_INCOMPLETE_IPI, 0x401) \
|
||||
_ER(EXIT_AVIC_UNACCELERATED_ACCESS, 0x402) \
|
||||
_ER(EXIT_ERR, -1)
|
||||
|
||||
#define _ER(reason, val) { #reason, val },
|
||||
struct str_values {
|
||||
const char *str;
|
||||
int val;
|
||||
};
|
||||
|
||||
static struct str_values vmx_exit_reasons[] = {
|
||||
VMX_EXIT_REASONS
|
||||
{ NULL, -1}
|
||||
};
|
||||
|
||||
static struct str_values svm_exit_reasons[] = {
|
||||
SVM_EXIT_REASONS
|
||||
{ NULL, -1}
|
||||
};
|
||||
|
||||
static struct isa_exit_reasons {
|
||||
unsigned isa;
|
||||
struct str_values *strings;
|
||||
} isa_exit_reasons[] = {
|
||||
{ .isa = 1, .strings = vmx_exit_reasons },
|
||||
{ .isa = 2, .strings = svm_exit_reasons },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const char *find_exit_reason(unsigned isa, int val)
|
||||
{
|
||||
struct str_values *strings = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0; isa_exit_reasons[i].strings; ++i)
|
||||
if (isa_exit_reasons[i].isa == isa) {
|
||||
strings = isa_exit_reasons[i].strings;
|
||||
break;
|
||||
}
|
||||
if (!strings)
|
||||
return "UNKNOWN-ISA";
|
||||
for (i = 0; strings[i].str; i++)
|
||||
if (strings[i].val == val)
|
||||
break;
|
||||
|
||||
return strings[i].str;
|
||||
}
|
||||
|
||||
static int print_exit_reason(struct trace_seq *s, struct tep_record *record,
|
||||
struct tep_event *event, const char *field)
|
||||
{
|
||||
unsigned long long isa;
|
||||
unsigned long long val;
|
||||
const char *reason;
|
||||
|
||||
if (tep_get_field_val(s, event, field, record, &val, 1) < 0)
|
||||
return -1;
|
||||
|
||||
if (tep_get_field_val(s, event, "isa", record, &isa, 0) < 0)
|
||||
isa = 1;
|
||||
|
||||
reason = find_exit_reason(isa, val);
|
||||
if (reason)
|
||||
trace_seq_printf(s, "reason %s", reason);
|
||||
else
|
||||
trace_seq_printf(s, "reason UNKNOWN (%llu)", val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_exit_handler(struct trace_seq *s, struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
unsigned long long info1 = 0, info2 = 0;
|
||||
|
||||
if (print_exit_reason(s, record, event, "exit_reason") < 0)
|
||||
return -1;
|
||||
|
||||
tep_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1);
|
||||
|
||||
if (tep_get_field_val(s, event, "info1", record, &info1, 0) >= 0
|
||||
&& tep_get_field_val(s, event, "info2", record, &info2, 0) >= 0)
|
||||
trace_seq_printf(s, " info %llx %llx", info1, info2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define KVM_EMUL_INSN_F_CR0_PE (1 << 0)
|
||||
#define KVM_EMUL_INSN_F_EFL_VM (1 << 1)
|
||||
#define KVM_EMUL_INSN_F_CS_D (1 << 2)
|
||||
#define KVM_EMUL_INSN_F_CS_L (1 << 3)
|
||||
|
||||
static int kvm_emulate_insn_handler(struct trace_seq *s,
|
||||
struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
unsigned long long rip, csbase, len, flags, failed;
|
||||
int llen;
|
||||
uint8_t *insn;
|
||||
const char *disasm;
|
||||
|
||||
if (tep_get_field_val(s, event, "rip", record, &rip, 1) < 0)
|
||||
return -1;
|
||||
|
||||
if (tep_get_field_val(s, event, "csbase", record, &csbase, 1) < 0)
|
||||
return -1;
|
||||
|
||||
if (tep_get_field_val(s, event, "len", record, &len, 1) < 0)
|
||||
return -1;
|
||||
|
||||
if (tep_get_field_val(s, event, "flags", record, &flags, 1) < 0)
|
||||
return -1;
|
||||
|
||||
if (tep_get_field_val(s, event, "failed", record, &failed, 1) < 0)
|
||||
return -1;
|
||||
|
||||
insn = tep_get_field_raw(s, event, "insn", record, &llen, 1);
|
||||
if (!insn)
|
||||
return -1;
|
||||
|
||||
disasm = disassemble(insn, len, rip,
|
||||
flags & KVM_EMUL_INSN_F_CR0_PE,
|
||||
flags & KVM_EMUL_INSN_F_EFL_VM,
|
||||
flags & KVM_EMUL_INSN_F_CS_D,
|
||||
flags & KVM_EMUL_INSN_F_CS_L);
|
||||
|
||||
trace_seq_printf(s, "%llx:%llx: %s%s", csbase, rip, disasm,
|
||||
failed ? " FAIL" : "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
if (print_exit_reason(s, record, event, "exit_code") < 0)
|
||||
return -1;
|
||||
|
||||
tep_print_num_field(s, " info1 %llx", event, "exit_info1", record, 1);
|
||||
tep_print_num_field(s, " info2 %llx", event, "exit_info2", record, 1);
|
||||
tep_print_num_field(s, " int_info %llx", event, "exit_int_info", record, 1);
|
||||
tep_print_num_field(s, " int_info_err %llx", event, "exit_int_info_err", record, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_nested_vmexit_handler(struct trace_seq *s, struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
tep_print_num_field(s, "rip %llx ", event, "rip", record, 1);
|
||||
|
||||
return kvm_nested_vmexit_inject_handler(s, record, event, context);
|
||||
}
|
||||
|
||||
union kvm_mmu_page_role {
|
||||
unsigned word;
|
||||
struct {
|
||||
unsigned level:4;
|
||||
unsigned cr4_pae:1;
|
||||
unsigned quadrant:2;
|
||||
unsigned direct:1;
|
||||
unsigned access:3;
|
||||
unsigned invalid:1;
|
||||
unsigned efer_nx:1;
|
||||
unsigned cr0_wp:1;
|
||||
unsigned smep_and_not_wp:1;
|
||||
unsigned smap_and_not_wp:1;
|
||||
unsigned pad_for_nice_hex_output:8;
|
||||
unsigned smm:8;
|
||||
};
|
||||
};
|
||||
|
||||
static int kvm_mmu_print_role(struct trace_seq *s, struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
unsigned long long val;
|
||||
static const char *access_str[] = {
|
||||
"---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux"
|
||||
};
|
||||
union kvm_mmu_page_role role;
|
||||
|
||||
if (tep_get_field_val(s, event, "role", record, &val, 1) < 0)
|
||||
return -1;
|
||||
|
||||
role.word = (int)val;
|
||||
|
||||
/*
|
||||
* We can only use the structure if file is of the same
|
||||
* endianness.
|
||||
*/
|
||||
if (tep_is_file_bigendian(event->tep) ==
|
||||
tep_is_local_bigendian(event->tep)) {
|
||||
|
||||
trace_seq_printf(s, "%u q%u%s %s%s %spae %snxe %swp%s%s%s",
|
||||
role.level,
|
||||
role.quadrant,
|
||||
role.direct ? " direct" : "",
|
||||
access_str[role.access],
|
||||
role.invalid ? " invalid" : "",
|
||||
role.cr4_pae ? "" : "!",
|
||||
role.efer_nx ? "" : "!",
|
||||
role.cr0_wp ? "" : "!",
|
||||
role.smep_and_not_wp ? " smep" : "",
|
||||
role.smap_and_not_wp ? " smap" : "",
|
||||
role.smm ? " smm" : "");
|
||||
} else
|
||||
trace_seq_printf(s, "WORD: %08x", role.word);
|
||||
|
||||
tep_print_num_field(s, " root %u ", event,
|
||||
"root_count", record, 1);
|
||||
|
||||
if (tep_get_field_val(s, event, "unsync", record, &val, 1) < 0)
|
||||
return -1;
|
||||
|
||||
trace_seq_printf(s, "%s%c", val ? "unsync" : "sync", 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_mmu_get_page_handler(struct trace_seq *s,
|
||||
struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
unsigned long long val;
|
||||
|
||||
if (tep_get_field_val(s, event, "created", record, &val, 1) < 0)
|
||||
return -1;
|
||||
|
||||
trace_seq_printf(s, "%s ", val ? "new" : "existing");
|
||||
|
||||
if (tep_get_field_val(s, event, "gfn", record, &val, 1) < 0)
|
||||
return -1;
|
||||
|
||||
trace_seq_printf(s, "sp gfn %llx ", val);
|
||||
return kvm_mmu_print_role(s, record, event, context);
|
||||
}
|
||||
|
||||
#define PT_WRITABLE_SHIFT 1
|
||||
#define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT)
|
||||
|
||||
static unsigned long long
|
||||
process_is_writable_pte(struct trace_seq *s, unsigned long long *args)
|
||||
{
|
||||
unsigned long pte = args[0];
|
||||
return pte & PT_WRITABLE_MASK;
|
||||
}
|
||||
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *tep)
|
||||
{
|
||||
init_disassembler();
|
||||
|
||||
tep_register_event_handler(tep, -1, "kvm", "kvm_exit",
|
||||
kvm_exit_handler, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1, "kvm", "kvm_emulate_insn",
|
||||
kvm_emulate_insn_handler, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1, "kvm", "kvm_nested_vmexit",
|
||||
kvm_nested_vmexit_handler, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1, "kvm", "kvm_nested_vmexit_inject",
|
||||
kvm_nested_vmexit_inject_handler, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1, "kvmmmu", "kvm_mmu_get_page",
|
||||
kvm_mmu_get_page_handler, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1, "kvmmmu", "kvm_mmu_sync_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1,
|
||||
"kvmmmu", "kvm_mmu_unsync_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1, "kvmmmu", "kvm_mmu_zap_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1, "kvmmmu",
|
||||
"kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
|
||||
NULL);
|
||||
|
||||
tep_register_print_function(tep,
|
||||
process_is_writable_pte,
|
||||
TEP_FUNC_ARG_INT,
|
||||
"is_writable_pte",
|
||||
TEP_FUNC_ARG_LONG,
|
||||
TEP_FUNC_ARG_VOID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_unregister_event_handler(tep, -1, "kvm", "kvm_exit",
|
||||
kvm_exit_handler, NULL);
|
||||
|
||||
tep_unregister_event_handler(tep, -1, "kvm", "kvm_emulate_insn",
|
||||
kvm_emulate_insn_handler, NULL);
|
||||
|
||||
tep_unregister_event_handler(tep, -1, "kvm", "kvm_nested_vmexit",
|
||||
kvm_nested_vmexit_handler, NULL);
|
||||
|
||||
tep_unregister_event_handler(tep, -1, "kvm", "kvm_nested_vmexit_inject",
|
||||
kvm_nested_vmexit_inject_handler, NULL);
|
||||
|
||||
tep_unregister_event_handler(tep, -1, "kvmmmu", "kvm_mmu_get_page",
|
||||
kvm_mmu_get_page_handler, NULL);
|
||||
|
||||
tep_unregister_event_handler(tep, -1, "kvmmmu", "kvm_mmu_sync_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
|
||||
tep_unregister_event_handler(tep, -1,
|
||||
"kvmmmu", "kvm_mmu_unsync_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
|
||||
tep_unregister_event_handler(tep, -1, "kvmmmu", "kvm_mmu_zap_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
|
||||
tep_unregister_event_handler(tep, -1, "kvmmmu",
|
||||
"kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
|
||||
NULL);
|
||||
|
||||
tep_unregister_print_function(tep, process_is_writable_pte,
|
||||
"is_writable_pte");
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2009 Johannes Berg <johannes@sipsolutions.net>
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "event-parse.h"
|
||||
#include "trace-seq.h"
|
||||
|
||||
#define INDENT 65
|
||||
|
||||
static void print_string(struct trace_seq *s, struct tep_event *event,
|
||||
const char *name, const void *data)
|
||||
{
|
||||
struct tep_format_field *f = tep_find_field(event, name);
|
||||
int offset;
|
||||
int length;
|
||||
|
||||
if (!f) {
|
||||
trace_seq_printf(s, "NOTFOUND:%s", name);
|
||||
return;
|
||||
}
|
||||
|
||||
offset = f->offset;
|
||||
length = f->size;
|
||||
|
||||
if (!strncmp(f->type, "__data_loc", 10)) {
|
||||
unsigned long long v;
|
||||
if (tep_read_number_field(f, data, &v)) {
|
||||
trace_seq_printf(s, "invalid_data_loc");
|
||||
return;
|
||||
}
|
||||
offset = v & 0xffff;
|
||||
length = v >> 16;
|
||||
}
|
||||
|
||||
trace_seq_printf(s, "%.*s", length, (char *)data + offset);
|
||||
}
|
||||
|
||||
#define SF(fn) tep_print_num_field(s, fn ":%d", event, fn, record, 0)
|
||||
#define SFX(fn) tep_print_num_field(s, fn ":%#x", event, fn, record, 0)
|
||||
#define SP() trace_seq_putc(s, ' ')
|
||||
|
||||
static int drv_bss_info_changed(struct trace_seq *s,
|
||||
struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
void *data = record->data;
|
||||
|
||||
print_string(s, event, "wiphy_name", data);
|
||||
trace_seq_printf(s, " vif:");
|
||||
print_string(s, event, "vif_name", data);
|
||||
tep_print_num_field(s, "(%d)", event, "vif_type", record, 1);
|
||||
|
||||
trace_seq_printf(s, "\n%*s", INDENT, "");
|
||||
SF("assoc"); SP();
|
||||
SF("aid"); SP();
|
||||
SF("cts"); SP();
|
||||
SF("shortpre"); SP();
|
||||
SF("shortslot"); SP();
|
||||
SF("dtimper"); SP();
|
||||
trace_seq_printf(s, "\n%*s", INDENT, "");
|
||||
SF("bcnint"); SP();
|
||||
SFX("assoc_cap"); SP();
|
||||
SFX("basic_rates"); SP();
|
||||
SF("enable_beacon");
|
||||
trace_seq_printf(s, "\n%*s", INDENT, "");
|
||||
SF("ht_operation_mode");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_register_event_handler(tep, -1, "mac80211",
|
||||
"drv_bss_info_changed",
|
||||
drv_bss_info_changed, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_unregister_event_handler(tep, -1, "mac80211",
|
||||
"drv_bss_info_changed",
|
||||
drv_bss_info_changed, NULL);
|
||||
}
|
@ -1,146 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "event-parse.h"
|
||||
#include "trace-seq.h"
|
||||
|
||||
static void write_state(struct trace_seq *s, int val)
|
||||
{
|
||||
const char states[] = "SDTtZXxW";
|
||||
int found = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (sizeof(states) - 1); i++) {
|
||||
if (!(val & (1 << i)))
|
||||
continue;
|
||||
|
||||
if (found)
|
||||
trace_seq_putc(s, '|');
|
||||
|
||||
found = 1;
|
||||
trace_seq_putc(s, states[i]);
|
||||
}
|
||||
|
||||
if (!found)
|
||||
trace_seq_putc(s, 'R');
|
||||
}
|
||||
|
||||
static void write_and_save_comm(struct tep_format_field *field,
|
||||
struct tep_record *record,
|
||||
struct trace_seq *s, int pid)
|
||||
{
|
||||
const char *comm;
|
||||
int len;
|
||||
|
||||
comm = (char *)(record->data + field->offset);
|
||||
len = s->len;
|
||||
trace_seq_printf(s, "%.*s",
|
||||
field->size, comm);
|
||||
|
||||
/* make sure the comm has a \0 at the end. */
|
||||
trace_seq_terminate(s);
|
||||
comm = &s->buffer[len];
|
||||
|
||||
/* Help out the comm to ids. This will handle dups */
|
||||
tep_register_comm(field->event->tep, comm, pid);
|
||||
}
|
||||
|
||||
static int sched_wakeup_handler(struct trace_seq *s,
|
||||
struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
struct tep_format_field *field;
|
||||
unsigned long long val;
|
||||
|
||||
if (tep_get_field_val(s, event, "pid", record, &val, 1))
|
||||
return trace_seq_putc(s, '!');
|
||||
|
||||
field = tep_find_any_field(event, "comm");
|
||||
if (field) {
|
||||
write_and_save_comm(field, record, s, val);
|
||||
trace_seq_putc(s, ':');
|
||||
}
|
||||
trace_seq_printf(s, "%lld", val);
|
||||
|
||||
if (tep_get_field_val(s, event, "prio", record, &val, 0) == 0)
|
||||
trace_seq_printf(s, " [%lld]", val);
|
||||
|
||||
if (tep_get_field_val(s, event, "success", record, &val, 1) == 0)
|
||||
trace_seq_printf(s, " success=%lld", val);
|
||||
|
||||
if (tep_get_field_val(s, event, "target_cpu", record, &val, 0) == 0)
|
||||
trace_seq_printf(s, " CPU:%03llu", val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sched_switch_handler(struct trace_seq *s,
|
||||
struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
struct tep_format_field *field;
|
||||
unsigned long long val;
|
||||
|
||||
if (tep_get_field_val(s, event, "prev_pid", record, &val, 1))
|
||||
return trace_seq_putc(s, '!');
|
||||
|
||||
field = tep_find_any_field(event, "prev_comm");
|
||||
if (field) {
|
||||
write_and_save_comm(field, record, s, val);
|
||||
trace_seq_putc(s, ':');
|
||||
}
|
||||
trace_seq_printf(s, "%lld ", val);
|
||||
|
||||
if (tep_get_field_val(s, event, "prev_prio", record, &val, 0) == 0)
|
||||
trace_seq_printf(s, "[%d] ", (int) val);
|
||||
|
||||
if (tep_get_field_val(s, event, "prev_state", record, &val, 0) == 0)
|
||||
write_state(s, val);
|
||||
|
||||
trace_seq_puts(s, " ==> ");
|
||||
|
||||
if (tep_get_field_val(s, event, "next_pid", record, &val, 1))
|
||||
return trace_seq_putc(s, '!');
|
||||
|
||||
field = tep_find_any_field(event, "next_comm");
|
||||
if (field) {
|
||||
write_and_save_comm(field, record, s, val);
|
||||
trace_seq_putc(s, ':');
|
||||
}
|
||||
trace_seq_printf(s, "%lld", val);
|
||||
|
||||
if (tep_get_field_val(s, event, "next_prio", record, &val, 0) == 0)
|
||||
trace_seq_printf(s, " [%d]", (int) val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_register_event_handler(tep, -1, "sched", "sched_switch",
|
||||
sched_switch_handler, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1, "sched", "sched_wakeup",
|
||||
sched_wakeup_handler, NULL);
|
||||
|
||||
tep_register_event_handler(tep, -1, "sched", "sched_wakeup_new",
|
||||
sched_wakeup_handler, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_unregister_event_handler(tep, -1, "sched", "sched_switch",
|
||||
sched_switch_handler, NULL);
|
||||
|
||||
tep_unregister_event_handler(tep, -1, "sched", "sched_wakeup",
|
||||
sched_wakeup_handler, NULL);
|
||||
|
||||
tep_unregister_event_handler(tep, -1, "sched", "sched_wakeup_new",
|
||||
sched_wakeup_handler, NULL);
|
||||
}
|
@ -1,434 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "event-parse.h"
|
||||
#include "trace-seq.h"
|
||||
|
||||
typedef unsigned long sector_t;
|
||||
typedef uint64_t u64;
|
||||
typedef unsigned int u32;
|
||||
|
||||
/*
|
||||
* SCSI opcodes
|
||||
*/
|
||||
#define TEST_UNIT_READY 0x00
|
||||
#define REZERO_UNIT 0x01
|
||||
#define REQUEST_SENSE 0x03
|
||||
#define FORMAT_UNIT 0x04
|
||||
#define READ_BLOCK_LIMITS 0x05
|
||||
#define REASSIGN_BLOCKS 0x07
|
||||
#define INITIALIZE_ELEMENT_STATUS 0x07
|
||||
#define READ_6 0x08
|
||||
#define WRITE_6 0x0a
|
||||
#define SEEK_6 0x0b
|
||||
#define READ_REVERSE 0x0f
|
||||
#define WRITE_FILEMARKS 0x10
|
||||
#define SPACE 0x11
|
||||
#define INQUIRY 0x12
|
||||
#define RECOVER_BUFFERED_DATA 0x14
|
||||
#define MODE_SELECT 0x15
|
||||
#define RESERVE 0x16
|
||||
#define RELEASE 0x17
|
||||
#define COPY 0x18
|
||||
#define ERASE 0x19
|
||||
#define MODE_SENSE 0x1a
|
||||
#define START_STOP 0x1b
|
||||
#define RECEIVE_DIAGNOSTIC 0x1c
|
||||
#define SEND_DIAGNOSTIC 0x1d
|
||||
#define ALLOW_MEDIUM_REMOVAL 0x1e
|
||||
|
||||
#define READ_FORMAT_CAPACITIES 0x23
|
||||
#define SET_WINDOW 0x24
|
||||
#define READ_CAPACITY 0x25
|
||||
#define READ_10 0x28
|
||||
#define WRITE_10 0x2a
|
||||
#define SEEK_10 0x2b
|
||||
#define POSITION_TO_ELEMENT 0x2b
|
||||
#define WRITE_VERIFY 0x2e
|
||||
#define VERIFY 0x2f
|
||||
#define SEARCH_HIGH 0x30
|
||||
#define SEARCH_EQUAL 0x31
|
||||
#define SEARCH_LOW 0x32
|
||||
#define SET_LIMITS 0x33
|
||||
#define PRE_FETCH 0x34
|
||||
#define READ_POSITION 0x34
|
||||
#define SYNCHRONIZE_CACHE 0x35
|
||||
#define LOCK_UNLOCK_CACHE 0x36
|
||||
#define READ_DEFECT_DATA 0x37
|
||||
#define MEDIUM_SCAN 0x38
|
||||
#define COMPARE 0x39
|
||||
#define COPY_VERIFY 0x3a
|
||||
#define WRITE_BUFFER 0x3b
|
||||
#define READ_BUFFER 0x3c
|
||||
#define UPDATE_BLOCK 0x3d
|
||||
#define READ_LONG 0x3e
|
||||
#define WRITE_LONG 0x3f
|
||||
#define CHANGE_DEFINITION 0x40
|
||||
#define WRITE_SAME 0x41
|
||||
#define UNMAP 0x42
|
||||
#define READ_TOC 0x43
|
||||
#define READ_HEADER 0x44
|
||||
#define GET_EVENT_STATUS_NOTIFICATION 0x4a
|
||||
#define LOG_SELECT 0x4c
|
||||
#define LOG_SENSE 0x4d
|
||||
#define XDWRITEREAD_10 0x53
|
||||
#define MODE_SELECT_10 0x55
|
||||
#define RESERVE_10 0x56
|
||||
#define RELEASE_10 0x57
|
||||
#define MODE_SENSE_10 0x5a
|
||||
#define PERSISTENT_RESERVE_IN 0x5e
|
||||
#define PERSISTENT_RESERVE_OUT 0x5f
|
||||
#define VARIABLE_LENGTH_CMD 0x7f
|
||||
#define REPORT_LUNS 0xa0
|
||||
#define SECURITY_PROTOCOL_IN 0xa2
|
||||
#define MAINTENANCE_IN 0xa3
|
||||
#define MAINTENANCE_OUT 0xa4
|
||||
#define MOVE_MEDIUM 0xa5
|
||||
#define EXCHANGE_MEDIUM 0xa6
|
||||
#define READ_12 0xa8
|
||||
#define SERVICE_ACTION_OUT_12 0xa9
|
||||
#define WRITE_12 0xaa
|
||||
#define SERVICE_ACTION_IN_12 0xab
|
||||
#define WRITE_VERIFY_12 0xae
|
||||
#define VERIFY_12 0xaf
|
||||
#define SEARCH_HIGH_12 0xb0
|
||||
#define SEARCH_EQUAL_12 0xb1
|
||||
#define SEARCH_LOW_12 0xb2
|
||||
#define SECURITY_PROTOCOL_OUT 0xb5
|
||||
#define READ_ELEMENT_STATUS 0xb8
|
||||
#define SEND_VOLUME_TAG 0xb6
|
||||
#define WRITE_LONG_2 0xea
|
||||
#define EXTENDED_COPY 0x83
|
||||
#define RECEIVE_COPY_RESULTS 0x84
|
||||
#define ACCESS_CONTROL_IN 0x86
|
||||
#define ACCESS_CONTROL_OUT 0x87
|
||||
#define READ_16 0x88
|
||||
#define WRITE_16 0x8a
|
||||
#define READ_ATTRIBUTE 0x8c
|
||||
#define WRITE_ATTRIBUTE 0x8d
|
||||
#define VERIFY_16 0x8f
|
||||
#define SYNCHRONIZE_CACHE_16 0x91
|
||||
#define WRITE_SAME_16 0x93
|
||||
#define SERVICE_ACTION_BIDIRECTIONAL 0x9d
|
||||
#define SERVICE_ACTION_IN_16 0x9e
|
||||
#define SERVICE_ACTION_OUT_16 0x9f
|
||||
/* values for service action in */
|
||||
#define SAI_READ_CAPACITY_16 0x10
|
||||
#define SAI_GET_LBA_STATUS 0x12
|
||||
/* values for VARIABLE_LENGTH_CMD service action codes
|
||||
* see spc4r17 Section D.3.5, table D.7 and D.8 */
|
||||
#define VLC_SA_RECEIVE_CREDENTIAL 0x1800
|
||||
/* values for maintenance in */
|
||||
#define MI_REPORT_IDENTIFYING_INFORMATION 0x05
|
||||
#define MI_REPORT_TARGET_PGS 0x0a
|
||||
#define MI_REPORT_ALIASES 0x0b
|
||||
#define MI_REPORT_SUPPORTED_OPERATION_CODES 0x0c
|
||||
#define MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS 0x0d
|
||||
#define MI_REPORT_PRIORITY 0x0e
|
||||
#define MI_REPORT_TIMESTAMP 0x0f
|
||||
#define MI_MANAGEMENT_PROTOCOL_IN 0x10
|
||||
/* value for MI_REPORT_TARGET_PGS ext header */
|
||||
#define MI_EXT_HDR_PARAM_FMT 0x20
|
||||
/* values for maintenance out */
|
||||
#define MO_SET_IDENTIFYING_INFORMATION 0x06
|
||||
#define MO_SET_TARGET_PGS 0x0a
|
||||
#define MO_CHANGE_ALIASES 0x0b
|
||||
#define MO_SET_PRIORITY 0x0e
|
||||
#define MO_SET_TIMESTAMP 0x0f
|
||||
#define MO_MANAGEMENT_PROTOCOL_OUT 0x10
|
||||
/* values for variable length command */
|
||||
#define XDREAD_32 0x03
|
||||
#define XDWRITE_32 0x04
|
||||
#define XPWRITE_32 0x06
|
||||
#define XDWRITEREAD_32 0x07
|
||||
#define READ_32 0x09
|
||||
#define VERIFY_32 0x0a
|
||||
#define WRITE_32 0x0b
|
||||
#define WRITE_SAME_32 0x0d
|
||||
|
||||
#define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f)
|
||||
#define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9])
|
||||
|
||||
static const char *
|
||||
scsi_trace_misc(struct trace_seq *, unsigned char *, int);
|
||||
|
||||
static const char *
|
||||
scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len)
|
||||
{
|
||||
const char *ret = p->buffer + p->len;
|
||||
sector_t lba = 0, txlen = 0;
|
||||
|
||||
lba |= ((cdb[1] & 0x1F) << 16);
|
||||
lba |= (cdb[2] << 8);
|
||||
lba |= cdb[3];
|
||||
txlen = cdb[4];
|
||||
|
||||
trace_seq_printf(p, "lba=%llu txlen=%llu",
|
||||
(unsigned long long)lba, (unsigned long long)txlen);
|
||||
trace_seq_putc(p, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *
|
||||
scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len)
|
||||
{
|
||||
const char *ret = p->buffer + p->len;
|
||||
sector_t lba = 0, txlen = 0;
|
||||
|
||||
lba |= (cdb[2] << 24);
|
||||
lba |= (cdb[3] << 16);
|
||||
lba |= (cdb[4] << 8);
|
||||
lba |= cdb[5];
|
||||
txlen |= (cdb[7] << 8);
|
||||
txlen |= cdb[8];
|
||||
|
||||
trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
|
||||
(unsigned long long)lba, (unsigned long long)txlen,
|
||||
cdb[1] >> 5);
|
||||
|
||||
if (cdb[0] == WRITE_SAME)
|
||||
trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);
|
||||
|
||||
trace_seq_putc(p, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *
|
||||
scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len)
|
||||
{
|
||||
const char *ret = p->buffer + p->len;
|
||||
sector_t lba = 0, txlen = 0;
|
||||
|
||||
lba |= (cdb[2] << 24);
|
||||
lba |= (cdb[3] << 16);
|
||||
lba |= (cdb[4] << 8);
|
||||
lba |= cdb[5];
|
||||
txlen |= (cdb[6] << 24);
|
||||
txlen |= (cdb[7] << 16);
|
||||
txlen |= (cdb[8] << 8);
|
||||
txlen |= cdb[9];
|
||||
|
||||
trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
|
||||
(unsigned long long)lba, (unsigned long long)txlen,
|
||||
cdb[1] >> 5);
|
||||
trace_seq_putc(p, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *
|
||||
scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len)
|
||||
{
|
||||
const char *ret = p->buffer + p->len;
|
||||
sector_t lba = 0, txlen = 0;
|
||||
|
||||
lba |= ((u64)cdb[2] << 56);
|
||||
lba |= ((u64)cdb[3] << 48);
|
||||
lba |= ((u64)cdb[4] << 40);
|
||||
lba |= ((u64)cdb[5] << 32);
|
||||
lba |= (cdb[6] << 24);
|
||||
lba |= (cdb[7] << 16);
|
||||
lba |= (cdb[8] << 8);
|
||||
lba |= cdb[9];
|
||||
txlen |= (cdb[10] << 24);
|
||||
txlen |= (cdb[11] << 16);
|
||||
txlen |= (cdb[12] << 8);
|
||||
txlen |= cdb[13];
|
||||
|
||||
trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
|
||||
(unsigned long long)lba, (unsigned long long)txlen,
|
||||
cdb[1] >> 5);
|
||||
|
||||
if (cdb[0] == WRITE_SAME_16)
|
||||
trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);
|
||||
|
||||
trace_seq_putc(p, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *
|
||||
scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len)
|
||||
{
|
||||
const char *ret = p->buffer + p->len, *cmd;
|
||||
sector_t lba = 0, txlen = 0;
|
||||
u32 ei_lbrt = 0;
|
||||
|
||||
switch (SERVICE_ACTION32(cdb)) {
|
||||
case READ_32:
|
||||
cmd = "READ";
|
||||
break;
|
||||
case VERIFY_32:
|
||||
cmd = "VERIFY";
|
||||
break;
|
||||
case WRITE_32:
|
||||
cmd = "WRITE";
|
||||
break;
|
||||
case WRITE_SAME_32:
|
||||
cmd = "WRITE_SAME";
|
||||
break;
|
||||
default:
|
||||
trace_seq_printf(p, "UNKNOWN");
|
||||
goto out;
|
||||
}
|
||||
|
||||
lba |= ((u64)cdb[12] << 56);
|
||||
lba |= ((u64)cdb[13] << 48);
|
||||
lba |= ((u64)cdb[14] << 40);
|
||||
lba |= ((u64)cdb[15] << 32);
|
||||
lba |= (cdb[16] << 24);
|
||||
lba |= (cdb[17] << 16);
|
||||
lba |= (cdb[18] << 8);
|
||||
lba |= cdb[19];
|
||||
ei_lbrt |= (cdb[20] << 24);
|
||||
ei_lbrt |= (cdb[21] << 16);
|
||||
ei_lbrt |= (cdb[22] << 8);
|
||||
ei_lbrt |= cdb[23];
|
||||
txlen |= (cdb[28] << 24);
|
||||
txlen |= (cdb[29] << 16);
|
||||
txlen |= (cdb[30] << 8);
|
||||
txlen |= cdb[31];
|
||||
|
||||
trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u",
|
||||
cmd, (unsigned long long)lba,
|
||||
(unsigned long long)txlen, cdb[10] >> 5, ei_lbrt);
|
||||
|
||||
if (SERVICE_ACTION32(cdb) == WRITE_SAME_32)
|
||||
trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1);
|
||||
|
||||
out:
|
||||
trace_seq_putc(p, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *
|
||||
scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len)
|
||||
{
|
||||
const char *ret = p->buffer + p->len;
|
||||
unsigned int regions = cdb[7] << 8 | cdb[8];
|
||||
|
||||
trace_seq_printf(p, "regions=%u", (regions - 8) / 16);
|
||||
trace_seq_putc(p, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *
|
||||
scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len)
|
||||
{
|
||||
const char *ret = p->buffer + p->len, *cmd;
|
||||
sector_t lba = 0;
|
||||
u32 alloc_len = 0;
|
||||
|
||||
switch (SERVICE_ACTION16(cdb)) {
|
||||
case SAI_READ_CAPACITY_16:
|
||||
cmd = "READ_CAPACITY_16";
|
||||
break;
|
||||
case SAI_GET_LBA_STATUS:
|
||||
cmd = "GET_LBA_STATUS";
|
||||
break;
|
||||
default:
|
||||
trace_seq_printf(p, "UNKNOWN");
|
||||
goto out;
|
||||
}
|
||||
|
||||
lba |= ((u64)cdb[2] << 56);
|
||||
lba |= ((u64)cdb[3] << 48);
|
||||
lba |= ((u64)cdb[4] << 40);
|
||||
lba |= ((u64)cdb[5] << 32);
|
||||
lba |= (cdb[6] << 24);
|
||||
lba |= (cdb[7] << 16);
|
||||
lba |= (cdb[8] << 8);
|
||||
lba |= cdb[9];
|
||||
alloc_len |= (cdb[10] << 24);
|
||||
alloc_len |= (cdb[11] << 16);
|
||||
alloc_len |= (cdb[12] << 8);
|
||||
alloc_len |= cdb[13];
|
||||
|
||||
trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd,
|
||||
(unsigned long long)lba, alloc_len);
|
||||
|
||||
out:
|
||||
trace_seq_putc(p, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *
|
||||
scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len)
|
||||
{
|
||||
switch (SERVICE_ACTION32(cdb)) {
|
||||
case READ_32:
|
||||
case VERIFY_32:
|
||||
case WRITE_32:
|
||||
case WRITE_SAME_32:
|
||||
return scsi_trace_rw32(p, cdb, len);
|
||||
default:
|
||||
return scsi_trace_misc(p, cdb, len);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len)
|
||||
{
|
||||
const char *ret = p->buffer + p->len;
|
||||
|
||||
trace_seq_printf(p, "-");
|
||||
trace_seq_putc(p, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *
|
||||
scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len)
|
||||
{
|
||||
switch (cdb[0]) {
|
||||
case READ_6:
|
||||
case WRITE_6:
|
||||
return scsi_trace_rw6(p, cdb, len);
|
||||
case READ_10:
|
||||
case VERIFY:
|
||||
case WRITE_10:
|
||||
case WRITE_SAME:
|
||||
return scsi_trace_rw10(p, cdb, len);
|
||||
case READ_12:
|
||||
case VERIFY_12:
|
||||
case WRITE_12:
|
||||
return scsi_trace_rw12(p, cdb, len);
|
||||
case READ_16:
|
||||
case VERIFY_16:
|
||||
case WRITE_16:
|
||||
case WRITE_SAME_16:
|
||||
return scsi_trace_rw16(p, cdb, len);
|
||||
case UNMAP:
|
||||
return scsi_trace_unmap(p, cdb, len);
|
||||
case SERVICE_ACTION_IN_16:
|
||||
return scsi_trace_service_action_in(p, cdb, len);
|
||||
case VARIABLE_LENGTH_CMD:
|
||||
return scsi_trace_varlen(p, cdb, len);
|
||||
default:
|
||||
return scsi_trace_misc(p, cdb, len);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long long process_scsi_trace_parse_cdb(struct trace_seq *s,
|
||||
unsigned long long *args)
|
||||
{
|
||||
scsi_trace_parse_cdb(s, (unsigned char *) (unsigned long) args[1], args[2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_register_print_function(tep,
|
||||
process_scsi_trace_parse_cdb,
|
||||
TEP_FUNC_ARG_STRING,
|
||||
"scsi_trace_parse_cdb",
|
||||
TEP_FUNC_ARG_PTR,
|
||||
TEP_FUNC_ARG_PTR,
|
||||
TEP_FUNC_ARG_INT,
|
||||
TEP_FUNC_ARG_VOID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_unregister_print_function(tep, process_scsi_trace_parse_cdb,
|
||||
"scsi_trace_parse_cdb");
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2015 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "event-parse.h"
|
||||
|
||||
enum tlb_flush_reason {
|
||||
TLB_FLUSH_ON_TASK_SWITCH,
|
||||
TLB_REMOTE_SHOOTDOWN,
|
||||
TLB_LOCAL_SHOOTDOWN,
|
||||
TLB_LOCAL_MM_SHOOTDOWN,
|
||||
NR_TLB_FLUSH_REASONS,
|
||||
};
|
||||
|
||||
static int tlb_flush_handler(struct trace_seq *s, struct tep_record *record,
|
||||
struct tep_event *event, void *context)
|
||||
{
|
||||
unsigned long long val;
|
||||
|
||||
trace_seq_printf(s, "pages=");
|
||||
|
||||
tep_print_num_field(s, "%ld", event, "pages", record, 1);
|
||||
|
||||
if (tep_get_field_val(s, event, "reason", record, &val, 1) < 0)
|
||||
return -1;
|
||||
|
||||
trace_seq_puts(s, " reason=");
|
||||
|
||||
switch (val) {
|
||||
case TLB_FLUSH_ON_TASK_SWITCH:
|
||||
trace_seq_puts(s, "flush on task switch");
|
||||
break;
|
||||
case TLB_REMOTE_SHOOTDOWN:
|
||||
trace_seq_puts(s, "remote shootdown");
|
||||
break;
|
||||
case TLB_LOCAL_SHOOTDOWN:
|
||||
trace_seq_puts(s, "local shootdown");
|
||||
break;
|
||||
case TLB_LOCAL_MM_SHOOTDOWN:
|
||||
trace_seq_puts(s, "local mm shootdown");
|
||||
break;
|
||||
}
|
||||
|
||||
trace_seq_printf(s, " (%lld)", val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_register_event_handler(tep, -1, "tlb", "tlb_flush",
|
||||
tlb_flush_handler, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_unregister_event_handler(tep, -1,
|
||||
"tlb", "tlb_flush",
|
||||
tlb_flush_handler, NULL);
|
||||
}
|
@ -1,138 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "event-parse.h"
|
||||
#include "trace-seq.h"
|
||||
|
||||
#define __HYPERVISOR_set_trap_table 0
|
||||
#define __HYPERVISOR_mmu_update 1
|
||||
#define __HYPERVISOR_set_gdt 2
|
||||
#define __HYPERVISOR_stack_switch 3
|
||||
#define __HYPERVISOR_set_callbacks 4
|
||||
#define __HYPERVISOR_fpu_taskswitch 5
|
||||
#define __HYPERVISOR_sched_op_compat 6
|
||||
#define __HYPERVISOR_dom0_op 7
|
||||
#define __HYPERVISOR_set_debugreg 8
|
||||
#define __HYPERVISOR_get_debugreg 9
|
||||
#define __HYPERVISOR_update_descriptor 10
|
||||
#define __HYPERVISOR_memory_op 12
|
||||
#define __HYPERVISOR_multicall 13
|
||||
#define __HYPERVISOR_update_va_mapping 14
|
||||
#define __HYPERVISOR_set_timer_op 15
|
||||
#define __HYPERVISOR_event_channel_op_compat 16
|
||||
#define __HYPERVISOR_xen_version 17
|
||||
#define __HYPERVISOR_console_io 18
|
||||
#define __HYPERVISOR_physdev_op_compat 19
|
||||
#define __HYPERVISOR_grant_table_op 20
|
||||
#define __HYPERVISOR_vm_assist 21
|
||||
#define __HYPERVISOR_update_va_mapping_otherdomain 22
|
||||
#define __HYPERVISOR_iret 23 /* x86 only */
|
||||
#define __HYPERVISOR_vcpu_op 24
|
||||
#define __HYPERVISOR_set_segment_base 25 /* x86/64 only */
|
||||
#define __HYPERVISOR_mmuext_op 26
|
||||
#define __HYPERVISOR_acm_op 27
|
||||
#define __HYPERVISOR_nmi_op 28
|
||||
#define __HYPERVISOR_sched_op 29
|
||||
#define __HYPERVISOR_callback_op 30
|
||||
#define __HYPERVISOR_xenoprof_op 31
|
||||
#define __HYPERVISOR_event_channel_op 32
|
||||
#define __HYPERVISOR_physdev_op 33
|
||||
#define __HYPERVISOR_hvm_op 34
|
||||
#define __HYPERVISOR_tmem_op 38
|
||||
|
||||
/* Architecture-specific hypercall definitions. */
|
||||
#define __HYPERVISOR_arch_0 48
|
||||
#define __HYPERVISOR_arch_1 49
|
||||
#define __HYPERVISOR_arch_2 50
|
||||
#define __HYPERVISOR_arch_3 51
|
||||
#define __HYPERVISOR_arch_4 52
|
||||
#define __HYPERVISOR_arch_5 53
|
||||
#define __HYPERVISOR_arch_6 54
|
||||
#define __HYPERVISOR_arch_7 55
|
||||
|
||||
#define N(x) [__HYPERVISOR_##x] = "("#x")"
|
||||
static const char *xen_hypercall_names[] = {
|
||||
N(set_trap_table),
|
||||
N(mmu_update),
|
||||
N(set_gdt),
|
||||
N(stack_switch),
|
||||
N(set_callbacks),
|
||||
N(fpu_taskswitch),
|
||||
N(sched_op_compat),
|
||||
N(dom0_op),
|
||||
N(set_debugreg),
|
||||
N(get_debugreg),
|
||||
N(update_descriptor),
|
||||
N(memory_op),
|
||||
N(multicall),
|
||||
N(update_va_mapping),
|
||||
N(set_timer_op),
|
||||
N(event_channel_op_compat),
|
||||
N(xen_version),
|
||||
N(console_io),
|
||||
N(physdev_op_compat),
|
||||
N(grant_table_op),
|
||||
N(vm_assist),
|
||||
N(update_va_mapping_otherdomain),
|
||||
N(iret),
|
||||
N(vcpu_op),
|
||||
N(set_segment_base),
|
||||
N(mmuext_op),
|
||||
N(acm_op),
|
||||
N(nmi_op),
|
||||
N(sched_op),
|
||||
N(callback_op),
|
||||
N(xenoprof_op),
|
||||
N(event_channel_op),
|
||||
N(physdev_op),
|
||||
N(hvm_op),
|
||||
|
||||
/* Architecture-specific hypercall definitions. */
|
||||
N(arch_0),
|
||||
N(arch_1),
|
||||
N(arch_2),
|
||||
N(arch_3),
|
||||
N(arch_4),
|
||||
N(arch_5),
|
||||
N(arch_6),
|
||||
N(arch_7),
|
||||
};
|
||||
#undef N
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
static const char *xen_hypercall_name(unsigned op)
|
||||
{
|
||||
if (op < ARRAY_SIZE(xen_hypercall_names) &&
|
||||
xen_hypercall_names[op] != NULL)
|
||||
return xen_hypercall_names[op];
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
unsigned long long process_xen_hypercall_name(struct trace_seq *s,
|
||||
unsigned long long *args)
|
||||
{
|
||||
unsigned int op = args[0];
|
||||
|
||||
trace_seq_printf(s, "%s", xen_hypercall_name(op));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_register_print_function(tep,
|
||||
process_xen_hypercall_name,
|
||||
TEP_FUNC_ARG_STRING,
|
||||
"xen_hypercall_name",
|
||||
TEP_FUNC_ARG_INT,
|
||||
TEP_FUNC_ARG_VOID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
|
||||
{
|
||||
tep_unregister_print_function(tep, process_xen_hypercall_name,
|
||||
"xen_hypercall_name");
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
#undef _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "event-parse.h"
|
||||
|
||||
#undef _PE
|
||||
#define _PE(code, str) str
|
||||
static const char * const tep_error_str[] = {
|
||||
TEP_ERRORS
|
||||
};
|
||||
#undef _PE
|
||||
|
||||
/*
|
||||
* The tools so far have been using the strerror_r() GNU variant, that returns
|
||||
* a string, be it the buffer passed or something else.
|
||||
*
|
||||
* But that, besides being tricky in cases where we expect that the function
|
||||
* using strerror_r() returns the error formatted in a provided buffer (we have
|
||||
* to check if it returned something else and copy that instead), breaks the
|
||||
* build on systems not using glibc, like Alpine Linux, where musl libc is
|
||||
* used.
|
||||
*
|
||||
* So, introduce yet another wrapper, str_error_r(), that has the GNU
|
||||
* interface, but uses the portable XSI variant of strerror_r(), so that users
|
||||
* rest asured that the provided buffer is used and it is what is returned.
|
||||
*/
|
||||
int tep_strerror(struct tep_handle *tep __maybe_unused,
|
||||
enum tep_errno errnum, char *buf, size_t buflen)
|
||||
{
|
||||
const char *msg;
|
||||
int idx;
|
||||
|
||||
if (!buflen)
|
||||
return 0;
|
||||
|
||||
if (errnum >= 0) {
|
||||
int err = strerror_r(errnum, buf, buflen);
|
||||
buf[buflen - 1] = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
if (errnum <= __TEP_ERRNO__START ||
|
||||
errnum >= __TEP_ERRNO__END)
|
||||
return -1;
|
||||
|
||||
idx = errnum - __TEP_ERRNO__START - 1;
|
||||
msg = tep_error_str[idx];
|
||||
snprintf(buf, buflen, "%s", msg);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,249 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*
|
||||
*/
|
||||
#include "trace-seq.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <asm/bug.h>
|
||||
#include "event-parse.h"
|
||||
#include "event-utils.h"
|
||||
|
||||
/*
|
||||
* The TRACE_SEQ_POISON is to catch the use of using
|
||||
* a trace_seq structure after it was destroyed.
|
||||
*/
|
||||
#define TRACE_SEQ_POISON ((void *)0xdeadbeef)
|
||||
#define TRACE_SEQ_CHECK(s) \
|
||||
do { \
|
||||
if (WARN_ONCE((s)->buffer == TRACE_SEQ_POISON, \
|
||||
"Usage of trace_seq after it was destroyed")) \
|
||||
(s)->state = TRACE_SEQ__BUFFER_POISONED; \
|
||||
} while (0)
|
||||
|
||||
#define TRACE_SEQ_CHECK_RET_N(s, n) \
|
||||
do { \
|
||||
TRACE_SEQ_CHECK(s); \
|
||||
if ((s)->state != TRACE_SEQ__GOOD) \
|
||||
return n; \
|
||||
} while (0)
|
||||
|
||||
#define TRACE_SEQ_CHECK_RET(s) TRACE_SEQ_CHECK_RET_N(s, )
|
||||
#define TRACE_SEQ_CHECK_RET0(s) TRACE_SEQ_CHECK_RET_N(s, 0)
|
||||
|
||||
/**
|
||||
* trace_seq_init - initialize the trace_seq structure
|
||||
* @s: a pointer to the trace_seq structure to initialize
|
||||
*/
|
||||
void trace_seq_init(struct trace_seq *s)
|
||||
{
|
||||
s->len = 0;
|
||||
s->readpos = 0;
|
||||
s->buffer_size = TRACE_SEQ_BUF_SIZE;
|
||||
s->buffer = malloc(s->buffer_size);
|
||||
if (s->buffer != NULL)
|
||||
s->state = TRACE_SEQ__GOOD;
|
||||
else
|
||||
s->state = TRACE_SEQ__MEM_ALLOC_FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* trace_seq_reset - re-initialize the trace_seq structure
|
||||
* @s: a pointer to the trace_seq structure to reset
|
||||
*/
|
||||
void trace_seq_reset(struct trace_seq *s)
|
||||
{
|
||||
if (!s)
|
||||
return;
|
||||
TRACE_SEQ_CHECK(s);
|
||||
s->len = 0;
|
||||
s->readpos = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* trace_seq_destroy - free up memory of a trace_seq
|
||||
* @s: a pointer to the trace_seq to free the buffer
|
||||
*
|
||||
* Only frees the buffer, not the trace_seq struct itself.
|
||||
*/
|
||||
void trace_seq_destroy(struct trace_seq *s)
|
||||
{
|
||||
if (!s)
|
||||
return;
|
||||
TRACE_SEQ_CHECK_RET(s);
|
||||
free(s->buffer);
|
||||
s->buffer = TRACE_SEQ_POISON;
|
||||
}
|
||||
|
||||
static void expand_buffer(struct trace_seq *s)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
buf = realloc(s->buffer, s->buffer_size + TRACE_SEQ_BUF_SIZE);
|
||||
if (WARN_ONCE(!buf, "Can't allocate trace_seq buffer memory")) {
|
||||
s->state = TRACE_SEQ__MEM_ALLOC_FAILED;
|
||||
return;
|
||||
}
|
||||
|
||||
s->buffer = buf;
|
||||
s->buffer_size += TRACE_SEQ_BUF_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* trace_seq_printf - sequence printing of trace information
|
||||
* @s: trace sequence descriptor
|
||||
* @fmt: printf format string
|
||||
*
|
||||
* It returns 0 if the trace oversizes the buffer's free
|
||||
* space, the number of characters printed, or a negative
|
||||
* value in case of an error.
|
||||
*
|
||||
* The tracer may use either sequence operations or its own
|
||||
* copy to user routines. To simplify formating of a trace
|
||||
* trace_seq_printf is used to store strings into a special
|
||||
* buffer (@s). Then the output may be either used by
|
||||
* the sequencer or pulled into another buffer.
|
||||
*/
|
||||
int
|
||||
trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int len;
|
||||
int ret;
|
||||
|
||||
try_again:
|
||||
TRACE_SEQ_CHECK_RET0(s);
|
||||
|
||||
len = (s->buffer_size - 1) - s->len;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = vsnprintf(s->buffer + s->len, len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (ret >= len) {
|
||||
expand_buffer(s);
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
if (ret > 0)
|
||||
s->len += ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* trace_seq_vprintf - sequence printing of trace information
|
||||
* @s: trace sequence descriptor
|
||||
* @fmt: printf format string
|
||||
*
|
||||
* It returns 0 if the trace oversizes the buffer's free
|
||||
* space, the number of characters printed, or a negative
|
||||
* value in case of an error.
|
||||
* *
|
||||
* The tracer may use either sequence operations or its own
|
||||
* copy to user routines. To simplify formating of a trace
|
||||
* trace_seq_printf is used to store strings into a special
|
||||
* buffer (@s). Then the output may be either used by
|
||||
* the sequencer or pulled into another buffer.
|
||||
*/
|
||||
int
|
||||
trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
|
||||
{
|
||||
int len;
|
||||
int ret;
|
||||
|
||||
try_again:
|
||||
TRACE_SEQ_CHECK_RET0(s);
|
||||
|
||||
len = (s->buffer_size - 1) - s->len;
|
||||
|
||||
ret = vsnprintf(s->buffer + s->len, len, fmt, args);
|
||||
|
||||
if (ret >= len) {
|
||||
expand_buffer(s);
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
if (ret > 0)
|
||||
s->len += ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* trace_seq_puts - trace sequence printing of simple string
|
||||
* @s: trace sequence descriptor
|
||||
* @str: simple string to record
|
||||
*
|
||||
* The tracer may use either the sequence operations or its own
|
||||
* copy to user routines. This function records a simple string
|
||||
* into a special buffer (@s) for later retrieval by a sequencer
|
||||
* or other mechanism.
|
||||
*/
|
||||
int trace_seq_puts(struct trace_seq *s, const char *str)
|
||||
{
|
||||
int len;
|
||||
|
||||
TRACE_SEQ_CHECK_RET0(s);
|
||||
|
||||
len = strlen(str);
|
||||
|
||||
while (len > ((s->buffer_size - 1) - s->len))
|
||||
expand_buffer(s);
|
||||
|
||||
TRACE_SEQ_CHECK_RET0(s);
|
||||
|
||||
memcpy(s->buffer + s->len, str, len);
|
||||
s->len += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int trace_seq_putc(struct trace_seq *s, unsigned char c)
|
||||
{
|
||||
TRACE_SEQ_CHECK_RET0(s);
|
||||
|
||||
while (s->len >= (s->buffer_size - 1))
|
||||
expand_buffer(s);
|
||||
|
||||
TRACE_SEQ_CHECK_RET0(s);
|
||||
|
||||
s->buffer[s->len++] = c;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void trace_seq_terminate(struct trace_seq *s)
|
||||
{
|
||||
TRACE_SEQ_CHECK_RET(s);
|
||||
|
||||
/* There's always one character left on the buffer */
|
||||
s->buffer[s->len] = 0;
|
||||
}
|
||||
|
||||
int trace_seq_do_fprintf(struct trace_seq *s, FILE *fp)
|
||||
{
|
||||
TRACE_SEQ_CHECK(s);
|
||||
|
||||
switch (s->state) {
|
||||
case TRACE_SEQ__GOOD:
|
||||
return fprintf(fp, "%.*s", s->len, s->buffer);
|
||||
case TRACE_SEQ__BUFFER_POISONED:
|
||||
fprintf(fp, "%s\n", "Usage of trace_seq after it was destroyed");
|
||||
break;
|
||||
case TRACE_SEQ__MEM_ALLOC_FAILED:
|
||||
fprintf(fp, "%s\n", "Can't allocate trace_seq buffer memory");
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int trace_seq_do_printf(struct trace_seq *s)
|
||||
{
|
||||
return trace_seq_do_fprintf(s, stdout);
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TRACE_SEQ_H
|
||||
#define _TRACE_SEQ_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* ----------------------- trace_seq ----------------------- */
|
||||
|
||||
#ifndef TRACE_SEQ_BUF_SIZE
|
||||
#define TRACE_SEQ_BUF_SIZE 4096
|
||||
#endif
|
||||
|
||||
enum trace_seq_fail {
|
||||
TRACE_SEQ__GOOD,
|
||||
TRACE_SEQ__BUFFER_POISONED,
|
||||
TRACE_SEQ__MEM_ALLOC_FAILED,
|
||||
};
|
||||
|
||||
/*
|
||||
* Trace sequences are used to allow a function to call several other functions
|
||||
* to create a string of data to use (up to a max of PAGE_SIZE).
|
||||
*/
|
||||
|
||||
struct trace_seq {
|
||||
char *buffer;
|
||||
unsigned int buffer_size;
|
||||
unsigned int len;
|
||||
unsigned int readpos;
|
||||
enum trace_seq_fail state;
|
||||
};
|
||||
|
||||
void trace_seq_init(struct trace_seq *s);
|
||||
void trace_seq_reset(struct trace_seq *s);
|
||||
void trace_seq_destroy(struct trace_seq *s);
|
||||
|
||||
extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 2, 3)));
|
||||
extern int trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
|
||||
__attribute__ ((format (printf, 2, 0)));
|
||||
|
||||
extern int trace_seq_puts(struct trace_seq *s, const char *str);
|
||||
extern int trace_seq_putc(struct trace_seq *s, unsigned char c);
|
||||
|
||||
extern void trace_seq_terminate(struct trace_seq *s);
|
||||
|
||||
extern int trace_seq_do_fprintf(struct trace_seq *s, FILE *fp);
|
||||
extern int trace_seq_do_printf(struct trace_seq *s);
|
||||
|
||||
#endif /* _TRACE_SEQ_H */
|
@ -3,7 +3,6 @@ tools/arch
|
||||
tools/scripts
|
||||
tools/build
|
||||
tools/include
|
||||
tools/lib/traceevent
|
||||
tools/lib/api
|
||||
tools/lib/bpf
|
||||
tools/lib/subcmd
|
||||
|
Loading…
x
Reference in New Issue
Block a user