mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-04 17:44:14 +08:00
perf tools changes for v6.2: 1st batch
Libraries: - Drop the old copy of libtraceevent in tools/lib/traceevent/ now that all major distros ship it from its external repository. This is now just another feature detection, emitting a warning when the libtraceevent-dev[el] package isn't installed, disabling the build of perf features and tools that strictly require parsing things from tracefs while keeping the core functionality present and working with a subset of the events, the most used ones like CPU cycles, hardware cache and also vendor events, etc. This was tested with lots of containers for Fedora, Debian, OpenSUSE, Alpine Linux, Ubuntu, with cross builds, etc. Build: - Update to C standard to gnu11, like was done for the kernel. - Install the tools/lib/ libraries locally instead of having headers searched directly from the source code directories, to help the cases where we can build either from in-kernel source libraries or from the same library shipped as a distro package, as is the case with libbpf and was the case with libtraceevent. perf stat: - Do not delay the workload with --delay, the delay is just for starting to count the events, to skip noise at workload startup. - When we have events for each cgroup, the metric should be printed for each cgroup separately. $ perf stat -a --for-each-cgroup system.slice,user.slice --metric-only sleep 1 Performance counter stats for 'system wide': GHz insn per cycle branch-misses of all branches system.slice 3.792 0.61 3.24% user.slice 3.661 2.32 0.37% - Fix printing field separator in CSV metrics output. - Fix --metric-only --json output. - Fix summary output in CSV with --metric-only. - Update event group check for support of uncore event. perf test: - Stop requiring a C toolchain in shell tests, instead add a workload option that has all the previously C snippets built as part of 'perf test -w' that then get used in the 'perf test' shell scripts. - Add event group test for events in multiple PMUs - The "kernel lock contention analysis" test should not print warnings in quiet mode. - Add attr tests for ARM64's new VG register. - Fix record test on KVM guests, as using precise flag with the br_inst_retired.near_call event causes the test fail on KVM guests, even when the guests have PMU forwarding enabled and the event itself is supported, so just remove the precise flag from the event. - Add mechanism for skipping attr tests on specific kernel versions where it is known that these checks will fail. - Skip watchpoint tests if no watchpoints available. - Add more Intel PT 'perf test' entries: hybrid CPUs, split the packet decoder into a suite of subtests. perf script: - Introduce task analyzer python script, where one first records some events: Recording can be done in two ways: $ perf script record tasks-analyzer -- sleep 10 $ perf record -e sched:sched_switch -a -- sleep 10 The script can parse any perf.data files, as long as it has sched:sched_switch events, other events will be ignored. The most simple report use case is to just call the script without arguments. Runtime is the time the task was running on the CPU, Time Out-In is the time between the process being scheduled *out* and scheduled back *in*. So the last time span between two executions: $ perf script report tasks-analyzer Switched-In Switched-Out CPU PID TID Comm Runtime Time Out-In 15576.658891407 15576.659156086 4 2412 2428 gdbus 265 1949 15576.659111320 15576.659455410 0 2412 2412 gnome-shell 344 2267 15576.659491326 15576.659506173 2 74 74 kworker/2:1 15 13145 15576.659506173 15576.659825748 2 2858 2858 gnome-terminal- 320 63263 15576.659871270 15576.659902872 6 20932 20932 kworker/u16:0 32 2314582 15576.659909951 15576.659945501 3 27264 27264 sh 36 -1 15576.659853285 15576.659971052 7 27265 27265 perf 118 5050741 [...] perf lock: - Allow concurrent record and report to support live monitoring of kernel lock contention without BPF: # perf lock record -a -o- sleep 1 | perf lock contention -i- contended total wait max wait avg wait type caller 2 10.27 us 6.17 us 5.13 us spinlock load_balance+0xc03 1 5.29 us 5.29 us 5.29 us rwlock:W ep_scan_ready_list+0x54 1 4.12 us 4.12 us 4.12 us spinlock smpboot_thread_fn+0x116 1 3.28 us 3.28 us 3.28 us mutex pipe_read+0x50 - Implement -t/--threads option when using BPF: $ sudo ./perf lock contention -abt -E 5 sleep 1 contended total wait max wait avg wait pid comm 1 740.66 ms 740.66 ms 740.66 ms 1950 nv_queue 3 305.50 ms 298.19 ms 101.83 ms 1884 nvidia-modeset/ 1 25.14 us 25.14 us 25.14 us 2725038 EventManager_De 12 23.09 us 9.30 us 1.92 us 0 swapper 1 20.18 us 20.18 us 20.18 us 2725033 EventManager_De - Add -l/--lock-addr to aggregate per-lock-instance contention: $ sudo ./perf lock contention -abl sleep 1 contended total wait max wait avg wait address symbol 1 36.28 us 36.28 us 36.28 us ffff92615d6448b8 9 10.91 us 1.84 us 1.21 us ffffffffbaed50c0 rcu_state 1 10.49 us 10.49 us 10.49 us ffff9262ac4f0c80 8 4.68 us 1.67 us 585 ns ffffffffbae07a40 jiffies_lock 3 3.03 us 1.45 us 1.01 us ffff9262277861e0 1 924 ns 924 ns 924 ns ffff926095ba9d20 1 436 ns 436 ns 436 ns ffff9260bfda4f60 perf record: - Add remaining branch filters: "no_cycles", "no_flags" & "hw_index", to be used with hardware such as Intel's LBR that allows things like stitching stacks of two samples to overcome the limits of the number of LBR registers. Symbol resolution: - Handle .debug files created with 'objcopy --only-keep-debug', where program headers are zeroed and thus can't be used for adjustments, use the info in the runtime_ss (runtime ELF) instead. perf trace: - Add BPF based augmenter for the 'perf_event_open's 'struct perf_event_attr' argument. - Add BPF based augmenter for the 'clock_gettime's 'struct timespec' argument. - In both cases the syscall tracepoint has just the pointer value, we need to hook a BPF program to collect the pointer contents, and then, in userspace, pretty print it in 'perf trace'. perf list: - Introduce JSON output of events. - Streamline how the expression specifying what events should be shown is handled, fixing several corner cases, such as the metric filter that is specified as a glob but was using strstr(). perf probe: - Fix to avoid crashing if DW_AT_decl_file is NULL, coping with clang generating DWARF5 like that. - Use dwarf_attr_integrate() as generic DWARF attr accessor as it supersedes dwarf_attr(), supporting abstact origin DIEs. perf inject: - Set PERF_RECORD_MISC_BUILD_ID_SIZE in the PERF_RECORD_HEADER_BUILD_ID so that perf.data readers can get the real build-id size and avoid trailing zeros. perf data: - Add tracepoint fields when converting a perf.data file to JSON. arm64: - Fix mksyscalltbl, don't lose syscalls due to sort -nu. - Add Arm Neoverse V2 PMU events. riscv: - Add riscv sbi firmware std event files. - Add Sifive U74 vendor events (JSON) file. - Add some more events and metrics for Alderlake/Alderlake-N. Documentation: - Add data documentation for the PMU structs in the C source code. Miscellaneous: - Periodic sanitization of headers, adding missing includes, removing needless ones, creating new ones, etc. - Use sig_atomic_t for signal handlers to avoid undefined behaviour in all perf tools. - Fixes for libbpf 1.0+ compatibility (maps, etc) on 'perf trace' BPF examples. - Remove some old perf bpf examples, leave the best ones that demonstrate how to associate BPF functions to points in the kernel. - Make quiet mode consistent between tools. - Use dedicated non-atomic clear/set bit helpers. - Use "grep -E" instead of "egrep" as recommended by warning emitted by GNU grep since at least version 3.8. - Complete list of supported subcommands in the 'perf daemon' help message. - Update John Garry's email address for arm64 perf tooling on the MAINTAINERS file, he moved from Huawei to Oracle. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQR2GiIUctdOfX2qHhGyPKLppCJ+JwUCY5yARAAKCRCyPKLppCJ+ J7bdAQCO4Y4gXKWv+AQc77aptQaCRmWy6T9ynsdv5gOV43NpCwD/TWZz8zcBqLSS fxYSgf2kOQ3Z9soE4/udsL5sDhFbsgA= =hLlg -----END PGP SIGNATURE----- Merge tag 'perf-tools-for-v6.2-1-2022-12-16' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux Pull perf tools updates from Arnaldo Carvalho de Melo: "Libraries: - Drop the old copy of libtraceevent in tools/lib/traceevent/ now that all major distros ship it from its external repository. This is now just another feature detection, emitting a warning when the libtraceevent-dev[el] package isn't installed, disabling the build of perf features and tools that strictly require parsing things from tracefs while keeping the core functionality present and working with a subset of the events, the most used ones like CPU cycles, hardware cache and also vendor events, etc. This was tested with lots of containers for Fedora, Debian, OpenSUSE, Alpine Linux, Ubuntu, with cross builds, etc. Build: - Update to C standard to gnu11, like was done for the kernel. - Install the tools/lib/ libraries locally instead of having headers searched directly from the source code directories, to help the cases where we can build either from in-kernel source libraries or from the same library shipped as a distro package, as is the case with libbpf and was the case with libtraceevent. perf stat: - Do not delay the workload with --delay, the delay is just for starting to count the events, to skip noise at workload startup. - When we have events for each cgroup, the metric should be printed for each cgroup separately. $ perf stat -a --for-each-cgroup system.slice,user.slice --metric-only sleep 1 Performance counter stats for 'system wide': GHz insn per cycle branch-misses of all branches system.slice 3.792 0.61 3.24% user.slice 3.661 2.32 0.37% - Fix printing field separator in CSV metrics output. - Fix --metric-only --json output. - Fix summary output in CSV with --metric-only. - Update event group check for support of uncore event. perf test: - Stop requiring a C toolchain in shell tests, instead add a workload option that has all the previously C snippets built as part of 'perf test -w' that then get used in the 'perf test' shell scripts. - Add event group test for events in multiple PMUs - The "kernel lock contention analysis" test should not print warnings in quiet mode. - Add attr tests for ARM64's new VG register. - Fix record test on KVM guests, as using precise flag with the br_inst_retired.near_call event causes the test fail on KVM guests, even when the guests have PMU forwarding enabled and the event itself is supported, so just remove the precise flag from the event. - Add mechanism for skipping attr tests on specific kernel versions where it is known that these checks will fail. - Skip watchpoint tests if no watchpoints available. - Add more Intel PT 'perf test' entries: hybrid CPUs, split the packet decoder into a suite of subtests. perf script: - Introduce task analyzer python script, where one first records some events: Recording can be done in two ways: $ perf script record tasks-analyzer -- sleep 10 $ perf record -e sched:sched_switch -a -- sleep 10 The script can parse any perf.data files, as long as it has sched:sched_switch events, other events will be ignored. The most simple report use case is to just call the script without arguments. Runtime is the time the task was running on the CPU, Time Out-In is the time between the process being scheduled *out* and scheduled back *in*. So the last time span between two executions: $ perf script report tasks-analyzer Switched-In Switched-Out CPU PID TID Comm Runtime Time Out-In 15576.658891407 15576.659156086 4 2412 2428 gdbus 265 1949 15576.659111320 15576.659455410 0 2412 2412 gnome-shell 344 2267 15576.659491326 15576.659506173 2 74 74 kworker/2:1 15 13145 15576.659506173 15576.659825748 2 2858 2858 gnome-terminal- 320 63263 15576.659871270 15576.659902872 6 20932 20932 kworker/u16:0 32 2314582 15576.659909951 15576.659945501 3 27264 27264 sh 36 -1 15576.659853285 15576.659971052 7 27265 27265 perf 118 5050741 [...] perf lock: - Allow concurrent record and report to support live monitoring of kernel lock contention without BPF: # perf lock record -a -o- sleep 1 | perf lock contention -i- contended total wait max wait avg wait type caller 2 10.27 us 6.17 us 5.13 us spinlock load_balance+0xc03 1 5.29 us 5.29 us 5.29 us rwlock:W ep_scan_ready_list+0x54 1 4.12 us 4.12 us 4.12 us spinlock smpboot_thread_fn+0x116 1 3.28 us 3.28 us 3.28 us mutex pipe_read+0x50 - Implement -t/--threads option when using BPF: $ sudo ./perf lock contention -abt -E 5 sleep 1 contended total wait max wait avg wait pid comm 1 740.66 ms 740.66 ms 740.66 ms 1950 nv_queue 3 305.50 ms 298.19 ms 101.83 ms 1884 nvidia-modeset/ 1 25.14 us 25.14 us 25.14 us 2725038 EventManager_De 12 23.09 us 9.30 us 1.92 us 0 swapper 1 20.18 us 20.18 us 20.18 us 2725033 EventManager_De - Add -l/--lock-addr to aggregate per-lock-instance contention: $ sudo ./perf lock contention -abl sleep 1 contended total wait max wait avg wait address symbol 1 36.28 us 36.28 us 36.28 us ffff92615d6448b8 9 10.91 us 1.84 us 1.21 us ffffffffbaed50c0 rcu_state 1 10.49 us 10.49 us 10.49 us ffff9262ac4f0c80 8 4.68 us 1.67 us 585 ns ffffffffbae07a40 jiffies_lock 3 3.03 us 1.45 us 1.01 us ffff9262277861e0 1 924 ns 924 ns 924 ns ffff926095ba9d20 1 436 ns 436 ns 436 ns ffff9260bfda4f60 perf record: - Add remaining branch filters: "no_cycles", "no_flags" & "hw_index", to be used with hardware such as Intel's LBR that allows things like stitching stacks of two samples to overcome the limits of the number of LBR registers. Symbol resolution: - Handle .debug files created with 'objcopy --only-keep-debug', where program headers are zeroed and thus can't be used for adjustments, use the info in the runtime_ss (runtime ELF) instead. perf trace: - Add BPF based augmenter for the 'perf_event_open's 'struct perf_event_attr' argument. - Add BPF based augmenter for the 'clock_gettime's 'struct timespec' argument. - In both cases the syscall tracepoint has just the pointer value, we need to hook a BPF program to collect the pointer contents, and then, in userspace, pretty print it in 'perf trace'. perf list: - Introduce JSON output of events. - Streamline how the expression specifying what events should be shown is handled, fixing several corner cases, such as the metric filter that is specified as a glob but was using strstr(). perf probe: - Fix to avoid crashing if DW_AT_decl_file is NULL, coping with clang generating DWARF5 like that. - Use dwarf_attr_integrate() as generic DWARF attr accessor as it supersedes dwarf_attr(), supporting abstact origin DIEs. perf inject: - Set PERF_RECORD_MISC_BUILD_ID_SIZE in the PERF_RECORD_HEADER_BUILD_ID so that perf.data readers can get the real build-id size and avoid trailing zeroes. perf data: - Add tracepoint fields when converting a perf.data file to JSON. arm64: - Fix mksyscalltbl, don't lose syscalls due to sort -nu. - Add Arm Neoverse V2 PMU events. riscv: - Add riscv sbi firmware std event files. - Add Sifive U74 vendor events (JSON) file. - Add some more events and metrics for Alderlake/Alderlake-N. Documentation: - Add data documentation for the PMU structs in the C source code. Miscellaneous: - Periodic sanitization of headers, adding missing includes, removing needless ones, creating new ones, etc. - Use sig_atomic_t for signal handlers to avoid undefined behaviour in all perf tools. - Fixes for libbpf 1.0+ compatibility (maps, etc) on 'perf trace' BPF examples. - Remove some old perf bpf examples, leave the best ones that demonstrate how to associate BPF functions to points in the kernel. - Make quiet mode consistent between tools. - Use dedicated non-atomic clear/set bit helpers. - Use "grep -E" instead of "egrep" as recommended by warning emitted by GNU grep since at least version 3.8. - Complete list of supported subcommands in the 'perf daemon' help message. - Update John Garry's email address for arm64 perf tooling on the MAINTAINERS file, he moved from Huawei to Oracle" * tag 'perf-tools-for-v6.2-1-2022-12-16' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux: (239 commits) libperf: Fix install_pkgconfig target perf tools: Use "grep -E" instead of "egrep" perf stat: Do not delay the workload with --delay perf evlist: Remove group option. perf build: Fix python/perf.so library's name perf test arm64: Add attr tests for new VG register perf test: Add mechanism for skipping attr tests on kernel versions perf test: Add mechanism for skipping attr tests on auxiliary vector values perf test: Add ability to test exit code for attr tests perf test: add new task-analyzer tests perf script: task-analyzer add csv support perf script: Introduce task analyzer python script perf cs-etm: Print auxtrace info even if OpenCSD isn't linked perf cs-etm: Cleanup cs_etm__process_auxtrace_info() perf cs-etm: Tidy up auxtrace info header printing perf cs-etm: Remove unused stub methods perf cs-etm: Print unknown header version as an error perf test: Update perf lock contention test perf lock contention: Add -l/--lock-addr option perf lock contention: Implement -t/--threads option for BPF ...
This commit is contained in:
commit
aa4800e31c
@ -16431,7 +16431,7 @@ F: tools/lib/perf/
|
||||
F: tools/perf/
|
||||
|
||||
PERFORMANCE EVENTS TOOLING ARM64
|
||||
R: John Garry <john.garry@huawei.com>
|
||||
R: John Garry <john.g.garry@oracle.com>
|
||||
R: Will Deacon <will@kernel.org>
|
||||
R: James Clark <james.clark@arm.com>
|
||||
R: Mike Leach <mike.leach@linaro.org>
|
||||
|
@ -15,6 +15,16 @@ LD ?= $(CROSS_COMPILE)ld
|
||||
|
||||
MAKEFLAGS += --no-print-directory
|
||||
|
||||
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))'
|
||||
|
||||
LIBFILE = $(OUTPUT)libapi.a
|
||||
|
||||
CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
|
||||
@ -45,10 +55,23 @@ RM = rm -f
|
||||
|
||||
API_IN := $(OUTPUT)libapi-in.o
|
||||
|
||||
ifeq ($(LP64), 1)
|
||||
libdir_relative = lib64
|
||||
else
|
||||
libdir_relative = lib
|
||||
endif
|
||||
|
||||
prefix ?=
|
||||
libdir = $(prefix)/$(libdir_relative)
|
||||
|
||||
# Shell quotes
|
||||
libdir_SQ = $(subst ','\'',$(libdir))
|
||||
|
||||
all:
|
||||
|
||||
export srctree OUTPUT CC LD CFLAGS V
|
||||
include $(srctree)/tools/build/Makefile.include
|
||||
include $(srctree)/tools/scripts/Makefile.include
|
||||
|
||||
all: fixdep $(LIBFILE)
|
||||
|
||||
@ -58,6 +81,49 @@ $(API_IN): FORCE
|
||||
$(LIBFILE): $(API_IN)
|
||||
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(API_IN)
|
||||
|
||||
define do_install_mkdir
|
||||
if [ ! -d '$(DESTDIR_SQ)$1' ]; then \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$1'; \
|
||||
fi
|
||||
endef
|
||||
|
||||
define do_install
|
||||
if [ ! -d '$2' ]; then \
|
||||
$(INSTALL) -d -m 755 '$2'; \
|
||||
fi; \
|
||||
$(INSTALL) $1 $(if $3,-m $3,) '$2'
|
||||
endef
|
||||
|
||||
install_lib: $(LIBFILE)
|
||||
$(call QUIET_INSTALL, $(LIBFILE)) \
|
||||
$(call do_install_mkdir,$(libdir_SQ)); \
|
||||
cp -fpR $(LIBFILE) $(DESTDIR)$(libdir_SQ)
|
||||
|
||||
HDRS := cpu.h debug.h io.h
|
||||
FD_HDRS := fd/array.h
|
||||
FS_HDRS := fs/fs.h fs/tracing_path.h
|
||||
INSTALL_HDRS_PFX := $(DESTDIR)$(prefix)/include/api
|
||||
INSTALL_HDRS := $(addprefix $(INSTALL_HDRS_PFX)/, $(HDRS))
|
||||
INSTALL_FD_HDRS := $(addprefix $(INSTALL_HDRS_PFX)/, $(FD_HDRS))
|
||||
INSTALL_FS_HDRS := $(addprefix $(INSTALL_HDRS_PFX)/, $(FS_HDRS))
|
||||
|
||||
$(INSTALL_HDRS): $(INSTALL_HDRS_PFX)/%.h: %.h
|
||||
$(call QUIET_INSTALL, $@) \
|
||||
$(call do_install,$<,$(INSTALL_HDRS_PFX)/,644)
|
||||
|
||||
$(INSTALL_FD_HDRS): $(INSTALL_HDRS_PFX)/fd/%.h: fd/%.h
|
||||
$(call QUIET_INSTALL, $@) \
|
||||
$(call do_install,$<,$(INSTALL_HDRS_PFX)/fd/,644)
|
||||
|
||||
$(INSTALL_FS_HDRS): $(INSTALL_HDRS_PFX)/fs/%.h: fs/%.h
|
||||
$(call QUIET_INSTALL, $@) \
|
||||
$(call do_install,$<,$(INSTALL_HDRS_PFX)/fs/,644)
|
||||
|
||||
install_headers: $(INSTALL_HDRS) $(INSTALL_FD_HDRS) $(INSTALL_FS_HDRS)
|
||||
$(call QUIET_INSTALL, libapi_headers)
|
||||
|
||||
install: install_lib install_headers
|
||||
|
||||
clean:
|
||||
$(call QUIET_CLEAN, libapi) $(RM) $(LIBFILE); \
|
||||
find $(or $(OUTPUT),.) -name \*.o -or -name \*.o.cmd -or -name \*.o.d | xargs $(RM)
|
||||
|
@ -113,6 +113,22 @@ DIR *tracing_events__opendir(void)
|
||||
return dir;
|
||||
}
|
||||
|
||||
int tracing_events__scandir_alphasort(struct dirent ***namelist)
|
||||
{
|
||||
char *path = get_tracing_file("events");
|
||||
int ret;
|
||||
|
||||
if (!path) {
|
||||
*namelist = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = scandir(path, namelist, NULL, alphasort);
|
||||
put_events_file(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tracing_path__strerror_open_tp(int err, char *buf, size_t size,
|
||||
const char *sys, const char *name)
|
||||
{
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <dirent.h>
|
||||
|
||||
DIR *tracing_events__opendir(void);
|
||||
int tracing_events__scandir_alphasort(struct dirent ***namelist);
|
||||
|
||||
void tracing_path_set(const char *mountpoint);
|
||||
const char *tracing_path_mount(void);
|
||||
|
@ -255,6 +255,7 @@ $(INSTALL_GEN_HDRS): $(INSTALL_PFX)/%.h: $(OUTPUT)%.h
|
||||
$(call do_install,$<,$(prefix)/include/bpf,644)
|
||||
|
||||
install_headers: $(BPF_GENERATED) $(INSTALL_SRC_HDRS) $(INSTALL_GEN_HDRS)
|
||||
$(call QUIET_INSTALL, libbpf_headers)
|
||||
|
||||
install_pkgconfig: $(PC_FILE)
|
||||
$(call QUIET_INSTALL, $(PC_FILE)) \
|
||||
|
@ -176,10 +176,10 @@ define do_install_mkdir
|
||||
endef
|
||||
|
||||
define do_install
|
||||
if [ ! -d '$(DESTDIR_SQ)$2' ]; then \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \
|
||||
fi; \
|
||||
$(INSTALL) $1 $(if $3,-m $3,) '$(DESTDIR_SQ)$2'
|
||||
if [ ! -d '$2' ]; then \
|
||||
$(INSTALL) -d -m 755 '$2'; \
|
||||
fi; \
|
||||
$(INSTALL) $1 $(if $3,-m $3,) '$2'
|
||||
endef
|
||||
|
||||
install_lib: libs
|
||||
@ -187,19 +187,28 @@ install_lib: libs
|
||||
$(call do_install_mkdir,$(libdir_SQ)); \
|
||||
cp -fpR $(LIBPERF_ALL) $(DESTDIR)$(libdir_SQ)
|
||||
|
||||
install_headers:
|
||||
$(call QUIET_INSTALL, headers) \
|
||||
$(call do_install,include/perf/core.h,$(prefix)/include/perf,644); \
|
||||
$(call do_install,include/perf/cpumap.h,$(prefix)/include/perf,644); \
|
||||
$(call do_install,include/perf/threadmap.h,$(prefix)/include/perf,644); \
|
||||
$(call do_install,include/perf/evlist.h,$(prefix)/include/perf,644); \
|
||||
$(call do_install,include/perf/evsel.h,$(prefix)/include/perf,644); \
|
||||
$(call do_install,include/perf/event.h,$(prefix)/include/perf,644); \
|
||||
$(call do_install,include/perf/mmap.h,$(prefix)/include/perf,644);
|
||||
HDRS := bpf_perf.h core.h cpumap.h threadmap.h evlist.h evsel.h event.h mmap.h
|
||||
INTERNAL_HDRS := cpumap.h evlist.h evsel.h lib.h mmap.h threadmap.h xyarray.h
|
||||
|
||||
INSTALL_HDRS_PFX := $(DESTDIR)$(prefix)/include/perf
|
||||
INSTALL_HDRS := $(addprefix $(INSTALL_HDRS_PFX)/, $(HDRS))
|
||||
INSTALL_INTERNAL_HDRS_PFX := $(DESTDIR)$(prefix)/include/internal
|
||||
INSTALL_INTERNAL_HDRS := $(addprefix $(INSTALL_INTERNAL_HDRS_PFX)/, $(INTERNAL_HDRS))
|
||||
|
||||
$(INSTALL_HDRS): $(INSTALL_HDRS_PFX)/%.h: include/perf/%.h
|
||||
$(call QUIET_INSTALL, $@) \
|
||||
$(call do_install,$<,$(INSTALL_HDRS_PFX)/,644)
|
||||
|
||||
$(INSTALL_INTERNAL_HDRS): $(INSTALL_INTERNAL_HDRS_PFX)/%.h: include/internal/%.h
|
||||
$(call QUIET_INSTALL, $@) \
|
||||
$(call do_install,$<,$(INSTALL_INTERNAL_HDRS_PFX)/,644)
|
||||
|
||||
install_headers: $(INSTALL_HDRS) $(INSTALL_INTERNAL_HDRS)
|
||||
$(call QUIET_INSTALL, libperf_headers)
|
||||
|
||||
install_pkgconfig: $(LIBPERF_PC)
|
||||
$(call QUIET_INSTALL, $(LIBPERF_PC)) \
|
||||
$(call do_install,$(LIBPERF_PC),$(libdir_SQ)/pkgconfig,644)
|
||||
$(call do_install,$(LIBPERF_PC),$(DESTDIR_SQ)$(libdir_SQ)/pkgconfig,644)
|
||||
|
||||
install_doc:
|
||||
$(Q)$(MAKE) -C Documentation install-man install-html install-examples
|
||||
|
@ -3,7 +3,6 @@
|
||||
#define __LIBPERF_CPUMAP_H
|
||||
|
||||
#include <perf/core.h>
|
||||
#include <perf/cpumap.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
@ -12,6 +11,8 @@ struct perf_cpu {
|
||||
int cpu;
|
||||
};
|
||||
|
||||
struct perf_cpu_map;
|
||||
|
||||
LIBPERF_API struct perf_cpu_map *perf_cpu_map__dummy_new(void);
|
||||
LIBPERF_API struct perf_cpu_map *perf_cpu_map__default_new(void);
|
||||
LIBPERF_API struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list);
|
||||
|
@ -17,6 +17,15 @@ RM = rm -f
|
||||
|
||||
MAKEFLAGS += --no-print-directory
|
||||
|
||||
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))'
|
||||
|
||||
LIBFILE = $(OUTPUT)libsubcmd.a
|
||||
|
||||
CFLAGS := -ggdb3 -Wall -Wextra -std=gnu99 -fPIC
|
||||
@ -48,6 +57,18 @@ CFLAGS += $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
|
||||
|
||||
SUBCMD_IN := $(OUTPUT)libsubcmd-in.o
|
||||
|
||||
ifeq ($(LP64), 1)
|
||||
libdir_relative = lib64
|
||||
else
|
||||
libdir_relative = lib
|
||||
endif
|
||||
|
||||
prefix ?=
|
||||
libdir = $(prefix)/$(libdir_relative)
|
||||
|
||||
# Shell quotes
|
||||
libdir_SQ = $(subst ','\'',$(libdir))
|
||||
|
||||
all:
|
||||
|
||||
export srctree OUTPUT CC LD CFLAGS V
|
||||
@ -61,6 +82,37 @@ $(SUBCMD_IN): FORCE
|
||||
$(LIBFILE): $(SUBCMD_IN)
|
||||
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(SUBCMD_IN)
|
||||
|
||||
define do_install_mkdir
|
||||
if [ ! -d '$(DESTDIR_SQ)$1' ]; then \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$1'; \
|
||||
fi
|
||||
endef
|
||||
|
||||
define do_install
|
||||
if [ ! -d '$2' ]; then \
|
||||
$(INSTALL) -d -m 755 '$2'; \
|
||||
fi; \
|
||||
$(INSTALL) $1 $(if $3,-m $3,) '$2'
|
||||
endef
|
||||
|
||||
install_lib: $(LIBFILE)
|
||||
$(call QUIET_INSTALL, $(LIBFILE)) \
|
||||
$(call do_install_mkdir,$(libdir_SQ)); \
|
||||
cp -fpR $(LIBFILE) $(DESTDIR)$(libdir_SQ)
|
||||
|
||||
HDRS := exec-cmd.h help.h pager.h parse-options.h run-command.h
|
||||
INSTALL_HDRS_PFX := $(DESTDIR)$(prefix)/include/subcmd
|
||||
INSTALL_HDRS := $(addprefix $(INSTALL_HDRS_PFX)/, $(HDRS))
|
||||
|
||||
$(INSTALL_HDRS): $(INSTALL_HDRS_PFX)/%.h: %.h
|
||||
$(call QUIET_INSTALL, $@) \
|
||||
$(call do_install,$<,$(INSTALL_HDRS_PFX)/,644)
|
||||
|
||||
install_headers: $(INSTALL_HDRS)
|
||||
$(call QUIET_INSTALL, libsubcmd_headers)
|
||||
|
||||
install: install_lib install_headers
|
||||
|
||||
clean:
|
||||
$(call QUIET_CLEAN, libsubcmd) $(RM) $(LIBFILE); \
|
||||
find $(or $(OUTPUT),.) -name \*.o -or -name \*.o.cmd -or -name \*.o.d | xargs $(RM)
|
||||
|
1
tools/lib/symbol/Build
Normal file
1
tools/lib/symbol/Build
Normal file
@ -0,0 +1 @@
|
||||
libsymbol-y += kallsyms.o
|
122
tools/lib/symbol/Makefile
Normal file
122
tools/lib/symbol/Makefile
Normal file
@ -0,0 +1,122 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
include ../../scripts/Makefile.include
|
||||
include ../../scripts/utilities.mak # QUIET_CLEAN
|
||||
|
||||
ifeq ($(srctree),)
|
||||
srctree := $(patsubst %/,%,$(dir $(CURDIR)))
|
||||
srctree := $(patsubst %/,%,$(dir $(srctree)))
|
||||
srctree := $(patsubst %/,%,$(dir $(srctree)))
|
||||
#$(info Determined 'srctree' to be $(srctree))
|
||||
endif
|
||||
|
||||
CC ?= $(CROSS_COMPILE)gcc
|
||||
AR ?= $(CROSS_COMPILE)ar
|
||||
LD ?= $(CROSS_COMPILE)ld
|
||||
|
||||
MAKEFLAGS += --no-print-directory
|
||||
|
||||
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))'
|
||||
|
||||
LIBFILE = $(OUTPUT)libsymbol.a
|
||||
|
||||
CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
|
||||
CFLAGS += -ggdb3 -Wall -Wextra -std=gnu11 -U_FORTIFY_SOURCE -fPIC
|
||||
|
||||
ifeq ($(DEBUG),0)
|
||||
ifeq ($(CC_NO_CLANG), 0)
|
||||
CFLAGS += -O3
|
||||
else
|
||||
CFLAGS += -O6
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG),0)
|
||||
CFLAGS += -D_FORTIFY_SOURCE
|
||||
endif
|
||||
|
||||
# Treat warnings as errors unless directed not to
|
||||
ifneq ($(WERROR),0)
|
||||
CFLAGS += -Werror
|
||||
endif
|
||||
|
||||
CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
|
||||
|
||||
CFLAGS += -I$(srctree)/tools/lib
|
||||
CFLAGS += -I$(srctree)/tools/include
|
||||
|
||||
RM = rm -f
|
||||
|
||||
SYMBOL_IN := $(OUTPUT)libsymbol-in.o
|
||||
|
||||
ifeq ($(LP64), 1)
|
||||
libdir_relative = lib64
|
||||
else
|
||||
libdir_relative = lib
|
||||
endif
|
||||
|
||||
prefix ?=
|
||||
libdir = $(prefix)/$(libdir_relative)
|
||||
|
||||
# Shell quotes
|
||||
libdir_SQ = $(subst ','\'',$(libdir))
|
||||
|
||||
all:
|
||||
|
||||
export srctree OUTPUT CC LD CFLAGS V
|
||||
include $(srctree)/tools/build/Makefile.include
|
||||
include $(srctree)/tools/scripts/Makefile.include
|
||||
|
||||
all: fixdep $(LIBFILE)
|
||||
|
||||
$(SYMBOL_IN): FORCE
|
||||
@$(MAKE) $(build)=libsymbol
|
||||
|
||||
$(LIBFILE): $(SYMBOL_IN)
|
||||
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(SYMBOL_IN)
|
||||
|
||||
define do_install_mkdir
|
||||
if [ ! -d '$(DESTDIR_SQ)$1' ]; then \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$1'; \
|
||||
fi
|
||||
endef
|
||||
|
||||
define do_install
|
||||
if [ ! -d '$2' ]; then \
|
||||
$(INSTALL) -d -m 755 '$2'; \
|
||||
fi; \
|
||||
$(INSTALL) $1 $(if $3,-m $3,) '$2'
|
||||
endef
|
||||
|
||||
install_lib: $(LIBFILE)
|
||||
$(call QUIET_INSTALL, $(LIBFILE)) \
|
||||
$(call do_install_mkdir,$(libdir_SQ)); \
|
||||
cp -fpR $(LIBFILE) $(DESTDIR)$(libdir_SQ)
|
||||
|
||||
HDRS := kallsyms.h
|
||||
INSTALL_HDRS_PFX := $(DESTDIR)$(prefix)/include/symbol
|
||||
INSTALL_HDRS := $(addprefix $(INSTALL_HDRS_PFX)/, $(HDRS))
|
||||
|
||||
$(INSTALL_HDRS): $(INSTALL_HDRS_PFX)/%.h: %.h
|
||||
$(call QUIET_INSTALL, $@) \
|
||||
$(call do_install,$<,$(INSTALL_HDRS_PFX)/,644)
|
||||
|
||||
install_headers: $(INSTALL_HDRS)
|
||||
$(call QUIET_INSTALL, libsymbol_headers)
|
||||
|
||||
install: install_lib install_headers
|
||||
|
||||
clean:
|
||||
$(call QUIET_CLEAN, libsymbol) $(RM) $(LIBFILE); \
|
||||
find $(or $(OUTPUT),.) -name \*.o -or -name \*.o.cmd -or -name \*.o.d | xargs $(RM)
|
||||
|
||||
FORCE:
|
||||
|
||||
.PHONY: clean FORCE
|
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, 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 */
|
7
tools/perf/.gitignore
vendored
7
tools/perf/.gitignore
vendored
@ -39,7 +39,12 @@ trace/beauty/generated/
|
||||
pmu-events/pmu-events.c
|
||||
pmu-events/jevents
|
||||
feature/
|
||||
libapi/
|
||||
libbpf/
|
||||
libperf/
|
||||
libsubcmd/
|
||||
libsymbol/
|
||||
libtraceevent/
|
||||
libtraceevent_plugins/
|
||||
fixdep
|
||||
libtraceevent-dynamic-list
|
||||
Documentation/doc.dep
|
||||
|
@ -5,7 +5,6 @@ perf-y += builtin-diff.o
|
||||
perf-y += builtin-evlist.o
|
||||
perf-y += builtin-ftrace.o
|
||||
perf-y += builtin-help.o
|
||||
perf-y += builtin-sched.o
|
||||
perf-y += builtin-buildid-list.o
|
||||
perf-y += builtin-buildid-cache.o
|
||||
perf-y += builtin-kallsyms.o
|
||||
@ -13,11 +12,8 @@ perf-y += builtin-list.o
|
||||
perf-y += builtin-record.o
|
||||
perf-y += builtin-report.o
|
||||
perf-y += builtin-stat.o
|
||||
perf-y += builtin-timechart.o
|
||||
perf-y += builtin-top.o
|
||||
perf-y += builtin-script.o
|
||||
perf-y += builtin-kmem.o
|
||||
perf-y += builtin-lock.o
|
||||
perf-y += builtin-kvm.o
|
||||
perf-y += builtin-inject.o
|
||||
perf-y += builtin-mem.o
|
||||
@ -25,9 +21,18 @@ perf-y += builtin-data.o
|
||||
perf-y += builtin-version.o
|
||||
perf-y += builtin-c2c.o
|
||||
perf-y += builtin-daemon.o
|
||||
perf-y += builtin-kwork.o
|
||||
|
||||
perf-$(CONFIG_TRACE) += builtin-trace.o
|
||||
perf-$(CONFIG_LIBTRACEEVENT) += builtin-kmem.o
|
||||
perf-$(CONFIG_LIBTRACEEVENT) += builtin-kwork.o
|
||||
perf-$(CONFIG_LIBTRACEEVENT) += builtin-lock.o
|
||||
perf-$(CONFIG_LIBTRACEEVENT) += builtin-sched.o
|
||||
perf-$(CONFIG_LIBTRACEEVENT) += builtin-timechart.o
|
||||
|
||||
ifeq ($(CONFIG_LIBTRACEEVENT),y)
|
||||
perf-$(CONFIG_TRACE) += builtin-trace.o
|
||||
perf-$(CONFIG_TRACE) += trace/beauty/
|
||||
endif
|
||||
|
||||
perf-$(CONFIG_LIBELF) += builtin-probe.o
|
||||
|
||||
perf-y += bench/
|
||||
@ -51,7 +56,6 @@ CFLAGS_builtin-report.o += -DDOCDIR="BUILD_STR($(srcdir_SQ)/Documentation)"
|
||||
perf-y += util/
|
||||
perf-y += arch/
|
||||
perf-y += ui/
|
||||
perf-y += scripts/
|
||||
perf-$(CONFIG_TRACE) += trace/beauty/
|
||||
perf-$(CONFIG_LIBTRACEEVENT) += scripts/
|
||||
|
||||
gtk-y += ui/gtk/
|
||||
|
@ -41,7 +41,7 @@ OPTIONS
|
||||
|
||||
-q::
|
||||
--quiet::
|
||||
Do not show any message. (Suppress -v)
|
||||
Do not show any warnings or messages. (Suppress -v)
|
||||
|
||||
-n::
|
||||
--show-nr-samples::
|
||||
|
@ -75,7 +75,7 @@ OPTIONS
|
||||
|
||||
-q::
|
||||
--quiet::
|
||||
Do not show any message. (Suppress -v)
|
||||
Do not show any warnings or messages. (Suppress -v)
|
||||
|
||||
-f::
|
||||
--force::
|
||||
|
@ -189,8 +189,16 @@ There is also script intel-pt-events.py which provides an example of how to
|
||||
unpack the raw data for power events and PTWRITE. The script also displays
|
||||
branches, and supports 2 additional modes selected by option:
|
||||
|
||||
--insn-trace - instruction trace
|
||||
--src-trace - source trace
|
||||
- --insn-trace - instruction trace
|
||||
- --src-trace - source trace
|
||||
|
||||
The intel-pt-events.py script also has options:
|
||||
|
||||
- --all-switch-events - display all switch events, not only the last consecutive.
|
||||
- --interleave [<n>] - interleave sample output for the same timestamp so that
|
||||
no more than n samples for a CPU are displayed in a row. 'n' defaults to 4.
|
||||
Note this only affects the order of output, and only when the timestamp is the
|
||||
same.
|
||||
|
||||
As mentioned above, it is easy to capture too much data. One way to limit the
|
||||
data captured is to use 'snapshot' mode which is explained further below.
|
||||
|
@ -39,9 +39,13 @@ any extra expressions computed by perf stat.
|
||||
--deprecated::
|
||||
Print deprecated events. By default the deprecated events are hidden.
|
||||
|
||||
--cputype::
|
||||
Print events applying cpu with this type for hybrid platform
|
||||
(e.g. --cputype core or --cputype atom)
|
||||
--unit::
|
||||
Print PMU events and metrics limited to the specific PMU name.
|
||||
(e.g. --unit cpu, --unit msr, --unit cpu_core, --unit cpu_atom)
|
||||
|
||||
-j::
|
||||
--json::
|
||||
Output in JSON format.
|
||||
|
||||
[[EVENT_MODIFIERS]]
|
||||
EVENT MODIFIERS
|
||||
|
@ -42,7 +42,7 @@ COMMON OPTIONS
|
||||
|
||||
-q::
|
||||
--quiet::
|
||||
Do not show any message. (Suppress -v)
|
||||
Do not show any warnings or messages. (Suppress -v)
|
||||
|
||||
-D::
|
||||
--dump-raw-trace::
|
||||
@ -168,6 +168,10 @@ CONTENTION OPTIONS
|
||||
--entries=<value>::
|
||||
Display this many entries.
|
||||
|
||||
-l::
|
||||
--lock-addr::
|
||||
Show lock contention stat by address
|
||||
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
@ -57,7 +57,7 @@ OPTIONS
|
||||
|
||||
-q::
|
||||
--quiet::
|
||||
Be quiet (do not show any messages including errors).
|
||||
Do not show any warnings or messages.
|
||||
Can not use with -v.
|
||||
|
||||
-a::
|
||||
|
@ -238,10 +238,6 @@ OPTIONS
|
||||
Also, by adding a comma, the number of mmap pages for AUX
|
||||
area tracing can be specified.
|
||||
|
||||
--group::
|
||||
Put all events in a single event group. This precedes the --event
|
||||
option and remains only for backward compatibility. See --event.
|
||||
|
||||
-g::
|
||||
Enables call-graph (stack chain/backtrace) recording for both
|
||||
kernel space and user space.
|
||||
@ -282,7 +278,7 @@ OPTIONS
|
||||
|
||||
-q::
|
||||
--quiet::
|
||||
Don't print any message, useful for scripting.
|
||||
Don't print any warnings or messages, useful for scripting.
|
||||
|
||||
-v::
|
||||
--verbose::
|
||||
@ -388,6 +384,7 @@ following filters are defined:
|
||||
- any_call: any function call or system call
|
||||
- any_ret: any function return or system call return
|
||||
- ind_call: any indirect branch
|
||||
- ind_jmp: any indirect jump
|
||||
- call: direct calls, including far (to/from kernel) calls
|
||||
- u: only when the branch target is at the user level
|
||||
- k: only when the branch target is in the kernel
|
||||
@ -396,6 +393,10 @@ following filters are defined:
|
||||
- no_tx: only when the target is not in a hardware transaction
|
||||
- abort_tx: only when the target is a hardware transaction abort
|
||||
- cond: conditional branches
|
||||
- call_stack: save call stack
|
||||
- no_flags: don't save branch flags e.g prediction, misprediction etc
|
||||
- no_cycles: don't save branch cycles
|
||||
- hw_index: save branch hardware index
|
||||
- save_type: save branch type during sampling in case binary is not available later
|
||||
For the platforms with Intel Arch LBR support (12th-Gen+ client or
|
||||
4th-Gen Xeon+ server), the save branch type is unconditionally enabled
|
||||
|
@ -27,7 +27,7 @@ OPTIONS
|
||||
|
||||
-q::
|
||||
--quiet::
|
||||
Do not show any message. (Suppress -v)
|
||||
Do not show any warnings or messages. (Suppress -v)
|
||||
|
||||
-n::
|
||||
--show-nr-samples::
|
||||
|
@ -354,8 +354,8 @@ forbids the event merging logic from sharing events between groups and
|
||||
may be used to increase accuracy in this case.
|
||||
|
||||
--quiet::
|
||||
Don't print output. This is useful with perf stat record below to only
|
||||
write data to the perf.data file.
|
||||
Don't print output, warnings or messages. This is useful with perf stat
|
||||
record below to only write data to the perf.data file.
|
||||
|
||||
STAT RECORD
|
||||
-----------
|
||||
|
@ -51,9 +51,6 @@ Default is to monitor all CPUS.
|
||||
--count-filter=<count>::
|
||||
Only display functions with more events than this.
|
||||
|
||||
--group::
|
||||
Put the counters into a counter group.
|
||||
|
||||
--group-sort-idx::
|
||||
Sort the output by the event at the index n in group. If n is invalid,
|
||||
sort by the first event. It can support multiple groups with different
|
||||
@ -313,10 +310,10 @@ use '-e e1 -e e2 -G foo,foo' or just use '-e e1 -e e2 -G foo'.
|
||||
|
||||
perf top -e cycles,probe:icmp_rcv --switch-on=probe:icmp_rcv
|
||||
|
||||
Alternatively one can ask for --group and then two overhead columns
|
||||
Alternatively one can ask for a group and then two overhead columns
|
||||
will appear, the first for cycles and the second for the switch-on event.
|
||||
|
||||
perf top --group -e cycles,probe:icmp_rcv --switch-on=probe:icmp_rcv
|
||||
perf top -e '{cycles,probe:icmp_rcv}' --switch-on=probe:icmp_rcv
|
||||
|
||||
This may be interesting to measure a workload only after some initialization
|
||||
phase is over, i.e. insert a perf probe at that point and use the above
|
||||
|
@ -3,7 +3,6 @@ tools/arch
|
||||
tools/scripts
|
||||
tools/build
|
||||
tools/include
|
||||
tools/lib/traceevent
|
||||
tools/lib/api
|
||||
tools/lib/bpf
|
||||
tools/lib/subcmd
|
||||
@ -13,8 +12,7 @@ tools/lib/ctype.c
|
||||
tools/lib/hweight.c
|
||||
tools/lib/rbtree.c
|
||||
tools/lib/string.c
|
||||
tools/lib/symbol/kallsyms.c
|
||||
tools/lib/symbol/kallsyms.h
|
||||
tools/lib/symbol
|
||||
tools/lib/find_bit.c
|
||||
tools/lib/bitmap.c
|
||||
tools/lib/list_sort.c
|
||||
|
@ -25,7 +25,7 @@ unexport MAKEFLAGS
|
||||
# (To override it, run 'make JOBS=1' and similar.)
|
||||
#
|
||||
ifeq ($(JOBS),)
|
||||
JOBS := $(shell (getconf _NPROCESSORS_ONLN || egrep -c '^processor|^CPU[0-9]' /proc/cpuinfo) 2>/dev/null)
|
||||
JOBS := $(shell (getconf _NPROCESSORS_ONLN || grep -E -c '^processor|^CPU[0-9]' /proc/cpuinfo) 2>/dev/null)
|
||||
ifeq ($(JOBS),0)
|
||||
JOBS := 1
|
||||
endif
|
||||
|
@ -307,7 +307,7 @@ CORE_CFLAGS += -ggdb3
|
||||
CORE_CFLAGS += -funwind-tables
|
||||
CORE_CFLAGS += -Wall
|
||||
CORE_CFLAGS += -Wextra
|
||||
CORE_CFLAGS += -std=gnu99
|
||||
CORE_CFLAGS += -std=gnu11
|
||||
|
||||
CXXFLAGS += -std=gnu++14 -fno-exceptions -fno-rtti
|
||||
CXXFLAGS += -Wall
|
||||
@ -349,7 +349,6 @@ ifeq ($(DEBUG),0)
|
||||
endif
|
||||
endif
|
||||
|
||||
INC_FLAGS += -I$(srctree)/tools/lib/perf/include
|
||||
INC_FLAGS += -I$(src-perf)/util/include
|
||||
INC_FLAGS += -I$(src-perf)/arch/$(SRCARCH)/include
|
||||
INC_FLAGS += -I$(srctree)/tools/include/
|
||||
@ -367,7 +366,6 @@ endif
|
||||
|
||||
INC_FLAGS += -I$(src-perf)/util
|
||||
INC_FLAGS += -I$(src-perf)
|
||||
INC_FLAGS += -I$(srctree)/tools/lib/
|
||||
|
||||
CORE_CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
|
||||
|
||||
@ -765,18 +763,20 @@ ifndef NO_LIBUNWIND
|
||||
EXTLIBS += $(EXTLIBS_LIBUNWIND)
|
||||
endif
|
||||
|
||||
ifeq ($(NO_SYSCALL_TABLE),0)
|
||||
$(call detected,CONFIG_TRACE)
|
||||
else
|
||||
ifndef NO_LIBAUDIT
|
||||
$(call feature_check,libaudit)
|
||||
ifneq ($(feature-libaudit), 1)
|
||||
msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
|
||||
NO_LIBAUDIT := 1
|
||||
else
|
||||
CFLAGS += -DHAVE_LIBAUDIT_SUPPORT
|
||||
EXTLIBS += -laudit
|
||||
$(call detected,CONFIG_TRACE)
|
||||
ifneq ($(NO_LIBTRACEEVENT),1)
|
||||
ifeq ($(NO_SYSCALL_TABLE),0)
|
||||
$(call detected,CONFIG_TRACE)
|
||||
else
|
||||
ifndef NO_LIBAUDIT
|
||||
$(call feature_check,libaudit)
|
||||
ifneq ($(feature-libaudit), 1)
|
||||
msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
|
||||
NO_LIBAUDIT := 1
|
||||
else
|
||||
CFLAGS += -DHAVE_LIBAUDIT_SUPPORT
|
||||
EXTLIBS += -laudit
|
||||
$(call detected,CONFIG_TRACE)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@ -871,6 +871,7 @@ define disable-python_code
|
||||
NO_LIBPYTHON := 1
|
||||
endef
|
||||
|
||||
PYTHON_EXTENSION_SUFFIX := '.so'
|
||||
ifdef NO_LIBPYTHON
|
||||
$(call disable-python,Python support disabled by user)
|
||||
else
|
||||
@ -889,7 +890,8 @@ else
|
||||
else
|
||||
LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
|
||||
EXTLIBS += $(PYTHON_EMBED_LIBADD)
|
||||
LANG_BINDINGS += $(obj-perf)python/perf.so
|
||||
PYTHON_EXTENSION_SUFFIX := $(shell $(PYTHON) -c 'from importlib import machinery; print(machinery.EXTENSION_SUFFIXES[0])')
|
||||
LANG_BINDINGS += $(obj-perf)python/perf$(PYTHON_EXTENSION_SUFFIX)
|
||||
CFLAGS += -DHAVE_LIBPYTHON_SUPPORT
|
||||
$(call detected,CONFIG_LIBPYTHON)
|
||||
endif
|
||||
@ -1184,9 +1186,11 @@ ifdef LIBPFM4
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef LIBTRACEEVENT_DYNAMIC
|
||||
# libtraceevent is a recommended dependency picked up from the system.
|
||||
ifneq ($(NO_LIBTRACEEVENT),1)
|
||||
$(call feature_check,libtraceevent)
|
||||
ifeq ($(feature-libtraceevent), 1)
|
||||
CFLAGS += -DHAVE_LIBTRACEEVENT
|
||||
EXTLIBS += -ltraceevent
|
||||
LIBTRACEEVENT_VERSION := $(shell $(PKG_CONFIG) --modversion libtraceevent)
|
||||
LIBTRACEEVENT_VERSION_1 := $(word 1, $(subst ., ,$(LIBTRACEEVENT_VERSION)))
|
||||
@ -1194,12 +1198,15 @@ ifdef LIBTRACEEVENT_DYNAMIC
|
||||
LIBTRACEEVENT_VERSION_3 := $(word 3, $(subst ., ,$(LIBTRACEEVENT_VERSION)))
|
||||
LIBTRACEEVENT_VERSION_CPP := $(shell expr $(LIBTRACEEVENT_VERSION_1) \* 255 \* 255 + $(LIBTRACEEVENT_VERSION_2) \* 255 + $(LIBTRACEEVENT_VERSION_3))
|
||||
CFLAGS += -DLIBTRACEEVENT_VERSION=$(LIBTRACEEVENT_VERSION_CPP)
|
||||
$(call detected,CONFIG_LIBTRACEEVENT)
|
||||
LIBTRACEEVENT_VERSION_WITH_TEP_FIELD_IS_RELATIVE := $(shell expr 1 \* 255 \* 255 + 5 \* 255 + 0) # 1.5.0
|
||||
ifeq ($(shell test $(LIBTRACEEVENT_VERSION_CPP) -gt $(LIBTRACEEVENT_VERSION_WITH_TEP_FIELD_IS_RELATIVE); echo $$?),0)
|
||||
CFLAGS += -DHAVE_LIBTRACEEVENT_TEP_FIELD_IS_RELATIVE
|
||||
endif
|
||||
else
|
||||
dummy := $(error Error: No libtraceevent devel library found, please install libtraceevent-devel);
|
||||
dummy := $(warning Warning: libtraceevent is missing limiting functionality, please install libtraceevent-dev/libtraceevent-devel)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef LIBTRACEFS_DYNAMIC
|
||||
$(call feature_check,libtracefs)
|
||||
ifeq ($(feature-libtracefs), 1)
|
||||
EXTLIBS += -ltracefs
|
||||
@ -1209,14 +1216,12 @@ ifdef LIBTRACEFS_DYNAMIC
|
||||
LIBTRACEFS_VERSION_3 := $(word 3, $(subst ., ,$(LIBTRACEFS_VERSION)))
|
||||
LIBTRACEFS_VERSION_CPP := $(shell expr $(LIBTRACEFS_VERSION_1) \* 255 \* 255 + $(LIBTRACEFS_VERSION_2) \* 255 + $(LIBTRACEFS_VERSION_3))
|
||||
CFLAGS += -DLIBTRACEFS_VERSION=$(LIBTRACEFS_VERSION_CPP)
|
||||
else
|
||||
dummy := $(error Error: No libtracefs devel library found, please install libtracefs-dev);
|
||||
endif
|
||||
endif
|
||||
|
||||
# Among the variables below, these:
|
||||
# perfexecdir
|
||||
# perf_include_dir
|
||||
# libbpf_include_dir
|
||||
# perf_examples_dir
|
||||
# template_dir
|
||||
# mandir
|
||||
@ -1239,7 +1244,8 @@ includedir = $(abspath $(prefix)/$(includedir_relative))
|
||||
mandir = share/man
|
||||
infodir = share/info
|
||||
perfexecdir = libexec/perf-core
|
||||
perf_include_dir = lib/perf/include
|
||||
# FIXME: system's libbpf header directory, where we expect to find bpf/bpf_helpers.h, for instance
|
||||
libbpf_include_dir = /usr/include
|
||||
perf_examples_dir = lib/perf/examples
|
||||
sharedir = $(prefix)/share
|
||||
template_dir = share/perf-core/templates
|
||||
@ -1272,7 +1278,7 @@ includedir_SQ = $(subst ','\'',$(includedir))
|
||||
mandir_SQ = $(subst ','\'',$(mandir))
|
||||
infodir_SQ = $(subst ','\'',$(infodir))
|
||||
perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
|
||||
perf_include_dir_SQ = $(subst ','\'',$(perf_include_dir))
|
||||
libbpf_include_dir_SQ = $(subst ','\'',$(libbpf_include_dir))
|
||||
perf_examples_dir_SQ = $(subst ','\'',$(perf_examples_dir))
|
||||
template_dir_SQ = $(subst ','\'',$(template_dir))
|
||||
htmldir_SQ = $(subst ','\'',$(htmldir))
|
||||
@ -1284,13 +1290,13 @@ srcdir_SQ = $(subst ','\'',$(srcdir))
|
||||
|
||||
ifneq ($(filter /%,$(firstword $(perfexecdir))),)
|
||||
perfexec_instdir = $(perfexecdir)
|
||||
perf_include_instdir = $(perf_include_dir)
|
||||
perf_include_instdir = $(libbpf_include_dir)
|
||||
perf_examples_instdir = $(perf_examples_dir)
|
||||
STRACE_GROUPS_INSTDIR = $(STRACE_GROUPS_DIR)
|
||||
tip_instdir = $(tipdir)
|
||||
else
|
||||
perfexec_instdir = $(prefix)/$(perfexecdir)
|
||||
perf_include_instdir = $(prefix)/$(perf_include_dir)
|
||||
perf_include_instdir = $(prefix)/$(libbpf_include_dir)
|
||||
perf_examples_instdir = $(prefix)/$(perf_examples_dir)
|
||||
STRACE_GROUPS_INSTDIR = $(prefix)/$(STRACE_GROUPS_DIR)
|
||||
tip_instdir = $(prefix)/$(tipdir)
|
||||
@ -1352,7 +1358,7 @@ $(call detected_var,ETC_PERFCONFIG_SQ)
|
||||
$(call detected_var,STRACE_GROUPS_DIR_SQ)
|
||||
$(call detected_var,prefix_SQ)
|
||||
$(call detected_var,perfexecdir_SQ)
|
||||
$(call detected_var,perf_include_dir_SQ)
|
||||
$(call detected_var,libbpf_include_dir_SQ)
|
||||
$(call detected_var,perf_examples_dir_SQ)
|
||||
$(call detected_var,tipdir_SQ)
|
||||
$(call detected_var,srcdir_SQ)
|
||||
|
@ -128,10 +128,6 @@ include ../scripts/utilities.mak
|
||||
#
|
||||
# Define BUILD_BPF_SKEL to enable BPF skeletons
|
||||
#
|
||||
# Define LIBTRACEEVENT_DYNAMIC to enable libtraceevent dynamic linking
|
||||
#
|
||||
# Define LIBTRACEFS_DYNAMIC to enable libtracefs dynamic linking
|
||||
#
|
||||
|
||||
# As per kernel Makefile, avoid funny character set dependencies
|
||||
unexport LC_ALL
|
||||
@ -241,10 +237,10 @@ sub-make: fixdep
|
||||
|
||||
else # force_fixdep
|
||||
|
||||
LIB_DIR = $(srctree)/tools/lib/api/
|
||||
TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
|
||||
LIBAPI_DIR = $(srctree)/tools/lib/api/
|
||||
LIBBPF_DIR = $(srctree)/tools/lib/bpf/
|
||||
SUBCMD_DIR = $(srctree)/tools/lib/subcmd/
|
||||
LIBSUBCMD_DIR = $(srctree)/tools/lib/subcmd/
|
||||
LIBSYMBOL_DIR = $(srctree)/tools/lib/symbol/
|
||||
LIBPERF_DIR = $(srctree)/tools/lib/perf/
|
||||
DOC_DIR = $(srctree)/tools/perf/Documentation/
|
||||
|
||||
@ -292,36 +288,15 @@ grep-libs = $(filter -l%,$(1))
|
||||
strip-libs = $(filter-out -l%,$(1))
|
||||
|
||||
ifneq ($(OUTPUT),)
|
||||
TE_PATH=$(OUTPUT)
|
||||
PLUGINS_PATH=$(OUTPUT)
|
||||
SUBCMD_PATH=$(OUTPUT)
|
||||
LIBPERF_PATH=$(OUTPUT)
|
||||
ifneq ($(subdir),)
|
||||
API_PATH=$(OUTPUT)/../lib/api/
|
||||
LIBAPI_OUTPUT = $(abspath $(OUTPUT))/libapi
|
||||
else
|
||||
API_PATH=$(OUTPUT)
|
||||
LIBAPI_OUTPUT = $(CURDIR)/libapi
|
||||
endif
|
||||
else
|
||||
TE_PATH=$(TRACE_EVENT_DIR)
|
||||
PLUGINS_PATH=$(TRACE_EVENT_DIR)plugins/
|
||||
API_PATH=$(LIB_DIR)
|
||||
SUBCMD_PATH=$(SUBCMD_DIR)
|
||||
LIBPERF_PATH=$(LIBPERF_DIR)
|
||||
endif
|
||||
|
||||
LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
|
||||
export LIBTRACEEVENT
|
||||
LIBTRACEEVENT_DYNAMIC_LIST = $(PLUGINS_PATH)libtraceevent-dynamic-list
|
||||
|
||||
#
|
||||
# The static build has no dynsym table, so this does not work for
|
||||
# static build. Looks like linker starts to scream about that now
|
||||
# (in Fedora 26) so we need to switch it off for static build.
|
||||
DYNAMIC_LIST_LDFLAGS = -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYNAMIC_LIST)
|
||||
LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS = $(if $(findstring -static,$(LDFLAGS)),,$(DYNAMIC_LIST_LDFLAGS))
|
||||
|
||||
LIBAPI = $(API_PATH)libapi.a
|
||||
LIBAPI_DESTDIR = $(LIBAPI_OUTPUT)
|
||||
LIBAPI_INCLUDE = $(LIBAPI_DESTDIR)/include
|
||||
LIBAPI = $(LIBAPI_OUTPUT)/libapi.a
|
||||
export LIBAPI
|
||||
CFLAGS += -I$(LIBAPI_OUTPUT)/include
|
||||
|
||||
ifneq ($(OUTPUT),)
|
||||
LIBBPF_OUTPUT = $(abspath $(OUTPUT))/libbpf
|
||||
@ -331,11 +306,38 @@ endif
|
||||
LIBBPF_DESTDIR = $(LIBBPF_OUTPUT)
|
||||
LIBBPF_INCLUDE = $(LIBBPF_DESTDIR)/include
|
||||
LIBBPF = $(LIBBPF_OUTPUT)/libbpf.a
|
||||
CFLAGS += -I$(LIBBPF_OUTPUT)/include
|
||||
|
||||
LIBSUBCMD = $(SUBCMD_PATH)libsubcmd.a
|
||||
ifneq ($(OUTPUT),)
|
||||
LIBSUBCMD_OUTPUT = $(abspath $(OUTPUT))/libsubcmd
|
||||
else
|
||||
LIBSUBCMD_OUTPUT = $(CURDIR)/libsubcmd
|
||||
endif
|
||||
LIBSUBCMD_DESTDIR = $(LIBSUBCMD_OUTPUT)
|
||||
LIBSUBCMD_INCLUDE = $(LIBSUBCMD_DESTDIR)/include
|
||||
LIBSUBCMD = $(LIBSUBCMD_OUTPUT)/libsubcmd.a
|
||||
CFLAGS += -I$(LIBSUBCMD_OUTPUT)/include
|
||||
|
||||
LIBPERF = $(LIBPERF_PATH)libperf.a
|
||||
ifneq ($(OUTPUT),)
|
||||
LIBSYMBOL_OUTPUT = $(abspath $(OUTPUT))/libsymbol
|
||||
else
|
||||
LIBSYMBOL_OUTPUT = $(CURDIR)/libsymbol
|
||||
endif
|
||||
LIBSYMBOL_DESTDIR = $(LIBSYMBOL_OUTPUT)
|
||||
LIBSYMBOL_INCLUDE = $(LIBSYMBOL_DESTDIR)/include
|
||||
LIBSYMBOL = $(LIBSYMBOL_OUTPUT)/libsymbol.a
|
||||
CFLAGS += -I$(LIBSYMBOL_OUTPUT)/include
|
||||
|
||||
ifneq ($(OUTPUT),)
|
||||
LIBPERF_OUTPUT = $(abspath $(OUTPUT))/libperf
|
||||
else
|
||||
LIBPERF_OUTPUT = $(CURDIR)/libperf
|
||||
endif
|
||||
LIBPERF_DESTDIR = $(LIBPERF_OUTPUT)
|
||||
LIBPERF_INCLUDE = $(LIBPERF_DESTDIR)/include
|
||||
LIBPERF = $(LIBPERF_OUTPUT)/libperf.a
|
||||
export LIBPERF
|
||||
CFLAGS += -I$(LIBPERF_OUTPUT)/include
|
||||
|
||||
# python extension build directories
|
||||
PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
|
||||
@ -345,8 +347,13 @@ export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
|
||||
|
||||
python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf*.so
|
||||
|
||||
PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
|
||||
PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBAPI)
|
||||
ifeq ($(CONFIG_LIBTRACEEVENT),y)
|
||||
PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
|
||||
else
|
||||
PYTHON_EXT_SRCS := $(shell grep -v '^\#\|util/trace-event.c' util/python-ext-sources)
|
||||
endif
|
||||
|
||||
PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBAPI)
|
||||
|
||||
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
|
||||
|
||||
@ -385,15 +392,12 @@ endif
|
||||
|
||||
export PERL_PATH
|
||||
|
||||
PERFLIBS = $(LIBAPI) $(LIBSUBCMD) $(LIBPERF)
|
||||
PERFLIBS = $(LIBAPI) $(LIBPERF) $(LIBSUBCMD) $(LIBSYMBOL)
|
||||
ifndef NO_LIBBPF
|
||||
ifndef LIBBPF_DYNAMIC
|
||||
PERFLIBS += $(LIBBPF)
|
||||
endif
|
||||
endif
|
||||
ifndef LIBTRACEEVENT_DYNAMIC
|
||||
PERFLIBS += $(LIBTRACEEVENT)
|
||||
endif
|
||||
|
||||
# We choose to avoid "if .. else if .. else .. endif endif"
|
||||
# because maintaining the nesting to match is a pain. If
|
||||
@ -643,9 +647,9 @@ all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
|
||||
# Create python binding output directory if not already present
|
||||
_dummy := $(shell [ -d '$(OUTPUT)python' ] || mkdir -p '$(OUTPUT)python')
|
||||
|
||||
$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) $(LIBTRACEEVENT_DYNAMIC_LIST) $(LIBPERF)
|
||||
$(OUTPUT)python/perf$(PYTHON_EXTENSION_SUFFIX): $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) $(LIBPERF)
|
||||
$(QUIET_GEN)LDSHARED="$(CC) -pthread -shared" \
|
||||
CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS)' \
|
||||
CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS)' \
|
||||
$(PYTHON_WORD) util/setup.py \
|
||||
--quiet build_ext; \
|
||||
cp $(PYTHON_EXTBUILD_LIB)perf*.so $(OUTPUT)python/
|
||||
@ -668,14 +672,14 @@ build := -f $(srctree)/tools/build/Makefile.build dir=. obj
|
||||
$(PERF_IN): prepare FORCE
|
||||
$(Q)$(MAKE) $(build)=perf
|
||||
|
||||
$(PMU_EVENTS_IN): FORCE
|
||||
$(PMU_EVENTS_IN): FORCE prepare
|
||||
$(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=pmu-events obj=pmu-events
|
||||
|
||||
$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(PMU_EVENTS_IN) $(LIBTRACEEVENT_DYNAMIC_LIST)
|
||||
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS) \
|
||||
$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(PMU_EVENTS_IN)
|
||||
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) \
|
||||
$(PERF_IN) $(PMU_EVENTS_IN) $(LIBS) -o $@
|
||||
|
||||
$(GTK_IN): FORCE
|
||||
$(GTK_IN): FORCE prepare
|
||||
$(Q)$(MAKE) $(build)=gtk
|
||||
|
||||
$(OUTPUT)libperf-gtk.so: $(GTK_IN) $(PERFLIBS)
|
||||
@ -751,6 +755,11 @@ prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders $(drm_ioc
|
||||
$(rename_flags_array) \
|
||||
$(arch_errno_name_array) \
|
||||
$(sync_file_range_arrays) \
|
||||
$(LIBAPI) \
|
||||
$(LIBBPF) \
|
||||
$(LIBPERF) \
|
||||
$(LIBSUBCMD) \
|
||||
$(LIBSYMBOL) \
|
||||
bpf-skel
|
||||
|
||||
$(OUTPUT)%.o: %.c prepare FORCE
|
||||
@ -808,30 +817,14 @@ endif
|
||||
|
||||
$(patsubst perf-%,%.o,$(PROGRAMS)): $(wildcard */*.h)
|
||||
|
||||
LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) 'EXTRA_CFLAGS=$(EXTRA_CFLAGS)' 'LDFLAGS=$(filter-out -static,$(LDFLAGS))'
|
||||
|
||||
$(LIBTRACEEVENT): FORCE
|
||||
$(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent.a
|
||||
|
||||
libtraceevent_plugins: FORCE
|
||||
$(Q)$(MAKE) -C $(TRACE_EVENT_DIR)plugins $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) plugins
|
||||
|
||||
$(LIBTRACEEVENT_DYNAMIC_LIST): libtraceevent_plugins
|
||||
$(Q)$(MAKE) -C $(TRACE_EVENT_DIR)plugins $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent-dynamic-list
|
||||
|
||||
$(LIBTRACEEVENT)-clean:
|
||||
$(call QUIET_CLEAN, libtraceevent)
|
||||
$(Q)$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null
|
||||
|
||||
install-traceevent-plugins: libtraceevent_plugins
|
||||
$(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) install_plugins
|
||||
|
||||
$(LIBAPI): FORCE
|
||||
$(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) $(OUTPUT)libapi.a
|
||||
$(LIBAPI): FORCE | $(LIBAPI_OUTPUT)
|
||||
$(Q)$(MAKE) -C $(LIBAPI_DIR) O=$(LIBAPI_OUTPUT) \
|
||||
DESTDIR=$(LIBAPI_DESTDIR) prefix= \
|
||||
$@ install_headers
|
||||
|
||||
$(LIBAPI)-clean:
|
||||
$(call QUIET_CLEAN, libapi)
|
||||
$(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null
|
||||
$(Q)$(RM) -r -- $(LIBAPI_OUTPUT)
|
||||
|
||||
$(LIBBPF): FORCE | $(LIBBPF_OUTPUT)
|
||||
$(Q)$(MAKE) -C $(LIBBPF_DIR) FEATURES_DUMP=$(FEATURE_DUMP_EXPORT) \
|
||||
@ -842,18 +835,32 @@ $(LIBBPF)-clean:
|
||||
$(call QUIET_CLEAN, libbpf)
|
||||
$(Q)$(RM) -r -- $(LIBBPF_OUTPUT)
|
||||
|
||||
$(LIBPERF): FORCE
|
||||
$(Q)$(MAKE) -C $(LIBPERF_DIR) EXTRA_CFLAGS="$(LIBPERF_CFLAGS)" O=$(OUTPUT) $(OUTPUT)libperf.a
|
||||
$(LIBPERF): FORCE | $(LIBPERF_OUTPUT)
|
||||
$(Q)$(MAKE) -C $(LIBPERF_DIR) O=$(LIBPERF_OUTPUT) \
|
||||
DESTDIR=$(LIBPERF_DESTDIR) prefix= \
|
||||
$@ install_headers
|
||||
|
||||
$(LIBPERF)-clean:
|
||||
$(call QUIET_CLEAN, libperf)
|
||||
$(Q)$(MAKE) -C $(LIBPERF_DIR) O=$(OUTPUT) clean >/dev/null
|
||||
$(Q)$(RM) -r -- $(LIBPERF_OUTPUT)
|
||||
|
||||
$(LIBSUBCMD): FORCE
|
||||
$(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) $(OUTPUT)libsubcmd.a
|
||||
$(LIBSUBCMD): FORCE | $(LIBSUBCMD_OUTPUT)
|
||||
$(Q)$(MAKE) -C $(LIBSUBCMD_DIR) O=$(LIBSUBCMD_OUTPUT) \
|
||||
DESTDIR=$(LIBSUBCMD_DESTDIR) prefix= \
|
||||
$@ install_headers
|
||||
|
||||
$(LIBSUBCMD)-clean:
|
||||
$(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) clean
|
||||
$(call QUIET_CLEAN, libsubcmd)
|
||||
$(Q)$(RM) -r -- $(LIBSUBCMD_OUTPUT)
|
||||
|
||||
$(LIBSYMBOL): FORCE | $(LIBSYMBOL_OUTPUT)
|
||||
$(Q)$(MAKE) -C $(LIBSYMBOL_DIR) O=$(LIBSYMBOL_OUTPUT) \
|
||||
DESTDIR=$(LIBSYMBOL_DESTDIR) prefix= \
|
||||
$@ install_headers
|
||||
|
||||
$(LIBSYMBOL)-clean:
|
||||
$(call QUIET_CLEAN, libsymbol)
|
||||
$(Q)$(RM) -r -- $(LIBSYMBOL_OUTPUT)
|
||||
|
||||
help:
|
||||
@echo 'Perf make targets:'
|
||||
@ -960,11 +967,6 @@ endif
|
||||
$(call QUIET_INSTALL, libexec) \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
|
||||
ifndef NO_LIBBPF
|
||||
$(call QUIET_INSTALL, bpf-headers) \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf'; \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf/linux'; \
|
||||
$(INSTALL) include/bpf/*.h -m 644 -t '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf'; \
|
||||
$(INSTALL) include/bpf/linux/*.h -m 644 -t '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf/linux'
|
||||
$(call QUIET_INSTALL, bpf-examples) \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf'; \
|
||||
$(INSTALL) examples/bpf/*.c -m 644 -t '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf'
|
||||
@ -1020,7 +1022,7 @@ install-tests: all install-gtk
|
||||
$(INSTALL) tests/shell/coresight/*.sh '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/coresight'
|
||||
$(Q)$(MAKE) -C tests/shell/coresight install-tests
|
||||
|
||||
install-bin: install-tools install-tests install-traceevent-plugins
|
||||
install-bin: install-tools install-tests
|
||||
|
||||
install: install-bin try-install-man
|
||||
|
||||
@ -1044,7 +1046,7 @@ SKELETONS += $(SKEL_OUT)/bperf_cgroup.skel.h $(SKEL_OUT)/func_latency.skel.h
|
||||
SKELETONS += $(SKEL_OUT)/off_cpu.skel.h $(SKEL_OUT)/lock_contention.skel.h
|
||||
SKELETONS += $(SKEL_OUT)/kwork_trace.skel.h
|
||||
|
||||
$(SKEL_TMP_OUT) $(LIBBPF_OUTPUT):
|
||||
$(SKEL_TMP_OUT) $(LIBAPI_OUTPUT) $(LIBBPF_OUTPUT) $(LIBPERF_OUTPUT) $(LIBSUBCMD_OUTPUT) $(LIBSYMBOL_OUTPUT):
|
||||
$(Q)$(MKDIR) -p $@
|
||||
|
||||
ifdef BUILD_BPF_SKEL
|
||||
@ -1089,7 +1091,7 @@ endif # BUILD_BPF_SKEL
|
||||
bpf-skel-clean:
|
||||
$(call QUIET_CLEAN, bpf-skel) $(RM) -r $(SKEL_TMP_OUT) $(SKELETONS)
|
||||
|
||||
clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean $(LIBPERF)-clean fixdep-clean python-clean bpf-skel-clean tests-coresight-targets-clean
|
||||
clean:: $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean $(LIBSYMBOL)-clean $(LIBPERF)-clean fixdep-clean python-clean bpf-skel-clean tests-coresight-targets-clean
|
||||
$(call QUIET_CLEAN, core-objs) $(RM) $(LIBPERF_A) $(OUTPUT)perf-archive $(OUTPUT)perf-iostat $(LANG_BINDINGS)
|
||||
$(Q)find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
|
||||
$(Q)$(RM) $(OUTPUT).config-detected
|
||||
@ -1146,6 +1148,6 @@ FORCE:
|
||||
.PHONY: all install clean config-clean strip install-gtk
|
||||
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
|
||||
.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope FORCE prepare
|
||||
.PHONY: libtraceevent_plugins archheaders
|
||||
.PHONY: archheaders
|
||||
|
||||
endif # force_fixdep
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <elfutils/libdwfl.h>
|
||||
#include "../../../util/unwind-libdw.h"
|
||||
#include "../../../util/perf_regs.h"
|
||||
#include "../../../util/event.h"
|
||||
#include "../../../util/sample.h"
|
||||
|
||||
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
|
||||
{
|
||||
|
@ -58,5 +58,5 @@ create_table()
|
||||
|
||||
$gcc -E -dM -x c -I $incpath/include/uapi $input \
|
||||
|sed -ne 's/^#define __NR_//p' \
|
||||
|sort -t' ' -k2 -nu \
|
||||
|sort -t' ' -k2 -n \
|
||||
|create_table
|
||||
|
@ -3,7 +3,7 @@ perf-y += machine.o
|
||||
perf-y += perf_regs.o
|
||||
perf-y += tsc.o
|
||||
perf-y += pmu.o
|
||||
perf-y += kvm-stat.o
|
||||
perf-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
|
||||
perf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
|
||||
perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "symbol.h"
|
||||
#include "callchain.h"
|
||||
#include "record.h"
|
||||
#include "util/perf_regs.h"
|
||||
|
||||
void arch__add_leaf_frame_record_opts(struct record_opts *opts)
|
||||
{
|
||||
|
@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <internal/cpumap.h>
|
||||
#include "../../../util/cpumap.h"
|
||||
#include "../../../util/pmu.h"
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user