diff options
Diffstat (limited to 'tools/lib')
71 files changed, 5942 insertions, 1114 deletions
diff --git a/tools/lib/bpf/.gitignore b/tools/lib/bpf/.gitignore index fecb78afea3f..d9e9dec04605 100644 --- a/tools/lib/bpf/.gitignore +++ b/tools/lib/bpf/.gitignore @@ -1,4 +1,5 @@ libbpf_version.h +libbpf.pc FEATURE-DUMP.libbpf test_libbpf libbpf.so.* diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 8e7c56e9590f..f91639bf5650 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -3,7 +3,7 @@ BPF_VERSION = 0 BPF_PATCHLEVEL = 0 -BPF_EXTRAVERSION = 2 +BPF_EXTRAVERSION = 3 MAKEFLAGS += --no-print-directory @@ -90,6 +90,7 @@ LIBBPF_VERSION = $(BPF_VERSION).$(BPF_PATCHLEVEL).$(BPF_EXTRAVERSION) LIB_TARGET = libbpf.a libbpf.so.$(LIBBPF_VERSION) LIB_FILE = libbpf.a libbpf.so* +PC_FILE = libbpf.pc # Set compile option CFLAGS ifdef EXTRA_CFLAGS @@ -134,13 +135,14 @@ VERSION_SCRIPT := libbpf.map LIB_TARGET := $(addprefix $(OUTPUT),$(LIB_TARGET)) LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE)) +PC_FILE := $(addprefix $(OUTPUT),$(PC_FILE)) GLOBAL_SYM_COUNT = $(shell readelf -s --wide $(BPF_IN) | \ awk '/GLOBAL/ && /DEFAULT/ && !/UND/ {s++} END{print s}') VERSIONED_SYM_COUNT = $(shell readelf -s --wide $(OUTPUT)libbpf.so | \ grep -Eo '[^ ]+@LIBBPF_' | cut -d@ -f1 | sort -u | wc -l) -CMD_TARGETS = $(LIB_TARGET) +CMD_TARGETS = $(LIB_TARGET) $(PC_FILE) CXX_TEST_TARGET = $(OUTPUT)test_libbpf @@ -187,6 +189,12 @@ $(OUTPUT)libbpf.a: $(BPF_IN) $(OUTPUT)test_libbpf: test_libbpf.cpp $(OUTPUT)libbpf.a $(QUIET_LINK)$(CXX) $(INCLUDES) $^ -lelf -o $@ +$(OUTPUT)libbpf.pc: + $(QUIET_GEN)sed -e "s|@PREFIX@|$(prefix)|" \ + -e "s|@LIBDIR@|$(libdir_SQ)|" \ + -e "s|@VERSION@|$(LIBBPF_VERSION)|" \ + < libbpf.pc.template > $@ + check: check_abi check_abi: $(OUTPUT)libbpf.so @@ -222,9 +230,14 @@ install_headers: $(call do_install,bpf.h,$(prefix)/include/bpf,644); \ $(call do_install,libbpf.h,$(prefix)/include/bpf,644); \ $(call do_install,btf.h,$(prefix)/include/bpf,644); \ + $(call do_install,libbpf_util.h,$(prefix)/include/bpf,644); \ $(call do_install,xsk.h,$(prefix)/include/bpf,644); -install: install_lib +install_pkgconfig: $(PC_FILE) + $(call QUIET_INSTALL, $(PC_FILE)) \ + $(call do_install,$(PC_FILE),$(libdir_SQ)/pkgconfig,644) + +install: install_lib install_pkgconfig ### Cleaning rules @@ -234,7 +247,7 @@ config-clean: clean: $(call QUIET_CLEAN, libbpf) $(RM) $(TARGETS) $(CXX_TEST_TARGET) \ - *.o *~ *.a *.so *.so.$(VERSION) .*.d .*.cmd LIBBPF-CFLAGS + *.o *~ *.a *.so *.so.$(VERSION) .*.d .*.cmd *.pc LIBBPF-CFLAGS $(call QUIET_CLEAN, core-gen) $(RM) $(OUTPUT)FEATURE-DUMP.libbpf diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 9cd015574e83..c4a48086dc9a 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -46,6 +46,8 @@ # define __NR_bpf 349 # elif defined(__s390__) # define __NR_bpf 351 +# elif defined(__arc__) +# define __NR_bpf 280 # else # error __NR_bpf not defined. libbpf does not support your arch. # endif @@ -79,7 +81,6 @@ static inline int sys_bpf_prog_load(union bpf_attr *attr, unsigned int size) int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr) { - __u32 name_len = create_attr->name ? strlen(create_attr->name) : 0; union bpf_attr attr; memset(&attr, '\0', sizeof(attr)); @@ -89,8 +90,9 @@ int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr) attr.value_size = create_attr->value_size; attr.max_entries = create_attr->max_entries; attr.map_flags = create_attr->map_flags; - memcpy(attr.map_name, create_attr->name, - min(name_len, BPF_OBJ_NAME_LEN - 1)); + if (create_attr->name) + memcpy(attr.map_name, create_attr->name, + min(strlen(create_attr->name), BPF_OBJ_NAME_LEN - 1)); attr.numa_node = create_attr->numa_node; attr.btf_fd = create_attr->btf_fd; attr.btf_key_type_id = create_attr->btf_key_type_id; @@ -155,7 +157,6 @@ int bpf_create_map_in_map_node(enum bpf_map_type map_type, const char *name, int key_size, int inner_map_fd, int max_entries, __u32 map_flags, int node) { - __u32 name_len = name ? strlen(name) : 0; union bpf_attr attr; memset(&attr, '\0', sizeof(attr)); @@ -166,7 +167,9 @@ int bpf_create_map_in_map_node(enum bpf_map_type map_type, const char *name, attr.inner_map_fd = inner_map_fd; attr.max_entries = max_entries; attr.map_flags = map_flags; - memcpy(attr.map_name, name, min(name_len, BPF_OBJ_NAME_LEN - 1)); + if (name) + memcpy(attr.map_name, name, + min(strlen(name), BPF_OBJ_NAME_LEN - 1)); if (node >= 0) { attr.map_flags |= BPF_F_NUMA_NODE; @@ -216,18 +219,15 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, void *finfo = NULL, *linfo = NULL; union bpf_attr attr; __u32 log_level; - __u32 name_len; int fd; if (!load_attr || !log_buf != !log_buf_sz) return -EINVAL; log_level = load_attr->log_level; - if (log_level > 2 || (log_level && !log_buf)) + if (log_level > (4 | 2 | 1) || (log_level && !log_buf)) return -EINVAL; - name_len = load_attr->name ? strlen(load_attr->name) : 0; - memset(&attr, 0, sizeof(attr)); attr.prog_type = load_attr->prog_type; attr.expected_attach_type = load_attr->expected_attach_type; @@ -253,8 +253,9 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, attr.line_info_rec_size = load_attr->line_info_rec_size; attr.line_info_cnt = load_attr->line_info_cnt; attr.line_info = ptr_to_u64(load_attr->line_info); - memcpy(attr.prog_name, load_attr->name, - min(name_len, BPF_OBJ_NAME_LEN - 1)); + if (load_attr->name) + memcpy(attr.prog_name, load_attr->name, + min(strlen(load_attr->name), BPF_OBJ_NAME_LEN - 1)); fd = sys_bpf_prog_load(&attr, sizeof(attr)); if (fd >= 0) @@ -429,6 +430,16 @@ int bpf_map_get_next_key(int fd, const void *key, void *next_key) return sys_bpf(BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr)); } +int bpf_map_freeze(int fd) +{ + union bpf_attr attr; + + memset(&attr, 0, sizeof(attr)); + attr.map_fd = fd; + + return sys_bpf(BPF_MAP_FREEZE, &attr, sizeof(attr)); +} + int bpf_obj_pin(int fd, const char *pathname) { union bpf_attr attr; @@ -545,10 +556,15 @@ int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr) attr.test.data_out = ptr_to_u64(test_attr->data_out); attr.test.data_size_in = test_attr->data_size_in; attr.test.data_size_out = test_attr->data_size_out; + attr.test.ctx_in = ptr_to_u64(test_attr->ctx_in); + attr.test.ctx_out = ptr_to_u64(test_attr->ctx_out); + attr.test.ctx_size_in = test_attr->ctx_size_in; + attr.test.ctx_size_out = test_attr->ctx_size_out; attr.test.repeat = test_attr->repeat; ret = sys_bpf(BPF_PROG_TEST_RUN, &attr, sizeof(attr)); test_attr->data_size_out = attr.test.data_size_out; + test_attr->ctx_size_out = attr.test.ctx_size_out; test_attr->retval = attr.test.retval; test_attr->duration = attr.test.duration; return ret; diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 6ffdd79bea89..9593fec75652 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -26,6 +26,7 @@ #include <linux/bpf.h> #include <stdbool.h> #include <stddef.h> +#include <stdint.h> #ifdef __cplusplus extern "C" { @@ -92,7 +93,7 @@ struct bpf_load_program_attr { #define MAPS_RELAX_COMPAT 0x01 /* Recommend log buffer size */ -#define BPF_LOG_BUF_SIZE (256 * 1024) +#define BPF_LOG_BUF_SIZE (UINT32_MAX >> 8) /* verifier maximum in kernels <= 5.1 */ LIBBPF_API int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, char *log_buf, size_t log_buf_sz); @@ -117,6 +118,7 @@ LIBBPF_API int bpf_map_lookup_and_delete_elem(int fd, const void *key, void *value); LIBBPF_API int bpf_map_delete_elem(int fd, const void *key); LIBBPF_API int bpf_map_get_next_key(int fd, const void *key, void *next_key); +LIBBPF_API int bpf_map_freeze(int fd); LIBBPF_API int bpf_obj_pin(int fd, const char *pathname); LIBBPF_API int bpf_obj_get(const char *pathname); LIBBPF_API int bpf_prog_attach(int prog_fd, int attachable_fd, @@ -135,6 +137,11 @@ struct bpf_prog_test_run_attr { * out: length of data_out */ __u32 retval; /* out: return code of the BPF program */ __u32 duration; /* out: average per repetition in ns */ + const void *ctx_in; /* optional */ + __u32 ctx_size_in; + void *ctx_out; /* optional */ + __u32 ctx_size_out; /* in: max length of ctx_out + * out: length of cxt_out */ }; LIBBPF_API int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr); diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index cf119c9b6f27..75eaf10b9e1a 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -24,6 +24,8 @@ ((k) == BTF_KIND_CONST) || \ ((k) == BTF_KIND_RESTRICT)) +#define IS_VAR(k) ((k) == BTF_KIND_VAR) + static struct btf_type btf_void; struct btf { @@ -212,6 +214,10 @@ static int btf_type_size(struct btf_type *t) return base_size + vlen * sizeof(struct btf_member); case BTF_KIND_FUNC_PROTO: return base_size + vlen * sizeof(struct btf_param); + case BTF_KIND_VAR: + return base_size + sizeof(struct btf_var); + case BTF_KIND_DATASEC: + return base_size + vlen * sizeof(struct btf_var_secinfo); default: pr_debug("Unsupported BTF_KIND:%u\n", BTF_INFO_KIND(t->info)); return -EINVAL; @@ -283,6 +289,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id) case BTF_KIND_STRUCT: case BTF_KIND_UNION: case BTF_KIND_ENUM: + case BTF_KIND_DATASEC: size = t->size; goto done; case BTF_KIND_PTR: @@ -292,6 +299,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id) case BTF_KIND_VOLATILE: case BTF_KIND_CONST: case BTF_KIND_RESTRICT: + case BTF_KIND_VAR: type_id = t->type; break; case BTF_KIND_ARRAY: @@ -326,7 +334,8 @@ int btf__resolve_type(const struct btf *btf, __u32 type_id) t = btf__type_by_id(btf, type_id); while (depth < MAX_RESOLVE_DEPTH && !btf_type_is_void_or_null(t) && - IS_MODIFIER(BTF_INFO_KIND(t->info))) { + (IS_MODIFIER(BTF_INFO_KIND(t->info)) || + IS_VAR(BTF_INFO_KIND(t->info)))) { type_id = t->type; t = btf__type_by_id(btf, type_id); depth++; @@ -408,6 +417,92 @@ done: return btf; } +static int compare_vsi_off(const void *_a, const void *_b) +{ + const struct btf_var_secinfo *a = _a; + const struct btf_var_secinfo *b = _b; + + return a->offset - b->offset; +} + +static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf, + struct btf_type *t) +{ + __u32 size = 0, off = 0, i, vars = BTF_INFO_VLEN(t->info); + const char *name = btf__name_by_offset(btf, t->name_off); + const struct btf_type *t_var; + struct btf_var_secinfo *vsi; + struct btf_var *var; + int ret; + + if (!name) { + pr_debug("No name found in string section for DATASEC kind.\n"); + return -ENOENT; + } + + ret = bpf_object__section_size(obj, name, &size); + if (ret || !size || (t->size && t->size != size)) { + pr_debug("Invalid size for section %s: %u bytes\n", name, size); + return -ENOENT; + } + + t->size = size; + + for (i = 0, vsi = (struct btf_var_secinfo *)(t + 1); + i < vars; i++, vsi++) { + t_var = btf__type_by_id(btf, vsi->type); + var = (struct btf_var *)(t_var + 1); + + if (BTF_INFO_KIND(t_var->info) != BTF_KIND_VAR) { + pr_debug("Non-VAR type seen in section %s\n", name); + return -EINVAL; + } + + if (var->linkage == BTF_VAR_STATIC) + continue; + + name = btf__name_by_offset(btf, t_var->name_off); + if (!name) { + pr_debug("No name found in string section for VAR kind\n"); + return -ENOENT; + } + + ret = bpf_object__variable_offset(obj, name, &off); + if (ret) { + pr_debug("No offset found in symbol table for VAR %s\n", name); + return -ENOENT; + } + + vsi->offset = off; + } + + qsort(t + 1, vars, sizeof(*vsi), compare_vsi_off); + return 0; +} + +int btf__finalize_data(struct bpf_object *obj, struct btf *btf) +{ + int err = 0; + __u32 i; + + for (i = 1; i <= btf->nr_types; i++) { + struct btf_type *t = btf->types[i]; + + /* Loader needs to fix up some of the things compiler + * couldn't get its hands on while emitting BTF. This + * is section size and global variable offset. We use + * the info from the ELF itself for this purpose. + */ + if (BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC) { + err = btf_fixup_datasec(obj, btf, t); + if (err) + break; + } + } + + return err; +} + int btf__load(struct btf *btf) { __u32 log_buf_size = BPF_LOG_BUF_SIZE; @@ -1259,8 +1354,16 @@ static struct btf_dedup *btf_dedup_new(struct btf *btf, struct btf_ext *btf_ext, } /* special BTF "void" type is made canonical immediately */ d->map[0] = 0; - for (i = 1; i <= btf->nr_types; i++) - d->map[i] = BTF_UNPROCESSED_ID; + for (i = 1; i <= btf->nr_types; i++) { + struct btf_type *t = d->btf->types[i]; + __u16 kind = BTF_INFO_KIND(t->info); + + /* VAR and DATASEC are never deduped and are self-canonical */ + if (kind == BTF_KIND_VAR || kind == BTF_KIND_DATASEC) + d->map[i] = i; + else + d->map[i] = BTF_UNPROCESSED_ID; + } d->hypot_map = malloc(sizeof(__u32) * (1 + btf->nr_types)); if (!d->hypot_map) { @@ -1851,6 +1954,8 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id) case BTF_KIND_UNION: case BTF_KIND_FUNC: case BTF_KIND_FUNC_PROTO: + case BTF_KIND_VAR: + case BTF_KIND_DATASEC: return 0; case BTF_KIND_INT: @@ -2604,6 +2709,7 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id) case BTF_KIND_PTR: case BTF_KIND_TYPEDEF: case BTF_KIND_FUNC: + case BTF_KIND_VAR: r = btf_dedup_remap_type_id(d, t->type); if (r < 0) return r; @@ -2658,6 +2764,20 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id) break; } + case BTF_KIND_DATASEC: { + struct btf_var_secinfo *var = (struct btf_var_secinfo *)(t + 1); + __u16 vlen = BTF_INFO_VLEN(t->info); + + for (i = 0; i < vlen; i++) { + r = btf_dedup_remap_type_id(d, var->type); + if (r < 0) + return r; + var->type = r; + var++; + } + break; + } + default: return -EINVAL; } diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h index 28a1e1e59861..c7b399e81fce 100644 --- a/tools/lib/bpf/btf.h +++ b/tools/lib/bpf/btf.h @@ -21,6 +21,8 @@ struct btf; struct btf_ext; struct btf_type; +struct bpf_object; + /* * The .BTF.ext ELF section layout defined as * struct btf_ext_header @@ -57,6 +59,7 @@ struct btf_ext_header { LIBBPF_API void btf__free(struct btf *btf); LIBBPF_API struct btf *btf__new(__u8 *data, __u32 size); +LIBBPF_API int btf__finalize_data(struct bpf_object *obj, struct btf *btf); LIBBPF_API int btf__load(struct btf *btf); LIBBPF_API __s32 btf__find_by_name(const struct btf *btf, const char *type_name); diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 11c25d9ea431..7e3b79d7c25f 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -7,6 +7,7 @@ * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com> * Copyright (C) 2015 Huawei Inc. * Copyright (C) 2017 Nicira, Inc. + * Copyright (C) 2019 Isovalent, Inc. */ #ifndef _GNU_SOURCE @@ -43,6 +44,7 @@ #include "btf.h" #include "str_error.h" #include "libbpf_util.h" +#include "libbpf_internal.h" #ifndef EM_BPF #define EM_BPF 247 @@ -52,6 +54,11 @@ #define BPF_FS_MAGIC 0xcafe4a11 #endif +/* vsprintf() in __base_pr() uses nonliteral format string. It may break + * compilation if user enables corresponding warning. Disable it explicitly. + */ +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + #define __printf(a, b) __attribute__((format(printf, a, b))) static int __base_pr(enum libbpf_print_level level, const char *format, @@ -120,6 +127,12 @@ static inline __u64 ptr_to_u64(const void *ptr) struct bpf_capabilities { /* v4.14: kernel support for program & map names. */ __u32 name:1; + /* v5.2: kernel support for global data sections. */ + __u32 global_data:1; + /* BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO support */ + __u32 btf_func:1; + /* BTF_KIND_VAR and BTF_KIND_DATASEC support */ + __u32 btf_datasec:1; }; /* @@ -144,6 +157,7 @@ struct bpf_program { enum { RELO_LD64, RELO_CALL, + RELO_DATA, } type; int insn_idx; union { @@ -152,6 +166,7 @@ struct bpf_program { }; } *reloc_desc; int nr_reloc; + int log_level; struct { int nr; @@ -176,6 +191,19 @@ struct bpf_program { __u32 line_info_cnt; }; +enum libbpf_map_type { + LIBBPF_MAP_UNSPEC, + LIBBPF_MAP_DATA, + LIBBPF_MAP_BSS, + LIBBPF_MAP_RODATA, +}; + +static const char * const libbpf_type_to_btf_name[] = { + [LIBBPF_MAP_DATA] = ".data", + [LIBBPF_MAP_BSS] = ".bss", + [LIBBPF_MAP_RODATA] = ".rodata", +}; + struct bpf_map { int fd; char *name; @@ -187,11 +215,18 @@ struct bpf_map { __u32 btf_value_type_id; void *priv; bpf_map_clear_priv_t clear_priv; + enum libbpf_map_type libbpf_type; +}; + +struct bpf_secdata { + void *rodata; + void *data; }; static LIST_HEAD(bpf_objects_list); struct bpf_object { + char name[BPF_OBJ_NAME_LEN]; char license[64]; __u32 kern_version; @@ -199,6 +234,7 @@ struct bpf_object { size_t nr_programs; struct bpf_map *maps; size_t nr_maps; + struct bpf_secdata sections; bool loaded; bool has_pseudo_calls; @@ -214,6 +250,9 @@ struct bpf_object { Elf *elf; GElf_Ehdr ehdr; Elf_Data *symbols; + Elf_Data *data; + Elf_Data *rodata; + Elf_Data *bss; size_t strtabidx; struct { GElf_Shdr shdr; @@ -222,6 +261,9 @@ struct bpf_object { int nr_reloc; int maps_shndx; int text_shndx; + int data_shndx; + int rodata_shndx; + int bss_shndx; } efile; /* * All loaded bpf_object is linked in a list, which is @@ -443,6 +485,7 @@ static struct bpf_object *bpf_object__new(const char *path, size_t obj_buf_sz) { struct bpf_object *obj; + char *end; obj = calloc(1, sizeof(struct bpf_object) + strlen(path) + 1); if (!obj) { @@ -451,8 +494,14 @@ static struct bpf_object *bpf_object__new(const char *path, } strcpy(obj->path, path); - obj->efile.fd = -1; + /* Using basename() GNU version which doesn't modify arg. */ + strncpy(obj->name, basename((void *)path), + sizeof(obj->name) - 1); + end = strchr(obj->name, '.'); + if (end) + *end = 0; + obj->efile.fd = -1; /* * Caller of this function should also calls * bpf_object__elf_finish() after data collection to return @@ -462,6 +511,9 @@ static struct bpf_object *bpf_object__new(const char *path, obj->efile.obj_buf = obj_buf; obj->efile.obj_buf_sz = obj_buf_sz; obj->efile.maps_shndx = -1; + obj->efile.data_shndx = -1; + obj->efile.rodata_shndx = -1; + obj->efile.bss_shndx = -1; obj->loaded = false; @@ -480,6 +532,9 @@ static void bpf_object__elf_finish(struct bpf_object *obj) obj->efile.elf = NULL; } obj->efile.symbols = NULL; + obj->efile.data = NULL; + obj->efile.rodata = NULL; + obj->efile.bss = NULL; zfree(&obj->efile.reloc); obj->efile.nr_reloc = 0; @@ -621,27 +676,182 @@ static bool bpf_map_type__is_map_in_map(enum bpf_map_type type) return false; } +static int bpf_object_search_section_size(const struct bpf_object *obj, + const char *name, size_t *d_size) +{ + const GElf_Ehdr *ep = &obj->efile.ehdr; + Elf *elf = obj->efile.elf; + Elf_Scn *scn = NULL; + int idx = 0; + + while ((scn = elf_nextscn(elf, scn)) != NULL) { + const char *sec_name; + Elf_Data *data; + GElf_Shdr sh; + + idx++; + if (gelf_getshdr(scn, &sh) != &sh) { + pr_warning("failed to get section(%d) header from %s\n", + idx, obj->path); + return -EIO; + } + + sec_name = elf_strptr(elf, ep->e_shstrndx, sh.sh_name); + if (!sec_name) { + pr_warning("failed to get section(%d) name from %s\n", + idx, obj->path); + return -EIO; + } + + if (strcmp(name, sec_name)) + continue; + + data = elf_getdata(scn, 0); + if (!data) { + pr_warning("failed to get section(%d) data from %s(%s)\n", + idx, name, obj->path); + return -EIO; + } + + *d_size = data->d_size; + return 0; + } + + return -ENOENT; +} + +int bpf_object__section_size(const struct bpf_object *obj, const char *name, + __u32 *size) +{ + int ret = -ENOENT; + size_t d_size; + + *size = 0; + if (!name) { + return -EINVAL; + } else if (!strcmp(name, ".data")) { + if (obj->efile.data) + *size = obj->efile.data->d_size; + } else if (!strcmp(name, ".bss")) { + if (obj->efile.bss) + *size = obj->efile.bss->d_size; + } else if (!strcmp(name, ".rodata")) { + if (obj->efile.rodata) + *size = obj->efile.rodata->d_size; + } else { + ret = bpf_object_search_section_size(obj, name, &d_size); + if (!ret) + *size = d_size; + } + + return *size ? 0 : ret; +} + +int bpf_object__variable_offset(const struct bpf_object *obj, const char *name, + __u32 *off) +{ + Elf_Data *symbols = obj->efile.symbols; + const char *sname; + size_t si; + + if (!name || !off) + return -EINVAL; + + for (si = 0; si < symbols->d_size / sizeof(GElf_Sym); si++) { + GElf_Sym sym; + + if (!gelf_getsym(symbols, si, &sym)) + continue; + if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL || + GELF_ST_TYPE(sym.st_info) != STT_OBJECT) + continue; + + sname = elf_strptr(obj->efile.elf, obj->efile.strtabidx, + sym.st_name); + if (!sname) { + pr_warning("failed to get sym name string for var %s\n", + name); + return -EIO; + } + if (strcmp(name, sname) == 0) { + *off = sym.st_value; + return 0; + } + } + + return -ENOENT; +} + +static bool bpf_object__has_maps(const struct bpf_object *obj) +{ + return obj->efile.maps_shndx >= 0 || + obj->efile.data_shndx >= 0 || + obj->efile.rodata_shndx >= 0 || + obj->efile.bss_shndx >= 0; +} + +static int +bpf_object__init_internal_map(struct bpf_object *obj, struct bpf_map *map, + enum libbpf_map_type type, Elf_Data *data, + void **data_buff) +{ + struct bpf_map_def *def = &map->def; + char map_name[BPF_OBJ_NAME_LEN]; + + map->libbpf_type = type; + map->offset = ~(typeof(map->offset))0; + snprintf(map_name, sizeof(map_name), "%.8s%.7s", obj->name, + libbpf_type_to_btf_name[type]); + map->name = strdup(map_name); + if (!map->name) { + pr_warning("failed to alloc map name\n"); + return -ENOMEM; + } + + def->type = BPF_MAP_TYPE_ARRAY; + def->key_size = sizeof(int); + def->value_size = data->d_size; + def->max_entries = 1; + def->map_flags = type == LIBBPF_MAP_RODATA ? + BPF_F_RDONLY_PROG : 0; + if (data_buff) { + *data_buff = malloc(data->d_size); + if (!*data_buff) { + zfree(&map->name); + pr_warning("failed to alloc map content buffer\n"); + return -ENOMEM; + } + memcpy(*data_buff, data->d_buf, data->d_size); + } + + pr_debug("map %td is \"%s\"\n", map - obj->maps, map->name); + return 0; +} + static int bpf_object__init_maps(struct bpf_object *obj, int flags) { + int i, map_idx, map_def_sz = 0, nr_syms, nr_maps = 0, nr_maps_glob = 0; bool strict = !(flags & MAPS_RELAX_COMPAT); - int i, map_idx, map_def_sz, nr_maps = 0; - Elf_Scn *scn; - Elf_Data *data = NULL; Elf_Data *symbols = obj->efile.symbols; + Elf_Data *data = NULL; + int ret = 0; - if (obj->efile.maps_shndx < 0) - return -EINVAL; if (!symbols) return -EINVAL; + nr_syms = symbols->d_size / sizeof(GElf_Sym); - scn = elf_getscn(obj->efile.elf, obj->efile.maps_shndx); - if (scn) - data = elf_getdata(scn, NULL); - if (!scn || !data) { - pr_warning("failed to get Elf_Data from map section %d\n", - obj->efile.maps_shndx); - return -EINVAL; + if (obj->efile.maps_shndx >= 0) { + Elf_Scn *scn = elf_getscn(obj->efile.elf, + obj->efile.maps_shndx); + + if (scn) + data = elf_getdata(scn, NULL); + if (!scn || !data) { + pr_warning("failed to get Elf_Data from map section %d\n", + obj->efile.maps_shndx); + return -EINVAL; + } } /* @@ -651,7 +861,16 @@ bpf_object__init_maps(struct bpf_object *obj, int flags) * * TODO: Detect array of map and report error. */ - for (i = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) { + if (obj->caps.global_data) { + if (obj->efile.data_shndx >= 0) + nr_maps_glob++; + if (obj->efile.rodata_shndx >= 0) + nr_maps_glob++; + if (obj->efile.bss_shndx >= 0) + nr_maps_glob++; + } + + for (i = 0; data && i < nr_syms; i++) { GElf_Sym sym; if (!gelf_getsym(symbols, i, &sym)) @@ -661,22 +880,24 @@ bpf_object__init_maps(struct bpf_object *obj, int flags) nr_maps++; } - /* Alloc obj->maps and fill nr_maps. */ - pr_debug("maps in %s: %d maps in %zd bytes\n", obj->path, - nr_maps, data->d_size); - - if (!nr_maps) + if (!nr_maps && !nr_maps_glob) return 0; /* Assume equally sized map definitions */ - map_def_sz = data->d_size / nr_maps; - if (!data->d_size || (data->d_size % nr_maps) != 0) { - pr_warning("unable to determine map definition size " - "section %s, %d maps in %zd bytes\n", - obj->path, nr_maps, data->d_size); - return -EINVAL; + if (data) { + pr_debug("maps in %s: %d maps in %zd bytes\n", obj->path, + nr_maps, data->d_size); + + map_def_sz = data->d_size / nr_maps; + if (!data->d_size || (data->d_size % nr_maps) != 0) { + pr_warning("unable to determine map definition size " + "section %s, %d maps in %zd bytes\n", + obj->path, nr_maps, data->d_size); + return -EINVAL; + } } + nr_maps += nr_maps_glob; obj->maps = calloc(nr_maps, sizeof(obj->maps[0])); if (!obj->maps) { pr_warning("alloc maps for object failed\n"); @@ -697,7 +918,7 @@ bpf_object__init_maps(struct bpf_object *obj, int flags) /* * Fill obj->maps using data in "maps" section. */ - for (i = 0, map_idx = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) { + for (i = 0, map_idx = 0; data && i < nr_syms; i++) { GElf_Sym sym; const char *map_name; struct bpf_map_def *def; @@ -710,6 +931,8 @@ bpf_object__init_maps(struct bpf_object *obj, int flags) map_name = elf_strptr(obj->efile.elf, obj->efile.strtabidx, sym.st_name); + + obj->maps[map_idx].libbpf_type = LIBBPF_MAP_UNSPEC; obj->maps[map_idx].offset = sym.st_value; if (sym.st_value + map_def_sz > data->d_size) { pr_warning("corrupted maps section in %s: last map \"%s\" too small\n", @@ -758,8 +981,31 @@ bpf_object__init_maps(struct bpf_object *obj, int flags) map_idx++; } - qsort(obj->maps, obj->nr_maps, sizeof(obj->maps[0]), compare_bpf_map); - return 0; + if (!obj->caps.global_data) + goto finalize; + + /* + * Populate rest of obj->maps with libbpf internal maps. + */ + if (obj->efile.data_shndx >= 0) + ret = bpf_object__init_internal_map(obj, &obj->maps[map_idx++], + LIBBPF_MAP_DATA, + obj->efile.data, + &obj->sections.data); + if (!ret && obj->efile.rodata_shndx >= 0) + ret = bpf_object__init_internal_map(obj, &obj->maps[map_idx++], + LIBBPF_MAP_RODATA, + obj->efile.rodata, + &obj->sections.rodata); + if (!ret && obj->efile.bss_shndx >= 0) + ret = bpf_object__init_internal_map(obj, &obj->maps[map_idx++], + LIBBPF_MAP_BSS, + obj->efile.bss, NULL); +finalize: + if (!ret) + qsort(obj->maps, obj->nr_maps, sizeof(obj->maps[0]), + compare_bpf_map); + return ret; } static bool section_have_execinstr(struct bpf_object *obj, int idx) @@ -780,11 +1026,80 @@ static bool section_have_execinstr(struct bpf_object *obj, int idx) return false; } +static void bpf_object__sanitize_btf(struct bpf_object *obj) +{ + bool has_datasec = obj->caps.btf_datasec; + bool has_func = obj->caps.btf_func; + struct btf *btf = obj->btf; + struct btf_type *t; + int i, j, vlen; + __u16 kind; + + if (!obj->btf || (has_func && has_datasec)) + return; + + for (i = 1; i <= btf__get_nr_types(btf); i++) { + t = (struct btf_type *)btf__type_by_id(btf, i); + kind = BTF_INFO_KIND(t->info); + + if (!has_datasec && kind == BTF_KIND_VAR) { + /* replace VAR with INT */ + t->info = BTF_INFO_ENC(BTF_KIND_INT, 0, 0); + t->size = sizeof(int); + *(int *)(t+1) = BTF_INT_ENC(0, 0, 32); + } else if (!has_datasec && kind == BTF_KIND_DATASEC) { + /* replace DATASEC with STRUCT */ + struct btf_var_secinfo *v = (void *)(t + 1); + struct btf_member *m = (void *)(t + 1); + struct btf_type *vt; + char *name; + + name = (char *)btf__name_by_offset(btf, t->name_off); + while (*name) { + if (*name == '.') + *name = '_'; + name++; + } + + vlen = BTF_INFO_VLEN(t->info); + t->info = BTF_INFO_ENC(BTF_KIND_STRUCT, 0, vlen); + for (j = 0; j < vlen; j++, v++, m++) { + /* order of field assignments is important */ + m->offset = v->offset * 8; + m->type = v->type; + /* preserve variable name as member name */ + vt = (void *)btf__type_by_id(btf, v->type); + m->name_off = vt->name_off; + } + } else if (!has_func && kind == BTF_KIND_FUNC_PROTO) { + /* replace FUNC_PROTO with ENUM */ + vlen = BTF_INFO_VLEN(t->info); + t->info = BTF_INFO_ENC(BTF_KIND_ENUM, 0, vlen); + t->size = sizeof(__u32); /* kernel enforced */ + } else if (!has_func && kind == BTF_KIND_FUNC) { + /* replace FUNC with TYPEDEF */ + t->info = BTF_INFO_ENC(BTF_KIND_TYPEDEF, 0, 0); + } + } +} + +static void bpf_object__sanitize_btf_ext(struct bpf_object *obj) +{ + if (!obj->btf_ext) + return; + + if (!obj->caps.btf_func) { + btf_ext__free(obj->btf_ext); + obj->btf_ext = NULL; + } +} + static int bpf_object__elf_collect(struct bpf_object *obj, int flags) { Elf *elf = obj->efile.elf; GElf_Ehdr *ep = &obj->efile.ehdr; Elf_Data *btf_ext_data = NULL; + Elf_Data *btf_data = NULL; Elf_Scn *scn = NULL; int idx = 0, err = 0; @@ -828,32 +1143,18 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags) (int)sh.sh_link, (unsigned long)sh.sh_flags, (int)sh.sh_type); - if (strcmp(name, "license") == 0) + if (strcmp(name, "license") == 0) { err = bpf_object__init_license(obj, data->d_buf, data->d_size); - else if (strcmp(name, "version") == 0) + } else if (strcmp(name, "version") == 0) { err = bpf_object__init_kversion(obj, data->d_buf, data->d_size); - else if (strcmp(name, "maps") == 0) + } else if (strcmp(name, "maps") == 0) { obj->efile.maps_shndx = idx; - else if (strcmp(name, BTF_ELF_SEC) == 0) { - obj->btf = btf__new(data->d_buf, data->d_size); - if (IS_ERR(obj->btf)) { - pr_warning("Error loading ELF section %s: %ld. Ignored and continue.\n", - BTF_ELF_SEC, PTR_ERR(obj->btf)); - obj->btf = NULL; - continue; - } - err = btf__load(obj->btf); - if (err) { - pr_warning("Error loading %s into kernel: %d. Ignored and continue.\n", - BTF_ELF_SEC, err); - btf__free(obj->btf); - obj->btf = NULL; - err = 0; - } + } else if (strcmp(name, BTF_ELF_SEC) == 0) { + btf_data = data; } else if (strcmp(name, BTF_EXT_ELF_SEC) == 0) { btf_ext_data = data; } else if (sh.sh_type == SHT_SYMTAB) { @@ -865,20 +1166,28 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags) obj->efile.symbols = data; obj->efile.strtabidx = sh.sh_link; } - } else if ((sh.sh_type == SHT_PROGBITS) && - (sh.sh_flags & SHF_EXECINSTR) && - (data->d_size > 0)) { - if (strcmp(name, ".text") == 0) - obj->efile.text_shndx = idx; - err = bpf_object__add_program(obj, data->d_buf, - data->d_size, name, idx); - if (err) { - char errmsg[STRERR_BUFSIZE]; - char *cp = libbpf_strerror_r(-err, errmsg, - sizeof(errmsg)); - - pr_warning("failed to alloc program %s (%s): %s", - name, obj->path, cp); + } else if (sh.sh_type == SHT_PROGBITS && data->d_size > 0) { + if (sh.sh_flags & SHF_EXECINSTR) { + if (strcmp(name, ".text") == 0) + obj->efile.text_shndx = idx; + err = bpf_object__add_program(obj, data->d_buf, + data->d_size, name, idx); + if (err) { + char errmsg[STRERR_BUFSIZE]; + char *cp = libbpf_strerror_r(-err, errmsg, + sizeof(errmsg)); + + pr_warning("failed to alloc program %s (%s): %s", + name, obj->path, cp); + } + } else if (strcmp(name, ".data") == 0) { + obj->efile.data = data; + obj->efile.data_shndx = idx; + } else if (strcmp(name, ".rodata") == 0) { + obj->efile.rodata = data; + obj->efile.rodata_shndx = idx; + } else { + pr_debug("skip section(%d) %s\n", idx, name); } } else if (sh.sh_type == SHT_REL) { void *reloc = obj->efile.reloc; @@ -906,6 +1215,9 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags) obj->efile.reloc[n].shdr = sh; obj->efile.reloc[n].data = data; } + } else if (sh.sh_type == SHT_NOBITS && strcmp(name, ".bss") == 0) { + obj->efile.bss = data; + obj->efile.bss_shndx = idx; } else { pr_debug("skip section(%d) %s\n", idx, name); } @@ -917,6 +1229,27 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags) pr_warning("Corrupted ELF file: index of strtab invalid\n"); return LIBBPF_ERRNO__FORMAT; } + if (btf_data) { + obj->btf = btf__new(btf_data->d_buf, btf_data->d_size); + if (IS_ERR(obj->btf)) { + pr_warning("Error loading ELF section %s: %ld. Ignored and continue.\n", + BTF_ELF_SEC, PTR_ERR(obj->btf)); + obj->btf = NULL; + } else { + err = btf__finalize_data(obj, obj->btf); + if (!err) { + bpf_object__sanitize_btf(obj); + err = btf__load(obj->btf); + } + if (err) { + pr_warning("Error finalizing and loading %s into kernel: %d. Ignored and continue.\n", + BTF_ELF_SEC, err); + btf__free(obj->btf); + obj->btf = NULL; + err = 0; + } + } + } if (btf_ext_data) { if (!obj->btf) { pr_debug("Ignore ELF section %s because its depending ELF section %s is not found.\n", @@ -929,10 +1262,12 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags) BTF_EXT_ELF_SEC, PTR_ERR(obj->btf_ext)); obj->btf_ext = NULL; + } else { + bpf_object__sanitize_btf_ext(obj); } } } - if (obj->efile.maps_shndx >= 0) { + if (bpf_object__has_maps(obj)) { err = bpf_object__init_maps(obj, flags); if (err) goto out; @@ -968,13 +1303,46 @@ bpf_object__find_program_by_title(struct bpf_object *obj, const char *title) return NULL; } +static bool bpf_object__shndx_is_data(const struct bpf_object *obj, + int shndx) +{ + return shndx == obj->efile.data_shndx || + shndx == obj->efile.bss_shndx || + shndx == obj->efile.rodata_shndx; +} + +static bool bpf_object__shndx_is_maps(const struct bpf_object *obj, + int shndx) +{ + return shndx == obj->efile.maps_shndx; +} + +static bool bpf_object__relo_in_known_section(const struct bpf_object *obj, + int shndx) +{ + return shndx == obj->efile.text_shndx || + bpf_object__shndx_is_maps(obj, shndx) || + bpf_object__shndx_is_data(obj, shndx); +} + +static enum libbpf_map_type +bpf_object__section_to_libbpf_map_type(const struct bpf_object *obj, int shndx) +{ + if (shndx == obj->efile.data_shndx) + return LIBBPF_MAP_DATA; + else if (shndx == obj->efile.bss_shndx) + return LIBBPF_MAP_BSS; + else if (shndx == obj->efile.rodata_shndx) + return LIBBPF_MAP_RODATA; + else + return LIBBPF_MAP_UNSPEC; +} + static int bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, Elf_Data *data, struct bpf_object *obj) { Elf_Data *symbols = obj->efile.symbols; - int text_shndx = obj->efile.text_shndx; - int maps_shndx = obj->efile.maps_shndx; struct bpf_map *maps = obj->maps; size_t nr_maps = obj->nr_maps; int i, nrels; @@ -994,7 +1362,10 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, GElf_Sym sym; GElf_Rel rel; unsigned int insn_idx; + unsigned int shdr_idx; struct bpf_insn *insns = prog->insns; + enum libbpf_map_type type; + const char *name; size_t map_idx; if (!gelf_getrel(data, i, &rel)) { @@ -1009,13 +1380,18 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, GELF_R_SYM(rel.r_info)); return -LIBBPF_ERRNO__FORMAT; } - pr_debug("relo for %lld value %lld name %d\n", + + name = elf_strptr(obj->efile.elf, obj->efile.strtabidx, + sym.st_name) ? : "<?>"; + + pr_debug("relo for %lld value %lld name %d (\'%s\')\n", (long long) (rel.r_info >> 32), - (long long) sym.st_value, sym.st_name); + (long long) sym.st_value, sym.st_name, name); - if (sym.st_shndx != maps_shndx && sym.st_shndx != text_shndx) { - pr_warning("Program '%s' contains non-map related relo data pointing to section %u\n", - prog->section_name, sym.st_shndx); + shdr_idx = sym.st_shndx; + if (!bpf_object__relo_in_known_section(obj, shdr_idx)) { + pr_warning("Program '%s' contains unrecognized relo data pointing to section %u\n", + prog->section_name, shdr_idx); return -LIBBPF_ERRNO__RELOC; } @@ -1040,24 +1416,45 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, return -LIBBPF_ERRNO__RELOC; } - /* TODO: 'maps' is sorted. We can use bsearch to make it faster. */ - for (map_idx = 0; map_idx < nr_maps; map_idx++) { - if (maps[map_idx].offset == sym.st_value) { - pr_debug("relocation: find map %zd (%s) for insn %u\n", - map_idx, maps[map_idx].name, insn_idx); - break; + if (bpf_object__shndx_is_maps(obj, shdr_idx) || + bpf_object__shndx_is_data(obj, shdr_idx)) { + type = bpf_object__section_to_libbpf_map_type(obj, shdr_idx); + if (type != LIBBPF_MAP_UNSPEC) { + if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL) { + pr_warning("bpf: relocation: not yet supported relo for non-static global \'%s\' variable found in insns[%d].code 0x%x\n", + name, insn_idx, insns[insn_idx].code); + return -LIBBPF_ERRNO__RELOC; + } + if (!obj->caps.global_data) { + pr_warning("bpf: relocation: kernel does not support global \'%s\' variable access in insns[%d]\n", + name, insn_idx); + return -LIBBPF_ERRNO__RELOC; + } } - } - if (map_idx >= nr_maps) { - pr_warning("bpf relocation: map_idx %d large than %d\n", - (int)map_idx, (int)nr_maps - 1); - return -LIBBPF_ERRNO__RELOC; - } + for (map_idx = 0; map_idx < nr_maps; map_idx++) { + if (maps[map_idx].libbpf_type != type) + continue; + if (type != LIBBPF_MAP_UNSPEC || + (type == LIBBPF_MAP_UNSPEC && + maps[map_idx].offset == sym.st_value)) { + pr_debug("relocation: find map %zd (%s) for insn %u\n", + map_idx, maps[map_idx].name, insn_idx); + break; + } + } - prog->reloc_desc[i].type = RELO_LD64; - prog->reloc_desc[i].insn_idx = insn_idx; - prog->reloc_desc[i].map_idx = map_idx; + if (map_idx >= nr_maps) { + pr_warning("bpf relocation: map_idx %d large than %d\n", + (int)map_idx, (int)nr_maps - 1); + return -LIBBPF_ERRNO__RELOC; + } + + prog->reloc_desc[i].type = type != LIBBPF_MAP_UNSPEC ? + RELO_DATA : RELO_LD64; + prog->reloc_desc[i].insn_idx = insn_idx; + prog->reloc_desc[i].map_idx = map_idx; + } } return 0; } @@ -1065,18 +1462,27 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, static int bpf_map_find_btf_info(struct bpf_map *map, const struct btf *btf) { struct bpf_map_def *def = &map->def; - __u32 key_type_id, value_type_id; + __u32 key_type_id = 0, value_type_id = 0; int ret; - ret = btf__get_map_kv_tids(btf, map->name, def->key_size, - def->value_size, &key_type_id, - &value_type_id); - if (ret) + if (!bpf_map__is_internal(map)) { + ret = btf__get_map_kv_tids(btf, map->name, def->key_size, + def->value_size, &key_type_id, + &value_type_id); + } else { + /* + * LLVM annotates global data differently in BTF, that is, + * only as '.data', '.bss' or '.rodata'. + */ + ret = btf__find_by_name(btf, + libbpf_type_to_btf_name[map->libbpf_type]); + } + if (ret < 0) return ret; map->btf_key_type_id = key_type_id; - map->btf_value_type_id = value_type_id; - + map->btf_value_type_id = bpf_map__is_internal(map) ? + ret : value_type_id; return 0; } @@ -1182,9 +1588,146 @@ bpf_object__probe_name(struct bpf_object *obj) } static int +bpf_object__probe_global_data(struct bpf_object *obj) +{ + struct bpf_load_program_attr prg_attr; + struct bpf_create_map_attr map_attr; + char *cp, errmsg[STRERR_BUFSIZE]; + struct bpf_insn insns[] = { + BPF_LD_MAP_VALUE(BPF_REG_1, 0, 16), + BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 42), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }; + int ret, map; + + memset(&map_attr, 0, sizeof(map_attr)); + map_attr.map_type = BPF_MAP_TYPE_ARRAY; + map_attr.key_size = sizeof(int); + map_attr.value_size = 32; + map_attr.max_entries = 1; + + map = bpf_create_map_xattr(&map_attr); + if (map < 0) { + cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); + pr_warning("Error in %s():%s(%d). Couldn't create simple array map.\n", + __func__, cp, errno); + return -errno; + } + + insns[0].imm = map; + + memset(&prg_attr, 0, sizeof(prg_attr)); + prg_attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER; + prg_attr.insns = insns; + prg_attr.insns_cnt = ARRAY_SIZE(insns); + prg_attr.license = "GPL"; + + ret = bpf_load_program_xattr(&prg_attr, NULL, 0); + if (ret >= 0) { + obj->caps.global_data = 1; + close(ret); + } + + close(map); + return 0; +} + +static int bpf_object__probe_btf_func(struct bpf_object *obj) +{ + const char strs[] = "\0int\0x\0a"; + /* void x(int a) {} */ + __u32 types[] = { + /* int */ + BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + /* FUNC_PROTO */ /* [2] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 0), + BTF_PARAM_ENC(7, 1), + /* FUNC x */ /* [3] */ + BTF_TYPE_ENC(5, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 0), 2), + }; + int res; + + res = libbpf__probe_raw_btf((char *)types, sizeof(types), + strs, sizeof(strs)); + if (res < 0) + return res; + if (res > 0) + obj->caps.btf_func = 1; + return 0; +} + +static int bpf_object__probe_btf_datasec(struct bpf_object *obj) +{ + const char strs[] = "\0x\0.data"; + /* static int a; */ + __u32 types[] = { + /* int */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + /* VAR x */ /* [2] */ + BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1), + BTF_VAR_STATIC, + /* DATASEC val */ /* [3] */ + BTF_TYPE_ENC(3, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4), + BTF_VAR_SECINFO_ENC(2, 0, 4), + }; + int res; + + res = libbpf__probe_raw_btf((char *)types, sizeof(types), + strs, sizeof(strs)); + if (res < 0) + return res; + if (res > 0) + obj->caps.btf_datasec = 1; + return 0; +} + +static int bpf_object__probe_caps(struct bpf_object *obj) { - return bpf_object__probe_name(obj); + int (*probe_fn[])(struct bpf_object *obj) = { + bpf_object__probe_name, + bpf_object__probe_global_data, + bpf_object__probe_btf_func, + bpf_object__probe_btf_datasec, + }; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(probe_fn); i++) { + ret = probe_fn[i](obj); + if (ret < 0) + return ret; + } + + return 0; +} + +static int +bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map) +{ + char *cp, errmsg[STRERR_BUFSIZE]; + int err, zero = 0; + __u8 *data; + + /* Nothing to do here since kernel already zero-initializes .bss map. */ + if (map->libbpf_type == LIBBPF_MAP_BSS) + return 0; + + data = map->libbpf_type == LIBBPF_MAP_DATA ? + obj->sections.data : obj->sections.rodata; + + err = bpf_map_update_elem(map->fd, &zero, data, 0); + /* Freeze .rodata map as read-only from syscall side. */ + if (!err && map->libbpf_type == LIBBPF_MAP_RODATA) { + err = bpf_map_freeze(map->fd); + if (err) { + cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); + pr_warning("Error freezing map(%s) as read-only: %s\n", + map->name, cp); + err = 0; + } + } + return err; } static int @@ -1244,6 +1787,7 @@ bpf_object__create_maps(struct bpf_object *obj) size_t j; err = *pfd; +err_out: cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); pr_warning("failed to create map (name: '%s'): %s\n", map->name, cp); @@ -1251,6 +1795,15 @@ bpf_object__create_maps(struct bpf_object *obj) zclose(obj->maps[j].fd); return err; } + + if (bpf_map__is_internal(map)) { + err = bpf_object__populate_internal_map(obj, map); + if (err < 0) { + zclose(*pfd); + goto err_out; + } + } + pr_debug("create map %s: fd=%d\n", map->name, *pfd); } @@ -1405,21 +1958,29 @@ bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj) return 0; for (i = 0; i < prog->nr_reloc; i++) { - if (prog->reloc_desc[i].type == RELO_LD64) { + if (prog->reloc_desc[i].type == RELO_LD64 || + prog->reloc_desc[i].type == RELO_DATA) { + bool relo_data = prog->reloc_desc[i].type == RELO_DATA; struct bpf_insn *insns = prog->insns; int insn_idx, map_idx; insn_idx = prog->reloc_desc[i].insn_idx; map_idx = prog->reloc_desc[i].map_idx; - if (insn_idx >= (int)prog->insns_cnt) { + if (insn_idx + 1 >= (int)prog->insns_cnt) { pr_warning("relocation out of range: '%s'\n", prog->section_name); return -LIBBPF_ERRNO__RELOC; } - insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD; + + if (!relo_data) { + insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD; + } else { + insns[insn_idx].src_reg = BPF_PSEUDO_MAP_VALUE; + insns[insn_idx + 1].imm = insns[insn_idx].imm; + } insns[insn_idx].imm = obj->maps[map_idx].fd; - } else { + } else if (prog->reloc_desc[i].type == RELO_CALL) { err = bpf_program__reloc_text(prog, obj, &prog->reloc_desc[i]); if (err) @@ -1494,6 +2055,7 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt, { struct bpf_load_program_attr load_attr; char *cp, errmsg[STRERR_BUFSIZE]; + int log_buf_size = BPF_LOG_BUF_SIZE; char *log_buf; int ret; @@ -1514,21 +2076,30 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt, load_attr.line_info = prog->line_info; load_attr.line_info_rec_size = prog->line_info_rec_size; load_attr.line_info_cnt = prog->line_info_cnt; + load_attr.log_level = prog->log_level; if (!load_attr.insns || !load_attr.insns_cnt) return -EINVAL; - log_buf = malloc(BPF_LOG_BUF_SIZE); +retry_load: + log_buf = malloc(log_buf_size); if (!log_buf) pr_warning("Alloc log buffer for bpf loader error, continue without log\n"); - ret = bpf_load_program_xattr(&load_attr, log_buf, BPF_LOG_BUF_SIZE); + ret = bpf_load_program_xattr(&load_attr, log_buf, log_buf_size); if (ret >= 0) { + if (load_attr.log_level) + pr_debug("verifier log:\n%s", log_buf); *pfd = ret; ret = 0; goto out; } + if (errno == ENOSPC) { + log_buf_size <<= 1; + free(log_buf); + goto retry_load; + } ret = -LIBBPF_ERRNO__LOAD; cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); pr_warning("load bpf program failed: %s\n", cp); @@ -1693,7 +2264,9 @@ static bool bpf_prog_type__needs_kver(enum bpf_prog_type type) case BPF_PROG_TYPE_UNSPEC: case BPF_PROG_TYPE_TRACEPOINT: case BPF_PROG_TYPE_RAW_TRACEPOINT: + case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE: case BPF_PROG_TYPE_PERF_EVENT: + case BPF_PROG_TYPE_CGROUP_SYSCTL: return false; case BPF_PROG_TYPE_KPROBE: default: @@ -1729,6 +2302,7 @@ __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz, CHECK_ERR(bpf_object__elf_init(obj), err, out); CHECK_ERR(bpf_object__check_endianness(obj), err, out); + CHECK_ERR(bpf_object__probe_caps(obj), err, out); CHECK_ERR(bpf_object__elf_collect(obj, flags), err, out); CHECK_ERR(bpf_object__collect_reloc(obj), err, out); CHECK_ERR(bpf_object__validate(obj, needs_kver), err, out); @@ -1822,7 +2396,6 @@ int bpf_object__load(struct bpf_object *obj) obj->loaded = true; - CHECK_ERR(bpf_object__probe_caps(obj), err, out); CHECK_ERR(bpf_object__create_maps(obj), err, out); CHECK_ERR(bpf_object__relocate(obj), err, out); CHECK_ERR(bpf_object__load_progs(obj), err, out); @@ -2303,6 +2876,9 @@ void bpf_object__close(struct bpf_object *obj) obj->maps[i].priv = NULL; obj->maps[i].clear_priv = NULL; } + + zfree(&obj->sections.rodata); + zfree(&obj->sections.data); zfree(&obj->maps); obj->nr_maps = 0; @@ -2631,6 +3207,8 @@ static const struct { BPF_CGROUP_UDP4_SENDMSG), BPF_EAPROG_SEC("cgroup/sendmsg6", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP6_SENDMSG), + BPF_EAPROG_SEC("cgroup/sysctl", BPF_PROG_TYPE_CGROUP_SYSCTL, + BPF_CGROUP_SYSCTL), }; #undef BPF_PROG_SEC_IMPL @@ -2780,6 +3358,11 @@ bool bpf_map__is_offload_neutral(struct bpf_map *map) return map->def.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY; } +bool bpf_map__is_internal(struct bpf_map *map) +{ + return map->libbpf_type != LIBBPF_MAP_UNSPEC; +} + void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex) { map->map_ifindex = ifindex; @@ -2938,6 +3521,7 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, bpf_program__set_expected_attach_type(prog, expected_attach_type); + prog->log_level = attr->log_level; if (!first_prog) first_prog = prog; } diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index c70785cc8ef5..c5ff00515ce7 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -75,6 +75,10 @@ struct bpf_object *__bpf_object__open_xattr(struct bpf_object_open_attr *attr, LIBBPF_API struct bpf_object *bpf_object__open_buffer(void *obj_buf, size_t obj_buf_sz, const char *name); +int bpf_object__section_size(const struct bpf_object *obj, const char *name, + __u32 *size); +int bpf_object__variable_offset(const struct bpf_object *obj, const char *name, + __u32 *off); LIBBPF_API int bpf_object__pin_maps(struct bpf_object *obj, const char *path); LIBBPF_API int bpf_object__unpin_maps(struct bpf_object *obj, const char *path); @@ -301,6 +305,7 @@ LIBBPF_API void *bpf_map__priv(struct bpf_map *map); LIBBPF_API int bpf_map__reuse_fd(struct bpf_map *map, int fd); LIBBPF_API int bpf_map__resize(struct bpf_map *map, __u32 max_entries); LIBBPF_API bool bpf_map__is_offload_neutral(struct bpf_map *map); +LIBBPF_API bool bpf_map__is_internal(struct bpf_map *map); LIBBPF_API void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex); LIBBPF_API int bpf_map__pin(struct bpf_map *map, const char *path); LIBBPF_API int bpf_map__unpin(struct bpf_map *map, const char *path); @@ -314,6 +319,7 @@ struct bpf_prog_load_attr { enum bpf_prog_type prog_type; enum bpf_attach_type expected_attach_type; int ifindex; + int log_level; }; LIBBPF_API int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index f3ce50500cf2..673001787cba 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -157,3 +157,10 @@ LIBBPF_0.0.2 { bpf_program__bpil_addr_to_offs; bpf_program__bpil_offs_to_addr; } LIBBPF_0.0.1; + +LIBBPF_0.0.3 { + global: + bpf_map__is_internal; + bpf_map_freeze; + btf__finalize_data; +} LIBBPF_0.0.2; diff --git a/tools/lib/bpf/libbpf.pc.template b/tools/lib/bpf/libbpf.pc.template new file mode 100644 index 000000000000..ac17fcef2108 --- /dev/null +++ b/tools/lib/bpf/libbpf.pc.template @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) + +prefix=@PREFIX@ +libdir=@LIBDIR@ +includedir=${prefix}/include + +Name: libbpf +Description: BPF library +Version: @VERSION@ +Libs: -L${libdir} -lbpf +Requires.private: libelf +Cflags: -I${includedir} diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h new file mode 100644 index 000000000000..789e435b5900 --- /dev/null +++ b/tools/lib/bpf/libbpf_internal.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ + +/* + * Internal libbpf helpers. + * + * Copyright (c) 2019 Facebook + */ + +#ifndef __LIBBPF_LIBBPF_INTERNAL_H +#define __LIBBPF_LIBBPF_INTERNAL_H + +#define BTF_INFO_ENC(kind, kind_flag, vlen) \ + ((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN)) +#define BTF_TYPE_ENC(name, info, size_or_type) (name), (info), (size_or_type) +#define BTF_INT_ENC(encoding, bits_offset, nr_bits) \ + ((encoding) << 24 | (bits_offset) << 16 | (nr_bits)) +#define BTF_TYPE_INT_ENC(name, encoding, bits_offset, bits, sz) \ + BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_INT, 0, 0), sz), \ + BTF_INT_ENC(encoding, bits_offset, bits) +#define BTF_MEMBER_ENC(name, type, bits_offset) (name), (type), (bits_offset) +#define BTF_PARAM_ENC(name, type) (name), (type) +#define BTF_VAR_SECINFO_ENC(type, offset, size) (type), (offset), (size) + +int libbpf__probe_raw_btf(const char *raw_types, size_t types_len, + const char *str_sec, size_t str_len); + +#endif /* __LIBBPF_LIBBPF_INTERNAL_H */ diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c index 8c3a1c04dcb2..5e2aa83f637a 100644 --- a/tools/lib/bpf/libbpf_probes.c +++ b/tools/lib/bpf/libbpf_probes.c @@ -9,11 +9,13 @@ #include <net/if.h> #include <sys/utsname.h> +#include <linux/btf.h> #include <linux/filter.h> #include <linux/kernel.h> #include "bpf.h" #include "libbpf.h" +#include "libbpf_internal.h" static bool grep(const char *buffer, const char *pattern) { @@ -93,10 +95,12 @@ probe_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns, case BPF_PROG_TYPE_CGROUP_DEVICE: case BPF_PROG_TYPE_SK_MSG: case BPF_PROG_TYPE_RAW_TRACEPOINT: + case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE: case BPF_PROG_TYPE_LWT_SEG6LOCAL: case BPF_PROG_TYPE_LIRC_MODE2: case BPF_PROG_TYPE_SK_REUSEPORT: case BPF_PROG_TYPE_FLOW_DISSECTOR: + case BPF_PROG_TYPE_CGROUP_SYSCTL: default: break; } @@ -129,11 +133,73 @@ bool bpf_probe_prog_type(enum bpf_prog_type prog_type, __u32 ifindex) return errno != EINVAL && errno != EOPNOTSUPP; } +int libbpf__probe_raw_btf(const char *raw_types, size_t types_len, + const char *str_sec, size_t str_len) +{ + struct btf_header hdr = { + .magic = BTF_MAGIC, + .version = BTF_VERSION, + .hdr_len = sizeof(struct btf_header), + .type_len = types_len, + .str_off = types_len, + .str_len = str_len, + }; + int btf_fd, btf_len; + __u8 *raw_btf; + + btf_len = hdr.hdr_len + hdr.type_len + hdr.str_len; + raw_btf = malloc(btf_len); + if (!raw_btf) + return -ENOMEM; + + memcpy(raw_btf, &hdr, sizeof(hdr)); + memcpy(raw_btf + hdr.hdr_len, raw_types, hdr.type_len); + memcpy(raw_btf + hdr.hdr_len + hdr.type_len, str_sec, hdr.str_len); + + btf_fd = bpf_load_btf(raw_btf, btf_len, NULL, 0, false); + if (btf_fd < 0) { + free(raw_btf); + return 0; + } + + close(btf_fd); + free(raw_btf); + return 1; +} + +static int load_sk_storage_btf(void) +{ + const char strs[] = "\0bpf_spin_lock\0val\0cnt\0l"; + /* struct bpf_spin_lock { + * int val; + * }; + * struct val { + * int cnt; + * struct bpf_spin_lock l; + * }; + */ + __u32 types[] = { + /* int */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + /* struct bpf_spin_lock */ /* [2] */ + BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 1), 4), + BTF_MEMBER_ENC(15, 1, 0), /* int val; */ + /* struct val */ /* [3] */ + BTF_TYPE_ENC(15, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), 8), + BTF_MEMBER_ENC(19, 1, 0), /* int cnt; */ + BTF_MEMBER_ENC(23, 2, 32),/* struct bpf_spin_lock l; */ + }; + + return libbpf__probe_raw_btf((char *)types, sizeof(types), + strs, sizeof(strs)); +} + bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex) { int key_size, value_size, max_entries, map_flags; + __u32 btf_key_type_id = 0, btf_value_type_id = 0; struct bpf_create_map_attr attr = {}; - int fd = -1, fd_inner; + int fd = -1, btf_fd = -1, fd_inner; key_size = sizeof(__u32); value_size = sizeof(__u32); @@ -159,6 +225,16 @@ bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex) case BPF_MAP_TYPE_STACK: key_size = 0; break; + case BPF_MAP_TYPE_SK_STORAGE: + btf_key_type_id = 1; + btf_value_type_id = 3; + value_size = 8; + max_entries = 0; + map_flags = BPF_F_NO_PREALLOC; + btf_fd = load_sk_storage_btf(); + if (btf_fd < 0) + return false; + break; case BPF_MAP_TYPE_UNSPEC: case BPF_MAP_TYPE_HASH: case BPF_MAP_TYPE_ARRAY: @@ -204,11 +280,18 @@ bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex) attr.max_entries = max_entries; attr.map_flags = map_flags; attr.map_ifindex = ifindex; + if (btf_fd >= 0) { + attr.btf_fd = btf_fd; + attr.btf_key_type_id = btf_key_type_id; + attr.btf_value_type_id = btf_value_type_id; + } fd = bpf_create_map_xattr(&attr); } if (fd >= 0) close(fd); + if (btf_fd >= 0) + close(btf_fd); return fd >= 0; } diff --git a/tools/lib/bpf/libbpf_util.h b/tools/lib/bpf/libbpf_util.h index 81ecda0cb9c9..da94c4cb2e4d 100644 --- a/tools/lib/bpf/libbpf_util.h +++ b/tools/lib/bpf/libbpf_util.h @@ -23,6 +23,36 @@ do { \ #define pr_info(fmt, ...) __pr(LIBBPF_INFO, fmt, ##__VA_ARGS__) #define pr_debug(fmt, ...) __pr(LIBBPF_DEBUG, fmt, ##__VA_ARGS__) +/* Use these barrier functions instead of smp_[rw]mb() when they are + * used in a libbpf header file. That way they can be built into the + * application that uses libbpf. + */ +#if defined(__i386__) || defined(__x86_64__) +# define libbpf_smp_rmb() asm volatile("" : : : "memory") +# define libbpf_smp_wmb() asm volatile("" : : : "memory") +# define libbpf_smp_mb() \ + asm volatile("lock; addl $0,-4(%%rsp)" : : : "memory", "cc") +/* Hinders stores to be observed before older loads. */ +# define libbpf_smp_rwmb() asm volatile("" : : : "memory") +#elif defined(__aarch64__) +# define libbpf_smp_rmb() asm volatile("dmb ishld" : : : "memory") +# define libbpf_smp_wmb() asm volatile("dmb ishst" : : : "memory") +# define libbpf_smp_mb() asm volatile("dmb ish" : : : "memory") +# define libbpf_smp_rwmb() libbpf_smp_mb() +#elif defined(__arm__) +/* These are only valid for armv7 and above */ +# define libbpf_smp_rmb() asm volatile("dmb ish" : : : "memory") +# define libbpf_smp_wmb() asm volatile("dmb ishst" : : : "memory") +# define libbpf_smp_mb() asm volatile("dmb ish" : : : "memory") +# define libbpf_smp_rwmb() libbpf_smp_mb() +#else +/* Architecture missing native barrier functions. */ +# define libbpf_smp_rmb() __sync_synchronize() +# define libbpf_smp_wmb() __sync_synchronize() +# define libbpf_smp_mb() __sync_synchronize() +# define libbpf_smp_rwmb() __sync_synchronize() +#endif + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/tools/lib/bpf/xsk.c b/tools/lib/bpf/xsk.c index 8d0078b65486..a3d1a302bc9c 100644 --- a/tools/lib/bpf/xsk.c +++ b/tools/lib/bpf/xsk.c @@ -248,8 +248,7 @@ int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, __u64 size, return 0; out_mmap: - munmap(umem->fill, - off.fr.desc + umem->config.fill_size * sizeof(__u64)); + munmap(map, off.fr.desc + umem->config.fill_size * sizeof(__u64)); out_socket: close(umem->fd); out_umem_alloc: @@ -259,7 +258,8 @@ out_umem_alloc: static int xsk_load_xdp_prog(struct xsk_socket *xsk) { - char bpf_log_buf[BPF_LOG_BUF_SIZE]; + static const int log_buf_size = 16 * 1024; + char log_buf[log_buf_size]; int err, prog_fd; /* This is the C-program: @@ -308,10 +308,10 @@ static int xsk_load_xdp_prog(struct xsk_socket *xsk) size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn); prog_fd = bpf_load_program(BPF_PROG_TYPE_XDP, prog, insns_cnt, - "LGPL-2.1 or BSD-2-Clause", 0, bpf_log_buf, - BPF_LOG_BUF_SIZE); + "LGPL-2.1 or BSD-2-Clause", 0, log_buf, + log_buf_size); if (prog_fd < 0) { - pr_warning("BPF log buffer:\n%s", bpf_log_buf); + pr_warning("BPF log buffer:\n%s", log_buf); return prog_fd; } @@ -387,21 +387,17 @@ static void xsk_delete_bpf_maps(struct xsk_socket *xsk) { close(xsk->qidconf_map_fd); close(xsk->xsks_map_fd); + xsk->qidconf_map_fd = -1; + xsk->xsks_map_fd = -1; } -static int xsk_update_bpf_maps(struct xsk_socket *xsk, int qidconf_value, - int xsks_value) +static int xsk_lookup_bpf_maps(struct xsk_socket *xsk) { - bool qidconf_map_updated = false, xsks_map_updated = false; + __u32 i, *map_ids, num_maps, prog_len = sizeof(struct bpf_prog_info); + __u32 map_len = sizeof(struct bpf_map_info); struct bpf_prog_info prog_info = {}; - __u32 prog_len = sizeof(prog_info); struct bpf_map_info map_info; - __u32 map_len = sizeof(map_info); - __u32 *map_ids; - int reset_value = 0; - __u32 num_maps; - unsigned int i; - int err; + int fd, err; err = bpf_obj_get_info_by_fd(xsk->prog_fd, &prog_info, &prog_len); if (err) @@ -422,66 +418,71 @@ static int xsk_update_bpf_maps(struct xsk_socket *xsk, int qidconf_value, goto out_map_ids; for (i = 0; i < prog_info.nr_map_ids; i++) { - int fd; + if (xsk->qidconf_map_fd != -1 && xsk->xsks_map_fd != -1) + break; fd = bpf_map_get_fd_by_id(map_ids[i]); - if (fd < 0) { - err = -errno; - goto out_maps; - } + if (fd < 0) + continue; err = bpf_obj_get_info_by_fd(fd, &map_info, &map_len); - if (err) - goto out_maps; + if (err) { + close(fd); + continue; + } if (!strcmp(map_info.name, "qidconf_map")) { - err = bpf_map_update_elem(fd, &xsk->queue_id, - &qidconf_value, 0); - if (err) - goto out_maps; - qidconf_map_updated = true; xsk->qidconf_map_fd = fd; - } else if (!strcmp(map_info.name, "xsks_map")) { - err = bpf_map_update_elem(fd, &xsk->queue_id, - &xsks_value, 0); - if (err) - goto out_maps; - xsks_map_updated = true; + continue; + } + + if (!strcmp(map_info.name, "xsks_map")) { xsk->xsks_map_fd = fd; + continue; } - if (qidconf_map_updated && xsks_map_updated) - break; + close(fd); } - if (!(qidconf_map_updated && xsks_map_updated)) { + err = 0; + if (xsk->qidconf_map_fd < 0 || xsk->xsks_map_fd < 0) { err = -ENOENT; - goto out_maps; + xsk_delete_bpf_maps(xsk); } - err = 0; - goto out_success; - -out_maps: - if (qidconf_map_updated) - (void)bpf_map_update_elem(xsk->qidconf_map_fd, &xsk->queue_id, - &reset_value, 0); - if (xsks_map_updated) - (void)bpf_map_update_elem(xsk->xsks_map_fd, &xsk->queue_id, - &reset_value, 0); -out_success: - if (qidconf_map_updated) - close(xsk->qidconf_map_fd); - if (xsks_map_updated) - close(xsk->xsks_map_fd); out_map_ids: free(map_ids); return err; } +static void xsk_clear_bpf_maps(struct xsk_socket *xsk) +{ + int qid = false; + + bpf_map_update_elem(xsk->qidconf_map_fd, &xsk->queue_id, &qid, 0); + bpf_map_delete_elem(xsk->xsks_map_fd, &xsk->queue_id); +} + +static int xsk_set_bpf_maps(struct xsk_socket *xsk) +{ + int qid = true, fd = xsk->fd, err; + + err = bpf_map_update_elem(xsk->qidconf_map_fd, &xsk->queue_id, &qid, 0); + if (err) + goto out; + + err = bpf_map_update_elem(xsk->xsks_map_fd, &xsk->queue_id, &fd, 0); + if (err) + goto out; + + return 0; +out: + xsk_clear_bpf_maps(xsk); + return err; +} + static int xsk_setup_xdp_prog(struct xsk_socket *xsk) { - bool prog_attached = false; __u32 prog_id = 0; int err; @@ -491,7 +492,6 @@ static int xsk_setup_xdp_prog(struct xsk_socket *xsk) return err; if (!prog_id) { - prog_attached = true; err = xsk_create_bpf_maps(xsk); if (err) return err; @@ -501,20 +501,21 @@ static int xsk_setup_xdp_prog(struct xsk_socket *xsk) goto out_maps; } else { xsk->prog_fd = bpf_prog_get_fd_by_id(prog_id); + err = xsk_lookup_bpf_maps(xsk); + if (err) + goto out_load; } - err = xsk_update_bpf_maps(xsk, true, xsk->fd); + err = xsk_set_bpf_maps(xsk); if (err) goto out_load; return 0; out_load: - if (prog_attached) - close(xsk->prog_fd); + close(xsk->prog_fd); out_maps: - if (prog_attached) - xsk_delete_bpf_maps(xsk); + xsk_delete_bpf_maps(xsk); return err; } @@ -523,11 +524,11 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname, struct xsk_ring_cons *rx, struct xsk_ring_prod *tx, const struct xsk_socket_config *usr_config) { + void *rx_map = NULL, *tx_map = NULL; struct sockaddr_xdp sxdp = {}; struct xdp_mmap_offsets off; struct xsk_socket *xsk; socklen_t optlen; - void *map; int err; if (!umem || !xsk_ptr || !rx || !tx) @@ -593,40 +594,40 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname, } if (rx) { - map = xsk_mmap(NULL, off.rx.desc + - xsk->config.rx_size * sizeof(struct xdp_desc), - PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_POPULATE, - xsk->fd, XDP_PGOFF_RX_RING); - if (map == MAP_FAILED) { + rx_map = xsk_mmap(NULL, off.rx.desc + + xsk->config.rx_size * sizeof(struct xdp_desc), + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_POPULATE, + xsk->fd, XDP_PGOFF_RX_RING); + if (rx_map == MAP_FAILED) { err = -errno; goto out_socket; } rx->mask = xsk->config.rx_size - 1; rx->size = xsk->config.rx_size; - rx->producer = map + off.rx.producer; - rx->consumer = map + off.rx.consumer; - rx->ring = map + off.rx.desc; + rx->producer = rx_map + off.rx.producer; + rx->consumer = rx_map + off.rx.consumer; + rx->ring = rx_map + off.rx.desc; } xsk->rx = rx; if (tx) { - map = xsk_mmap(NULL, off.tx.desc + - xsk->config.tx_size * sizeof(struct xdp_desc), - PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_POPULATE, - xsk->fd, XDP_PGOFF_TX_RING); - if (map == MAP_FAILED) { + tx_map = xsk_mmap(NULL, off.tx.desc + + xsk->config.tx_size * sizeof(struct xdp_desc), + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_POPULATE, + xsk->fd, XDP_PGOFF_TX_RING); + if (tx_map == MAP_FAILED) { err = -errno; goto out_mmap_rx; } tx->mask = xsk->config.tx_size - 1; tx->size = xsk->config.tx_size; - tx->producer = map + off.tx.producer; - tx->consumer = map + off.tx.consumer; - tx->ring = map + off.tx.desc; + tx->producer = tx_map + off.tx.producer; + tx->consumer = tx_map + off.tx.consumer; + tx->ring = tx_map + off.tx.desc; tx->cached_cons = xsk->config.tx_size; } xsk->tx = tx; @@ -642,6 +643,9 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname, goto out_mmap_tx; } + xsk->qidconf_map_fd = -1; + xsk->xsks_map_fd = -1; + if (!(xsk->config.libbpf_flags & XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD)) { err = xsk_setup_xdp_prog(xsk); if (err) @@ -653,13 +657,11 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname, out_mmap_tx: if (tx) - munmap(xsk->tx, - off.tx.desc + + munmap(tx_map, off.tx.desc + xsk->config.tx_size * sizeof(struct xdp_desc)); out_mmap_rx: if (rx) - munmap(xsk->rx, - off.rx.desc + + munmap(rx_map, off.rx.desc + xsk->config.rx_size * sizeof(struct xdp_desc)); out_socket: if (--umem->refcount) @@ -684,9 +686,9 @@ int xsk_umem__delete(struct xsk_umem *umem) optlen = sizeof(off); err = getsockopt(umem->fd, SOL_XDP, XDP_MMAP_OFFSETS, &off, &optlen); if (!err) { - munmap(umem->fill->ring, + munmap(umem->fill->ring - off.fr.desc, off.fr.desc + umem->config.fill_size * sizeof(__u64)); - munmap(umem->comp->ring, + munmap(umem->comp->ring - off.cr.desc, off.cr.desc + umem->config.comp_size * sizeof(__u64)); } @@ -698,6 +700,7 @@ int xsk_umem__delete(struct xsk_umem *umem) void xsk_socket__delete(struct xsk_socket *xsk) { + size_t desc_sz = sizeof(struct xdp_desc); struct xdp_mmap_offsets off; socklen_t optlen; int err; @@ -705,19 +708,21 @@ void xsk_socket__delete(struct xsk_socket *xsk) if (!xsk) return; - (void)xsk_update_bpf_maps(xsk, 0, 0); + xsk_clear_bpf_maps(xsk); + xsk_delete_bpf_maps(xsk); optlen = sizeof(off); err = getsockopt(xsk->fd, SOL_XDP, XDP_MMAP_OFFSETS, &off, &optlen); if (!err) { - if (xsk->rx) - munmap(xsk->rx->ring, - off.rx.desc + - xsk->config.rx_size * sizeof(struct xdp_desc)); - if (xsk->tx) - munmap(xsk->tx->ring, - off.tx.desc + - xsk->config.tx_size * sizeof(struct xdp_desc)); + if (xsk->rx) { + munmap(xsk->rx->ring - off.rx.desc, + off.rx.desc + xsk->config.rx_size * desc_sz); + } + if (xsk->tx) { + munmap(xsk->tx->ring - off.tx.desc, + off.tx.desc + xsk->config.tx_size * desc_sz); + } + } xsk->umem->refcount--; diff --git a/tools/lib/bpf/xsk.h b/tools/lib/bpf/xsk.h index a497f00e2962..82ea71a0f3ec 100644 --- a/tools/lib/bpf/xsk.h +++ b/tools/lib/bpf/xsk.h @@ -16,6 +16,7 @@ #include <linux/if_xdp.h> #include "libbpf.h" +#include "libbpf_util.h" #ifdef __cplusplus extern "C" { @@ -36,6 +37,10 @@ struct name { \ DEFINE_XSK_RING(xsk_ring_prod); DEFINE_XSK_RING(xsk_ring_cons); +/* For a detailed explanation on the memory barriers associated with the + * ring, please take a look at net/xdp/xsk_queue.h. + */ + struct xsk_umem; struct xsk_socket; @@ -105,7 +110,7 @@ static inline __u32 xsk_cons_nb_avail(struct xsk_ring_cons *r, __u32 nb) static inline size_t xsk_ring_prod__reserve(struct xsk_ring_prod *prod, size_t nb, __u32 *idx) { - if (unlikely(xsk_prod_nb_free(prod, nb) < nb)) + if (xsk_prod_nb_free(prod, nb) < nb) return 0; *idx = prod->cached_prod; @@ -116,10 +121,10 @@ static inline size_t xsk_ring_prod__reserve(struct xsk_ring_prod *prod, static inline void xsk_ring_prod__submit(struct xsk_ring_prod *prod, size_t nb) { - /* Make sure everything has been written to the ring before signalling - * this to the kernel. + /* Make sure everything has been written to the ring before indicating + * this to the kernel by writing the producer pointer. */ - smp_wmb(); + libbpf_smp_wmb(); *prod->producer += nb; } @@ -129,11 +134,11 @@ static inline size_t xsk_ring_cons__peek(struct xsk_ring_cons *cons, { size_t entries = xsk_cons_nb_avail(cons, nb); - if (likely(entries > 0)) { + if (entries > 0) { /* Make sure we do not speculatively read the data before * we have received the packet buffers from the ring. */ - smp_rmb(); + libbpf_smp_rmb(); *idx = cons->cached_cons; cons->cached_cons += entries; @@ -144,6 +149,11 @@ static inline size_t xsk_ring_cons__peek(struct xsk_ring_cons *cons, static inline void xsk_ring_cons__release(struct xsk_ring_cons *cons, size_t nb) { + /* Make sure data has been read before indicating we are done + * with the entries by updating the consumer pointer. + */ + libbpf_smp_rwmb(); + *cons->consumer += nb; } diff --git a/tools/lib/traceevent/Documentation/Makefile b/tools/lib/traceevent/Documentation/Makefile new file mode 100644 index 000000000000..aa72ab96c3c1 --- /dev/null +++ b/tools/lib/traceevent/Documentation/Makefile @@ -0,0 +1,207 @@ +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 $@+ $@ diff --git a/tools/lib/traceevent/Documentation/asciidoc.conf b/tools/lib/traceevent/Documentation/asciidoc.conf new file mode 100644 index 000000000000..07595717f06e --- /dev/null +++ b/tools/lib/traceevent/Documentation/asciidoc.conf @@ -0,0 +1,120 @@ +## linktep: macro +# +# Usage: linktep:command[manpage-section] +# +# Note, {0} is the manpage section, while {target} is the command. +# +# Show TEP link as: <command>(<section>); if section is defined, else just show +# the command. + +[macros] +(?su)[\\]?(?P<name>linktep):(?P<target>\S*?)\[(?P<attrlist>.*?)\]= + +[attributes] +asterisk=* +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[] diff --git a/tools/lib/traceevent/Documentation/libtraceevent-commands.txt b/tools/lib/traceevent/Documentation/libtraceevent-commands.txt new file mode 100644 index 000000000000..bec552001f8e --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-commands.txt @@ -0,0 +1,153 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-cpus.txt b/tools/lib/traceevent/Documentation/libtraceevent-cpus.txt new file mode 100644 index 000000000000..5ad70e43b752 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-cpus.txt @@ -0,0 +1,77 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-endian_read.txt b/tools/lib/traceevent/Documentation/libtraceevent-endian_read.txt new file mode 100644 index 000000000000..e64851b6e189 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-endian_read.txt @@ -0,0 +1,78 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-event_find.txt b/tools/lib/traceevent/Documentation/libtraceevent-event_find.txt new file mode 100644 index 000000000000..7bc062c9f76f --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-event_find.txt @@ -0,0 +1,103 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-event_get.txt b/tools/lib/traceevent/Documentation/libtraceevent-event_get.txt new file mode 100644 index 000000000000..6525092fc417 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-event_get.txt @@ -0,0 +1,99 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-event_list.txt b/tools/lib/traceevent/Documentation/libtraceevent-event_list.txt new file mode 100644 index 000000000000..fba350e5a4cb --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-event_list.txt @@ -0,0 +1,122 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-field_find.txt b/tools/lib/traceevent/Documentation/libtraceevent-field_find.txt new file mode 100644 index 000000000000..0896af5b9eff --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-field_find.txt @@ -0,0 +1,118 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-field_get_val.txt b/tools/lib/traceevent/Documentation/libtraceevent-field_get_val.txt new file mode 100644 index 000000000000..6324f0d48aeb --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-field_get_val.txt @@ -0,0 +1,122 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-field_print.txt b/tools/lib/traceevent/Documentation/libtraceevent-field_print.txt new file mode 100644 index 000000000000..9a9df98ac44d --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-field_print.txt @@ -0,0 +1,126 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-field_read.txt b/tools/lib/traceevent/Documentation/libtraceevent-field_read.txt new file mode 100644 index 000000000000..64e9e25d3fd9 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-field_read.txt @@ -0,0 +1,81 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-fields.txt b/tools/lib/traceevent/Documentation/libtraceevent-fields.txt new file mode 100644 index 000000000000..1ccb531d5114 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-fields.txt @@ -0,0 +1,105 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-file_endian.txt b/tools/lib/traceevent/Documentation/libtraceevent-file_endian.txt new file mode 100644 index 000000000000..f401ad311047 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-file_endian.txt @@ -0,0 +1,91 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-filter.txt b/tools/lib/traceevent/Documentation/libtraceevent-filter.txt new file mode 100644 index 000000000000..4a9962d8cb59 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-filter.txt @@ -0,0 +1,209 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-func_apis.txt b/tools/lib/traceevent/Documentation/libtraceevent-func_apis.txt new file mode 100644 index 000000000000..38bfea30a5f6 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-func_apis.txt @@ -0,0 +1,183 @@ +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 "%pF" or "%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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-func_find.txt b/tools/lib/traceevent/Documentation/libtraceevent-func_find.txt new file mode 100644 index 000000000000..04840e244445 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-func_find.txt @@ -0,0 +1,88 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-handle.txt b/tools/lib/traceevent/Documentation/libtraceevent-handle.txt new file mode 100644 index 000000000000..8d568316847d --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-handle.txt @@ -0,0 +1,101 @@ +libtraceevent(3) +================ + +NAME +---- +tep_alloc, tep_free,tep_ref, tep_unref,tep_ref_get - 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_ref_get*(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_ref_get(tep); +tep_ref(tep); +if ( (ref+1) != tep_ref_get(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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-header_page.txt b/tools/lib/traceevent/Documentation/libtraceevent-header_page.txt new file mode 100644 index 000000000000..615d117dc39f --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-header_page.txt @@ -0,0 +1,102 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-host_endian.txt b/tools/lib/traceevent/Documentation/libtraceevent-host_endian.txt new file mode 100644 index 000000000000..d5d375eb8d1e --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-host_endian.txt @@ -0,0 +1,104 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-long_size.txt b/tools/lib/traceevent/Documentation/libtraceevent-long_size.txt new file mode 100644 index 000000000000..01d78ea2519a --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-long_size.txt @@ -0,0 +1,78 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-page_size.txt b/tools/lib/traceevent/Documentation/libtraceevent-page_size.txt new file mode 100644 index 000000000000..452c0cfa1822 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-page_size.txt @@ -0,0 +1,82 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-parse_event.txt b/tools/lib/traceevent/Documentation/libtraceevent-parse_event.txt new file mode 100644 index 000000000000..f248114ca1ff --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-parse_event.txt @@ -0,0 +1,90 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-parse_head.txt b/tools/lib/traceevent/Documentation/libtraceevent-parse_head.txt new file mode 100644 index 000000000000..c90f16c7d8e6 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-parse_head.txt @@ -0,0 +1,82 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-record_parse.txt b/tools/lib/traceevent/Documentation/libtraceevent-record_parse.txt new file mode 100644 index 000000000000..e9a69116c78b --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-record_parse.txt @@ -0,0 +1,137 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-reg_event_handler.txt b/tools/lib/traceevent/Documentation/libtraceevent-reg_event_handler.txt new file mode 100644 index 000000000000..53d37d72a1c1 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-reg_event_handler.txt @@ -0,0 +1,156 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-reg_print_func.txt b/tools/lib/traceevent/Documentation/libtraceevent-reg_print_func.txt new file mode 100644 index 000000000000..708dce91ebd8 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-reg_print_func.txt @@ -0,0 +1,155 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-set_flag.txt b/tools/lib/traceevent/Documentation/libtraceevent-set_flag.txt new file mode 100644 index 000000000000..b0599780b9a6 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-set_flag.txt @@ -0,0 +1,104 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-strerror.txt b/tools/lib/traceevent/Documentation/libtraceevent-strerror.txt new file mode 100644 index 000000000000..ee4062a00c9f --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-strerror.txt @@ -0,0 +1,85 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent-tseq.txt b/tools/lib/traceevent/Documentation/libtraceevent-tseq.txt new file mode 100644 index 000000000000..8ac6aa174e12 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-tseq.txt @@ -0,0 +1,158 @@ +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 diff --git a/tools/lib/traceevent/Documentation/libtraceevent.txt b/tools/lib/traceevent/Documentation/libtraceevent.txt new file mode 100644 index 000000000000..fbd977b47de1 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent.txt @@ -0,0 +1,203 @@ +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_ref_get*(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_); + bool *tep_is_latency_format*(struct tep_handle pass:[*]_tep_); + void *tep_set_latency_format*(struct tep_handle pass:[*]_tep_, int _lat_); + 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_trace_clock*(struct tep_handle pass:[*]_tep_, const char pass:[*]_trace_clock_); + 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_); + +Event printing: + void *tep_print_event*(struct tep_handle pass:[*]_tep_, struct trace_seq pass:[*]_s_, struct tep_record pass:[*]_record_, bool _use_trace_clock_); + void *tep_print_event_data*(struct tep_handle pass:[*]_tep_, struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, struct tep_record pass:[*]_record_); + void *tep_event_info*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, struct tep_record pass:[*]_record_); + void *tep_print_event_task*(struct tep_handle pass:[*]_tep_, struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, struct tep_record pass:[*]_record_); + void *tep_print_event_time*(struct tep_handle pass:[*]_tep_, struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, struct tep_record pass:[*]record, bool _use_trace_clock_); + void *tep_set_print_raw*(struct tep_handle pass:[*]_tep_, int _print_raw_); + +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: + void *tep_data_latency_format*(struct tep_handle pass:[*]_tep_, struct trace_seq pass:[*]_s_, struct tep_record pass:[*]_record_); + 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 diff --git a/tools/lib/traceevent/Documentation/manpage-1.72.xsl b/tools/lib/traceevent/Documentation/manpage-1.72.xsl new file mode 100644 index 000000000000..b4d315cb8c47 --- /dev/null +++ b/tools/lib/traceevent/Documentation/manpage-1.72.xsl @@ -0,0 +1,14 @@ +<!-- manpage-1.72.xsl: + special settings for manpages rendered from asciidoc+docbook + handles peculiarities in docbook-xsl 1.72.0 --> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version="1.0"> + +<xsl:import href="manpage-base.xsl"/> + +<!-- these are the special values for the roff control characters + needed for docbook-xsl 1.72.0 --> +<xsl:param name="git.docbook.backslash">▓</xsl:param> +<xsl:param name="git.docbook.dot" >⌂</xsl:param> + +</xsl:stylesheet> diff --git a/tools/lib/traceevent/Documentation/manpage-base.xsl b/tools/lib/traceevent/Documentation/manpage-base.xsl new file mode 100644 index 000000000000..a264fa616093 --- /dev/null +++ b/tools/lib/traceevent/Documentation/manpage-base.xsl @@ -0,0 +1,35 @@ +<!-- manpage-base.xsl: + special formatting for manpages rendered from asciidoc+docbook --> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version="1.0"> + +<!-- these params silence some output from xmlto --> +<xsl:param name="man.output.quietly" select="1"/> +<xsl:param name="refentry.meta.get.quietly" select="1"/> + +<!-- convert asciidoc callouts to man page format; + git.docbook.backslash and git.docbook.dot params + must be supplied by another XSL file or other means --> +<xsl:template match="co"> + <xsl:value-of select="concat( + $git.docbook.backslash,'fB(', + substring-after(@id,'-'),')', + $git.docbook.backslash,'fR')"/> +</xsl:template> +<xsl:template match="calloutlist"> + <xsl:value-of select="$git.docbook.dot"/> + <xsl:text>sp </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> diff --git a/tools/lib/traceevent/Documentation/manpage-bold-literal.xsl b/tools/lib/traceevent/Documentation/manpage-bold-literal.xsl new file mode 100644 index 000000000000..608eb5df6281 --- /dev/null +++ b/tools/lib/traceevent/Documentation/manpage-bold-literal.xsl @@ -0,0 +1,17 @@ +<!-- manpage-bold-literal.xsl: + special formatting for manpages rendered from asciidoc+docbook --> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version="1.0"> + +<!-- render literal text as bold (instead of plain or monospace); + this makes literal text easier to distinguish in manpages + viewed on a tty --> +<xsl:template match="literal"> + <xsl:value-of select="$git.docbook.backslash"/> + <xsl:text>fB</xsl:text> + <xsl:apply-templates/> + <xsl:value-of select="$git.docbook.backslash"/> + <xsl:text>fR</xsl:text> +</xsl:template> + +</xsl:stylesheet> diff --git a/tools/lib/traceevent/Documentation/manpage-normal.xsl b/tools/lib/traceevent/Documentation/manpage-normal.xsl new file mode 100644 index 000000000000..a48f5b11f3dc --- /dev/null +++ b/tools/lib/traceevent/Documentation/manpage-normal.xsl @@ -0,0 +1,13 @@ +<!-- manpage-normal.xsl: + special settings for manpages rendered from asciidoc+docbook + handles anything we want to keep away from docbook-xsl 1.72.0 --> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version="1.0"> + +<xsl:import href="manpage-base.xsl"/> + +<!-- these are the normal values for the roff control characters --> +<xsl:param name="git.docbook.backslash">\</xsl:param> +<xsl:param name="git.docbook.dot" >.</xsl:param> + +</xsl:stylesheet> diff --git a/tools/lib/traceevent/Documentation/manpage-suppress-sp.xsl b/tools/lib/traceevent/Documentation/manpage-suppress-sp.xsl new file mode 100644 index 000000000000..a63c7632a87d --- /dev/null +++ b/tools/lib/traceevent/Documentation/manpage-suppress-sp.xsl @@ -0,0 +1,21 @@ +<!-- manpage-suppress-sp.xsl: + special settings for manpages rendered from asciidoc+docbook + handles erroneous, inline .sp in manpage output of some + versions of docbook-xsl --> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version="1.0"> + +<!-- attempt to work around spurious .sp at the tail of the line + that some versions of docbook stylesheets seem to add --> +<xsl:template match="simpara"> + <xsl:variable name="content"> + <xsl:apply-templates/> + </xsl:variable> + <xsl:value-of select="normalize-space($content)"/> + <xsl:if test="not(ancestor::authorblurb) and + not(ancestor::personblurb)"> + <xsl:text> </xsl:text> + </xsl:if> +</xsl:template> + +</xsl:stylesheet> diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index 941761d9923d..3292c290654f 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile @@ -50,9 +50,13 @@ 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 set_plugin_dir := 1 @@ -279,6 +283,8 @@ define do_install_pkgconfig_file cp -f ${PKG_CONFIG_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; \ @@ -300,10 +306,10 @@ install_pkgconfig: install_headers: $(call QUIET_INSTALL, headers) \ - $(call do_install,event-parse.h,$(prefix)/include/traceevent,644); \ - $(call do_install,event-utils.h,$(prefix)/include/traceevent,644); \ - $(call do_install,trace-seq.h,$(prefix)/include/traceevent,644); \ - $(call do_install,kbuffer.h,$(prefix)/include/traceevent,644) + $(call do_install,event-parse.h,$(DESTDIR)$(includedir_SQ),644); \ + $(call do_install,event-utils.h,$(DESTDIR)$(includedir_SQ),644); \ + $(call do_install,trace-seq.h,$(DESTDIR)$(includedir_SQ),644); \ + $(call do_install,kbuffer.h,$(DESTDIR)$(includedir_SQ),644) install: install_lib @@ -313,6 +319,38 @@ clean: $(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 += force plugins force: diff --git a/tools/lib/traceevent/event-parse-api.c b/tools/lib/traceevent/event-parse-api.c index d463761a58f4..988587840c80 100644 --- a/tools/lib/traceevent/event-parse-api.c +++ b/tools/lib/traceevent/event-parse-api.c @@ -9,6 +9,22 @@ #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 * @@ -17,10 +33,7 @@ */ struct tep_event *tep_get_first_event(struct tep_handle *tep) { - if (tep && tep->events) - return tep->events[0]; - - return NULL; + return tep_get_event(tep, 0); } /** @@ -32,7 +45,7 @@ struct tep_event *tep_get_first_event(struct tep_handle *tep) */ int tep_get_events_count(struct tep_handle *tep) { - if(tep) + if (tep) return tep->nr_events; return 0; } @@ -43,19 +56,47 @@ int tep_get_events_count(struct tep_handle *tep) * @flag: flag, or combination of flags to be set * can be any combination from enum tep_flag * - * This sets a flag or mbination of flags 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) + if (tep) tep->flags |= flag; } -unsigned short tep_data2host2(struct tep_handle *pevent, unsigned short data) +/** + * 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; +} + +unsigned short tep_data2host2(struct tep_handle *tep, unsigned short data) { unsigned short swap; - if (!pevent || pevent->host_bigendian == pevent->file_bigendian) + if (!tep || tep->host_bigendian == tep->file_bigendian) return data; swap = ((data & 0xffULL) << 8) | @@ -64,11 +105,11 @@ unsigned short tep_data2host2(struct tep_handle *pevent, unsigned short data) return swap; } -unsigned int tep_data2host4(struct tep_handle *pevent, unsigned int data) +unsigned int tep_data2host4(struct tep_handle *tep, unsigned int data) { unsigned int swap; - if (!pevent || pevent->host_bigendian == pevent->file_bigendian) + if (!tep || tep->host_bigendian == tep->file_bigendian) return data; swap = ((data & 0xffULL) << 24) | @@ -80,11 +121,11 @@ unsigned int tep_data2host4(struct tep_handle *pevent, unsigned int data) } unsigned long long -tep_data2host8(struct tep_handle *pevent, unsigned long long data) +tep_data2host8(struct tep_handle *tep, unsigned long long data) { unsigned long long swap; - if (!pevent || pevent->host_bigendian == pevent->file_bigendian) + if (!tep || tep->host_bigendian == tep->file_bigendian) return data; swap = ((data & 0xffULL) << 56) | @@ -101,175 +142,232 @@ tep_data2host8(struct tep_handle *pevent, unsigned long long data) /** * tep_get_header_page_size - get size of the header page - * @pevent: a handle to the tep_handle + * @tep: a handle to the tep_handle * * This returns size of the header page - * If @pevent is NULL, 0 is returned. + * 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_page_size(struct tep_handle *pevent) +int tep_get_header_timestamp_size(struct tep_handle *tep) { - if(pevent) - return pevent->header_page_size_size; + if (tep) + return tep->header_page_ts_size; return 0; } /** * tep_get_cpus - get the number of CPUs - * @pevent: a handle to the tep_handle + * @tep: a handle to the tep_handle * * This returns the number of CPUs - * If @pevent is NULL, 0 is returned. + * If @tep is NULL, 0 is returned. */ -int tep_get_cpus(struct tep_handle *pevent) +int tep_get_cpus(struct tep_handle *tep) { - if(pevent) - return pevent->cpus; + if (tep) + return tep->cpus; return 0; } /** * tep_set_cpus - set the number of CPUs - * @pevent: a handle to the tep_handle + * @tep: a handle to the tep_handle * * This sets the number of CPUs */ -void tep_set_cpus(struct tep_handle *pevent, int cpus) +void tep_set_cpus(struct tep_handle *tep, int cpus) { - if(pevent) - pevent->cpus = cpus; + if (tep) + tep->cpus = cpus; } /** - * tep_get_long_size - get the size of a long integer on the current machine - * @pevent: a handle to the tep_handle + * 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 current machine - * If @pevent is NULL, 0 is returned. + * 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 *pevent) +int tep_get_long_size(struct tep_handle *tep) { - if(pevent) - return pevent->long_size; + if (tep) + return tep->long_size; return 0; } /** - * tep_set_long_size - set the size of a long integer on the current machine - * @pevent: a handle to the tep_handle + * 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 current machine + * This sets the size of a long integer on the traced machine */ -void tep_set_long_size(struct tep_handle *pevent, int long_size) +void tep_set_long_size(struct tep_handle *tep, int long_size) { - if(pevent) - pevent->long_size = long_size; + if (tep) + tep->long_size = long_size; } /** - * tep_get_page_size - get the size of a memory page on the current machine - * @pevent: a handle to the tep_handle + * 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 current machine - * If @pevent is NULL, 0 is returned. + * 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 *pevent) +int tep_get_page_size(struct tep_handle *tep) { - if(pevent) - return pevent->page_size; + if (tep) + return tep->page_size; return 0; } /** - * tep_set_page_size - set the size of a memory page on the current machine - * @pevent: a handle to the tep_handle + * 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 current machine + * This sets the size of a memory page on the traced machine */ -void tep_set_page_size(struct tep_handle *pevent, int _page_size) +void tep_set_page_size(struct tep_handle *tep, int _page_size) { - if(pevent) - pevent->page_size = _page_size; + if (tep) + tep->page_size = _page_size; } /** - * tep_file_bigendian - get if the file is in big endian order - * @pevent: a handle to the tep_handle + * tep_is_file_bigendian - return the endian of the file + * @tep: a handle to the tep_handle * - * This returns if the file is in big endian order - * If @pevent is NULL, 0 is returned. + * This returns true if the file is in big endian order + * If @tep is NULL, false is returned. */ -int tep_file_bigendian(struct tep_handle *pevent) +bool tep_is_file_bigendian(struct tep_handle *tep) { - if(pevent) - return pevent->file_bigendian; - return 0; + if (tep) + return (tep->file_bigendian == TEP_BIG_ENDIAN); + return false; } /** * tep_set_file_bigendian - set if the file is in big endian order - * @pevent: a handle to the tep_handle + * @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 *pevent, enum tep_endian endian) +void tep_set_file_bigendian(struct tep_handle *tep, enum tep_endian endian) { - if(pevent) - pevent->file_bigendian = endian; + if (tep) + tep->file_bigendian = endian; } /** - * tep_is_host_bigendian - get if the order of the current host is big endian - * @pevent: a handle to the tep_handle + * tep_is_local_bigendian - return the endian of the saved local machine + * @tep: a handle to the tep_handle * - * This gets if the order of the current host is big endian - * If @pevent is NULL, 0 is returned. + * This returns true if the saved local machine in @tep is big endian. + * If @tep is NULL, false is returned. */ -int tep_is_host_bigendian(struct tep_handle *pevent) +bool tep_is_local_bigendian(struct tep_handle *tep) { - if(pevent) - return pevent->host_bigendian; + if (tep) + return (tep->host_bigendian == TEP_BIG_ENDIAN); return 0; } /** - * tep_set_host_bigendian - set the order of the local host - * @pevent: a handle to the tep_handle + * 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 order of the local host + * This sets the endian order for the local machine. */ -void tep_set_host_bigendian(struct tep_handle *pevent, enum tep_endian endian) +void tep_set_local_bigendian(struct tep_handle *tep, enum tep_endian endian) { - if(pevent) - pevent->host_bigendian = endian; + if (tep) + tep->host_bigendian = endian; } /** * tep_is_latency_format - get if the latency output format is configured - * @pevent: a handle to the tep_handle + * @tep: a handle to the tep_handle * - * This gets if the latency output format is configured - * If @pevent is NULL, 0 is returned. + * This returns true if the latency output format is configured + * If @tep is NULL, false is returned. */ -int tep_is_latency_format(struct tep_handle *pevent) +bool tep_is_latency_format(struct tep_handle *tep) { - if(pevent) - return pevent->latency_format; - return 0; + if (tep) + return (tep->latency_format); + return false; } /** * tep_set_latency_format - set the latency output format - * @pevent: a handle to the tep_handle + * @tep: a handle to the tep_handle * @lat: non zero for latency output format * * This sets the latency output format */ -void tep_set_latency_format(struct tep_handle *pevent, int lat) +void tep_set_latency_format(struct tep_handle *tep, int lat) +{ + if (tep) + tep->latency_format = lat; +} + +/** + * 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_print_raw - set a flag to force print in raw format + * @tep: a handle to the tep_handle + * @print_raw: the new value of the print_raw flag + * + * This sets a flag to force print in raw format + */ +void tep_set_print_raw(struct tep_handle *tep, int print_raw) +{ + if (tep) + tep->print_raw = print_raw; +} + +/** + * 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(pevent) - pevent->latency_format = lat; + if (tep) + tep->test_filters = test_filters; } diff --git a/tools/lib/traceevent/event-parse-local.h b/tools/lib/traceevent/event-parse-local.h index 35833ee32d6c..09aa142f7fdd 100644 --- a/tools/lib/traceevent/event-parse-local.h +++ b/tools/lib/traceevent/event-parse-local.h @@ -92,8 +92,8 @@ struct tep_handle { void tep_free_event(struct tep_event *event); void tep_free_format_field(struct tep_format_field *field); -unsigned short tep_data2host2(struct tep_handle *pevent, unsigned short data); -unsigned int tep_data2host4(struct tep_handle *pevent, unsigned int data); -unsigned long long tep_data2host8(struct tep_handle *pevent, unsigned long long data); +unsigned short tep_data2host2(struct tep_handle *tep, unsigned short data); +unsigned int tep_data2host4(struct tep_handle *tep, unsigned int data); +unsigned long long tep_data2host8(struct tep_handle *tep, unsigned long long data); #endif /* _PARSE_EVENTS_INT_H */ diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 981c6ce2da2c..b36b536a9fcb 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -148,14 +148,14 @@ struct cmdline_list { int pid; }; -static int cmdline_init(struct tep_handle *pevent) +static int cmdline_init(struct tep_handle *tep) { - struct cmdline_list *cmdlist = pevent->cmdlist; + struct cmdline_list *cmdlist = tep->cmdlist; struct cmdline_list *item; struct tep_cmdline *cmdlines; int i; - cmdlines = malloc(sizeof(*cmdlines) * pevent->cmdline_count); + cmdlines = malloc(sizeof(*cmdlines) * tep->cmdline_count); if (!cmdlines) return -1; @@ -169,15 +169,15 @@ static int cmdline_init(struct tep_handle *pevent) free(item); } - qsort(cmdlines, pevent->cmdline_count, sizeof(*cmdlines), cmdline_cmp); + qsort(cmdlines, tep->cmdline_count, sizeof(*cmdlines), cmdline_cmp); - pevent->cmdlines = cmdlines; - pevent->cmdlist = NULL; + tep->cmdlines = cmdlines; + tep->cmdlist = NULL; return 0; } -static const char *find_cmdline(struct tep_handle *pevent, int pid) +static const char *find_cmdline(struct tep_handle *tep, int pid) { const struct tep_cmdline *comm; struct tep_cmdline key; @@ -185,13 +185,13 @@ static const char *find_cmdline(struct tep_handle *pevent, int pid) if (!pid) return "<idle>"; - if (!pevent->cmdlines && cmdline_init(pevent)) + if (!tep->cmdlines && cmdline_init(tep)) return "<not enough memory for cmdlines!>"; key.pid = pid; - comm = bsearch(&key, pevent->cmdlines, pevent->cmdline_count, - sizeof(*pevent->cmdlines), cmdline_cmp); + comm = bsearch(&key, tep->cmdlines, tep->cmdline_count, + sizeof(*tep->cmdlines), cmdline_cmp); if (comm) return comm->comm; @@ -199,32 +199,32 @@ static const char *find_cmdline(struct tep_handle *pevent, int pid) } /** - * tep_pid_is_registered - return if a pid has a cmdline registered - * @pevent: handle for the pevent + * tep_is_pid_registered - return if a pid has a cmdline registered + * @tep: a handle to the trace event parser context * @pid: The pid to check if it has a cmdline registered with. * - * Returns 1 if the pid has a cmdline mapped to it - * 0 otherwise. + * Returns true if the pid has a cmdline mapped to it + * false otherwise. */ -int tep_pid_is_registered(struct tep_handle *pevent, int pid) +bool tep_is_pid_registered(struct tep_handle *tep, int pid) { const struct tep_cmdline *comm; struct tep_cmdline key; if (!pid) - return 1; + return true; - if (!pevent->cmdlines && cmdline_init(pevent)) - return 0; + if (!tep->cmdlines && cmdline_init(tep)) + return false; key.pid = pid; - comm = bsearch(&key, pevent->cmdlines, pevent->cmdline_count, - sizeof(*pevent->cmdlines), cmdline_cmp); + comm = bsearch(&key, tep->cmdlines, tep->cmdline_count, + sizeof(*tep->cmdlines), cmdline_cmp); if (comm) - return 1; - return 0; + return true; + return false; } /* @@ -232,10 +232,10 @@ int tep_pid_is_registered(struct tep_handle *pevent, int pid) * we must add this pid. This is much slower than when cmdlines * are added before the array is initialized. */ -static int add_new_comm(struct tep_handle *pevent, +static int add_new_comm(struct tep_handle *tep, const char *comm, int pid, bool override) { - struct tep_cmdline *cmdlines = pevent->cmdlines; + struct tep_cmdline *cmdlines = tep->cmdlines; struct tep_cmdline *cmdline; struct tep_cmdline key; char *new_comm; @@ -246,8 +246,8 @@ static int add_new_comm(struct tep_handle *pevent, /* avoid duplicates */ key.pid = pid; - cmdline = bsearch(&key, pevent->cmdlines, pevent->cmdline_count, - sizeof(*pevent->cmdlines), cmdline_cmp); + cmdline = bsearch(&key, tep->cmdlines, tep->cmdline_count, + sizeof(*tep->cmdlines), cmdline_cmp); if (cmdline) { if (!override) { errno = EEXIST; @@ -264,37 +264,37 @@ static int add_new_comm(struct tep_handle *pevent, return 0; } - cmdlines = realloc(cmdlines, sizeof(*cmdlines) * (pevent->cmdline_count + 1)); + cmdlines = realloc(cmdlines, sizeof(*cmdlines) * (tep->cmdline_count + 1)); if (!cmdlines) { errno = ENOMEM; return -1; } - cmdlines[pevent->cmdline_count].comm = strdup(comm); - if (!cmdlines[pevent->cmdline_count].comm) { + cmdlines[tep->cmdline_count].comm = strdup(comm); + if (!cmdlines[tep->cmdline_count].comm) { free(cmdlines); errno = ENOMEM; return -1; } - cmdlines[pevent->cmdline_count].pid = pid; + cmdlines[tep->cmdline_count].pid = pid; - if (cmdlines[pevent->cmdline_count].comm) - pevent->cmdline_count++; + if (cmdlines[tep->cmdline_count].comm) + tep->cmdline_count++; - qsort(cmdlines, pevent->cmdline_count, sizeof(*cmdlines), cmdline_cmp); - pevent->cmdlines = cmdlines; + qsort(cmdlines, tep->cmdline_count, sizeof(*cmdlines), cmdline_cmp); + tep->cmdlines = cmdlines; return 0; } -static int _tep_register_comm(struct tep_handle *pevent, +static int _tep_register_comm(struct tep_handle *tep, const char *comm, int pid, bool override) { struct cmdline_list *item; - if (pevent->cmdlines) - return add_new_comm(pevent, comm, pid, override); + if (tep->cmdlines) + return add_new_comm(tep, comm, pid, override); item = malloc(sizeof(*item)); if (!item) @@ -309,17 +309,17 @@ static int _tep_register_comm(struct tep_handle *pevent, return -1; } item->pid = pid; - item->next = pevent->cmdlist; + item->next = tep->cmdlist; - pevent->cmdlist = item; - pevent->cmdline_count++; + tep->cmdlist = item; + tep->cmdline_count++; return 0; } /** * tep_register_comm - register a pid / comm mapping - * @pevent: handle for the pevent + * @tep: a handle to the trace event parser context * @comm: the command line to register * @pid: the pid to map the command line to * @@ -327,14 +327,14 @@ static int _tep_register_comm(struct tep_handle *pevent, * a given pid. The comm is duplicated. If a command with the same pid * already exist, -1 is returned and errno is set to EEXIST */ -int tep_register_comm(struct tep_handle *pevent, const char *comm, int pid) +int tep_register_comm(struct tep_handle *tep, const char *comm, int pid) { - return _tep_register_comm(pevent, comm, pid, false); + return _tep_register_comm(tep, comm, pid, false); } /** * tep_override_comm - register a pid / comm mapping - * @pevent: handle for the pevent + * @tep: a handle to the trace event parser context * @comm: the command line to register * @pid: the pid to map the command line to * @@ -342,19 +342,19 @@ int tep_register_comm(struct tep_handle *pevent, const char *comm, int pid) * a given pid. The comm is duplicated. If a command with the same pid * already exist, the command string is udapted with the new one */ -int tep_override_comm(struct tep_handle *pevent, const char *comm, int pid) +int tep_override_comm(struct tep_handle *tep, const char *comm, int pid) { - if (!pevent->cmdlines && cmdline_init(pevent)) { + if (!tep->cmdlines && cmdline_init(tep)) { errno = ENOMEM; return -1; } - return _tep_register_comm(pevent, comm, pid, true); + return _tep_register_comm(tep, comm, pid, true); } -int tep_register_trace_clock(struct tep_handle *pevent, const char *trace_clock) +int tep_register_trace_clock(struct tep_handle *tep, const char *trace_clock) { - pevent->trace_clock = strdup(trace_clock); - if (!pevent->trace_clock) { + tep->trace_clock = strdup(trace_clock); + if (!tep->trace_clock) { errno = ENOMEM; return -1; } @@ -408,18 +408,18 @@ static int func_bcmp(const void *a, const void *b) return 1; } -static int func_map_init(struct tep_handle *pevent) +static int func_map_init(struct tep_handle *tep) { struct func_list *funclist; struct func_list *item; struct func_map *func_map; int i; - func_map = malloc(sizeof(*func_map) * (pevent->func_count + 1)); + func_map = malloc(sizeof(*func_map) * (tep->func_count + 1)); if (!func_map) return -1; - funclist = pevent->funclist; + funclist = tep->funclist; i = 0; while (funclist) { @@ -432,34 +432,34 @@ static int func_map_init(struct tep_handle *pevent) free(item); } - qsort(func_map, pevent->func_count, sizeof(*func_map), func_cmp); + qsort(func_map, tep->func_count, sizeof(*func_map), func_cmp); /* * Add a special record at the end. */ - func_map[pevent->func_count].func = NULL; - func_map[pevent->func_count].addr = 0; - func_map[pevent->func_count].mod = NULL; + func_map[tep->func_count].func = NULL; + func_map[tep->func_count].addr = 0; + func_map[tep->func_count].mod = NULL; - pevent->func_map = func_map; - pevent->funclist = NULL; + tep->func_map = func_map; + tep->funclist = NULL; return 0; } static struct func_map * -__find_func(struct tep_handle *pevent, unsigned long long addr) +__find_func(struct tep_handle *tep, unsigned long long addr) { struct func_map *func; struct func_map key; - if (!pevent->func_map) - func_map_init(pevent); + if (!tep->func_map) + func_map_init(tep); key.addr = addr; - func = bsearch(&key, pevent->func_map, pevent->func_count, - sizeof(*pevent->func_map), func_bcmp); + func = bsearch(&key, tep->func_map, tep->func_count, + sizeof(*tep->func_map), func_bcmp); return func; } @@ -472,15 +472,14 @@ struct func_resolver { /** * tep_set_function_resolver - set an alternative function resolver - * @pevent: handle for the pevent + * @tep: a handle to the trace event parser context * @resolver: function to be used * @priv: resolver function private state. * * Some tools may have already a way to resolve kernel functions, allow them to - * keep using it instead of duplicating all the entries inside - * pevent->funclist. + * keep using it instead of duplicating all the entries inside tep->funclist. */ -int tep_set_function_resolver(struct tep_handle *pevent, +int tep_set_function_resolver(struct tep_handle *tep, tep_func_resolver_t *func, void *priv) { struct func_resolver *resolver = malloc(sizeof(*resolver)); @@ -491,38 +490,38 @@ int tep_set_function_resolver(struct tep_handle *pevent, resolver->func = func; resolver->priv = priv; - free(pevent->func_resolver); - pevent->func_resolver = resolver; + free(tep->func_resolver); + tep->func_resolver = resolver; return 0; } /** * tep_reset_function_resolver - reset alternative function resolver - * @pevent: handle for the pevent + * @tep: a handle to the trace event parser context * * Stop using whatever alternative resolver was set, use the default * one instead. */ -void tep_reset_function_resolver(struct tep_handle *pevent) +void tep_reset_function_resolver(struct tep_handle *tep) { - free(pevent->func_resolver); - pevent->func_resolver = NULL; + free(tep->func_resolver); + tep->func_resolver = NULL; } static struct func_map * -find_func(struct tep_handle *pevent, unsigned long long addr) +find_func(struct tep_handle *tep, unsigned long long addr) { struct func_map *map; - if (!pevent->func_resolver) - return __find_func(pevent, addr); + if (!tep->func_resolver) + return __find_func(tep, addr); - map = &pevent->func_resolver->map; + map = &tep->func_resolver->map; map->mod = NULL; map->addr = addr; - map->func = pevent->func_resolver->func(pevent->func_resolver->priv, - &map->addr, &map->mod); + map->func = tep->func_resolver->func(tep->func_resolver->priv, + &map->addr, &map->mod); if (map->func == NULL) return NULL; @@ -531,18 +530,18 @@ find_func(struct tep_handle *pevent, unsigned long long addr) /** * tep_find_function - find a function by a given address - * @pevent: handle for the pevent + * @tep: a handle to the trace event parser context * @addr: the address to find the function with * * Returns a pointer to the function stored that has the given * address. Note, the address does not have to be exact, it * will select the function that would contain the address. */ -const char *tep_find_function(struct tep_handle *pevent, unsigned long long addr) +const char *tep_find_function(struct tep_handle *tep, unsigned long long addr) { struct func_map *map; - map = find_func(pevent, addr); + map = find_func(tep, addr); if (!map) return NULL; @@ -551,7 +550,7 @@ const char *tep_find_function(struct tep_handle *pevent, unsigned long long addr /** * tep_find_function_address - find a function address by a given address - * @pevent: handle for the pevent + * @tep: a handle to the trace event parser context * @addr: the address to find the function with * * Returns the address the function starts at. This can be used in @@ -559,11 +558,11 @@ const char *tep_find_function(struct tep_handle *pevent, unsigned long long addr * name and the function offset. */ unsigned long long -tep_find_function_address(struct tep_handle *pevent, unsigned long long addr) +tep_find_function_address(struct tep_handle *tep, unsigned long long addr) { struct func_map *map; - map = find_func(pevent, addr); + map = find_func(tep, addr); if (!map) return 0; @@ -572,7 +571,7 @@ tep_find_function_address(struct tep_handle *pevent, unsigned long long addr) /** * tep_register_function - register a function with a given address - * @pevent: handle for the pevent + * @tep: a handle to the trace event parser context * @function: the function name to register * @addr: the address the function starts at * @mod: the kernel module the function may be in (NULL for none) @@ -580,7 +579,7 @@ tep_find_function_address(struct tep_handle *pevent, unsigned long long addr) * This registers a function name with an address and module. * The @func passed in is duplicated. */ -int tep_register_function(struct tep_handle *pevent, char *func, +int tep_register_function(struct tep_handle *tep, char *func, unsigned long long addr, char *mod) { struct func_list *item = malloc(sizeof(*item)); @@ -588,7 +587,7 @@ int tep_register_function(struct tep_handle *pevent, char *func, if (!item) return -1; - item->next = pevent->funclist; + item->next = tep->funclist; item->func = strdup(func); if (!item->func) goto out_free; @@ -601,8 +600,8 @@ int tep_register_function(struct tep_handle *pevent, char *func, item->mod = NULL; item->addr = addr; - pevent->funclist = item; - pevent->func_count++; + tep->funclist = item; + tep->func_count++; return 0; @@ -617,23 +616,23 @@ out_free: /** * tep_print_funcs - print out the stored functions - * @pevent: handle for the pevent + * @tep: a handle to the trace event parser context * * This prints out the stored functions. */ -void tep_print_funcs(struct tep_handle *pevent) +void tep_print_funcs(struct tep_handle *tep) { int i; - if (!pevent->func_map) - func_map_init(pevent); + if (!tep->func_map) + func_map_init(tep); - for (i = 0; i < (int)pevent->func_count; i++) { + for (i = 0; i < (int)tep->func_count; i++) { printf("%016llx %s", - pevent->func_map[i].addr, - pevent->func_map[i].func); - if (pevent->func_map[i].mod) - printf(" [%s]\n", pevent->func_map[i].mod); + tep->func_map[i].addr, + tep->func_map[i].func); + if (tep->func_map[i].mod) + printf(" [%s]\n", tep->func_map[i].mod); else printf("\n"); } @@ -663,18 +662,18 @@ static int printk_cmp(const void *a, const void *b) return 0; } -static int printk_map_init(struct tep_handle *pevent) +static int printk_map_init(struct tep_handle *tep) { struct printk_list *printklist; struct printk_list *item; struct printk_map *printk_map; int i; - printk_map = malloc(sizeof(*printk_map) * (pevent->printk_count + 1)); + printk_map = malloc(sizeof(*printk_map) * (tep->printk_count + 1)); if (!printk_map) return -1; - printklist = pevent->printklist; + printklist = tep->printklist; i = 0; while (printklist) { @@ -686,41 +685,41 @@ static int printk_map_init(struct tep_handle *pevent) free(item); } - qsort(printk_map, pevent->printk_count, sizeof(*printk_map), printk_cmp); + qsort(printk_map, tep->printk_count, sizeof(*printk_map), printk_cmp); - pevent->printk_map = printk_map; - pevent->printklist = NULL; + tep->printk_map = printk_map; + tep->printklist = NULL; return 0; } static struct printk_map * -find_printk(struct tep_handle *pevent, unsigned long long addr) +find_printk(struct tep_handle *tep, unsigned long long addr) { struct printk_map *printk; struct printk_map key; - if (!pevent->printk_map && printk_map_init(pevent)) + if (!tep->printk_map && printk_map_init(tep)) return NULL; key.addr = addr; - printk = bsearch(&key, pevent->printk_map, pevent->printk_count, - sizeof(*pevent->printk_map), printk_cmp); + printk = bsearch(&key, tep->printk_map, tep->printk_count, + sizeof(*tep->printk_map), printk_cmp); return printk; } /** * tep_register_print_string - register a string by its address - * @pevent: handle for the pevent + * @tep: a handle to the trace event parser context * @fmt: the string format to register * @addr: the address the string was located at * * This registers a string by the address it was stored in the kernel. * The @fmt passed in is duplicated. */ -int tep_register_print_string(struct tep_handle *pevent, const char *fmt, +int tep_register_print_string(struct tep_handle *tep, const char *fmt, unsigned long long addr) { struct printk_list *item = malloc(sizeof(*item)); @@ -729,7 +728,7 @@ int tep_register_print_string(struct tep_handle *pevent, const char *fmt, if (!item) return -1; - item->next = pevent->printklist; + item->next = tep->printklist; item->addr = addr; /* Strip off quotes and '\n' from the end */ @@ -747,8 +746,8 @@ int tep_register_print_string(struct tep_handle *pevent, const char *fmt, if (strcmp(p, "\\n") == 0) *p = 0; - pevent->printklist = item; - pevent->printk_count++; + tep->printklist = item; + tep->printk_count++; return 0; @@ -760,21 +759,21 @@ out_free: /** * tep_print_printk - print out the stored strings - * @pevent: handle for the pevent + * @tep: a handle to the trace event parser context * * This prints the string formats that were stored. */ -void tep_print_printk(struct tep_handle *pevent) +void tep_print_printk(struct tep_handle *tep) { int i; - if (!pevent->printk_map) - printk_map_init(pevent); + if (!tep->printk_map) + printk_map_init(tep); - for (i = 0; i < (int)pevent->printk_count; i++) { + for (i = 0; i < (int)tep->printk_count; i++) { printf("%016llx %s\n", - pevent->printk_map[i].addr, - pevent->printk_map[i].printk); + tep->printk_map[i].addr, + tep->printk_map[i].printk); } } @@ -783,29 +782,29 @@ static struct tep_event *alloc_event(void) return calloc(1, sizeof(struct tep_event)); } -static int add_event(struct tep_handle *pevent, struct tep_event *event) +static int add_event(struct tep_handle *tep, struct tep_event *event) { int i; - struct tep_event **events = realloc(pevent->events, sizeof(event) * - (pevent->nr_events + 1)); + struct tep_event **events = realloc(tep->events, sizeof(event) * + (tep->nr_events + 1)); if (!events) return -1; - pevent->events = events; + tep->events = events; - for (i = 0; i < pevent->nr_events; i++) { - if (pevent->events[i]->id > event->id) + for (i = 0; i < tep->nr_events; i++) { + if (tep->events[i]->id > event->id) break; } - if (i < pevent->nr_events) - memmove(&pevent->events[i + 1], - &pevent->events[i], - sizeof(event) * (pevent->nr_events - i)); + if (i < tep->nr_events) + memmove(&tep->events[i + 1], + &tep->events[i], + sizeof(event) * (tep->nr_events - i)); - pevent->events[i] = event; - pevent->nr_events++; + tep->events[i] = event; + tep->nr_events++; - event->pevent = pevent; + event->tep = tep; return 0; } @@ -1184,7 +1183,7 @@ static enum tep_event_type read_token(char **tok) } /** - * tep_read_token - access to utilities to use the pevent parser + * tep_read_token - access to utilities to use the tep parser * @tok: The token to return * * This will parse tokens from the string given by @@ -1657,8 +1656,8 @@ static int event_read_fields(struct tep_event *event, struct tep_format_field ** else if (field->flags & TEP_FIELD_IS_STRING) field->elementsize = 1; else if (field->flags & TEP_FIELD_IS_LONG) - field->elementsize = event->pevent ? - event->pevent->long_size : + field->elementsize = event->tep ? + event->tep->long_size : sizeof(long); } else field->elementsize = field->size; @@ -2942,14 +2941,14 @@ process_bitmask(struct tep_event *event __maybe_unused, struct tep_print_arg *ar } static struct tep_function_handler * -find_func_handler(struct tep_handle *pevent, char *func_name) +find_func_handler(struct tep_handle *tep, char *func_name) { struct tep_function_handler *func; - if (!pevent) + if (!tep) return NULL; - for (func = pevent->func_handlers; func; func = func->next) { + for (func = tep->func_handlers; func; func = func->next) { if (strcmp(func->name, func_name) == 0) break; } @@ -2957,12 +2956,12 @@ find_func_handler(struct tep_handle *pevent, char *func_name) return func; } -static void remove_func_handler(struct tep_handle *pevent, char *func_name) +static void remove_func_handler(struct tep_handle *tep, char *func_name) { struct tep_function_handler *func; struct tep_function_handler **next; - next = &pevent->func_handlers; + next = &tep->func_handlers; while ((func = *next)) { if (strcmp(func->name, func_name) == 0) { *next = func->next; @@ -3076,7 +3075,7 @@ process_function(struct tep_event *event, struct tep_print_arg *arg, return process_dynamic_array_len(event, arg, tok); } - func = find_func_handler(event->pevent, token); + func = find_func_handler(event->tep, token); if (func) { free_token(token); return process_func_handler(event, func, arg, tok); @@ -3357,14 +3356,14 @@ tep_find_any_field(struct tep_event *event, const char *name) /** * tep_read_number - read a number from data - * @pevent: handle for the pevent + * @tep: a handle to the trace event parser context * @ptr: the raw data * @size: the size of the data that holds the number * * Returns the number (converted to host) from the * raw data. */ -unsigned long long tep_read_number(struct tep_handle *pevent, +unsigned long long tep_read_number(struct tep_handle *tep, const void *ptr, int size) { unsigned long long val; @@ -3373,12 +3372,12 @@ unsigned long long tep_read_number(struct tep_handle *pevent, case 1: return *(unsigned char *)ptr; case 2: - return tep_data2host2(pevent, *(unsigned short *)ptr); + return tep_data2host2(tep, *(unsigned short *)ptr); case 4: - return tep_data2host4(pevent, *(unsigned int *)ptr); + return tep_data2host4(tep, *(unsigned int *)ptr); case 8: memcpy(&val, (ptr), sizeof(unsigned long long)); - return tep_data2host8(pevent, val); + return tep_data2host8(tep, val); default: /* BUG! */ return 0; @@ -3406,7 +3405,7 @@ int tep_read_number_field(struct tep_format_field *field, const void *data, case 2: case 4: case 8: - *value = tep_read_number(field->event->pevent, + *value = tep_read_number(field->event->tep, data + field->offset, field->size); return 0; default: @@ -3414,7 +3413,7 @@ int tep_read_number_field(struct tep_format_field *field, const void *data, } } -static int get_common_info(struct tep_handle *pevent, +static int get_common_info(struct tep_handle *tep, const char *type, int *offset, int *size) { struct tep_event *event; @@ -3424,12 +3423,12 @@ static int get_common_info(struct tep_handle *pevent, * All events should have the same common elements. * Pick any event to find where the type is; */ - if (!pevent->events) { + if (!tep->events) { do_warning("no event_list!"); return -1; } - event = pevent->events[0]; + event = tep->events[0]; field = tep_find_common_field(event, type); if (!field) return -1; @@ -3440,58 +3439,58 @@ static int get_common_info(struct tep_handle *pevent, return 0; } -static int __parse_common(struct tep_handle *pevent, void *data, +static int __parse_common(struct tep_handle *tep, void *data, int *size, int *offset, const char *name) { int ret; if (!*size) { - ret = get_common_info(pevent, name, offset, size); + ret = get_common_info(tep, name, offset, size); if (ret < 0) return ret; } - return tep_read_number(pevent, data + *offset, *size); + return tep_read_number(tep, data + *offset, *size); } -static int trace_parse_common_type(struct tep_handle *pevent, void *data) +static int trace_parse_common_type(struct tep_handle *tep, void *data) { - return __parse_common(pevent, data, - &pevent->type_size, &pevent->type_offset, + return __parse_common(tep, data, + &tep->type_size, &tep->type_offset, "common_type"); } -static int parse_common_pid(struct tep_handle *pevent, void *data) +static int parse_common_pid(struct tep_handle *tep, void *data) { - return __parse_common(pevent, data, - &pevent->pid_size, &pevent->pid_offset, + return __parse_common(tep, data, + &tep->pid_size, &tep->pid_offset, "common_pid"); } -static int parse_common_pc(struct tep_handle *pevent, void *data) +static int parse_common_pc(struct tep_handle *tep, void *data) { - return __parse_common(pevent, data, - &pevent->pc_size, &pevent->pc_offset, + return __parse_common(tep, data, + &tep->pc_size, &tep->pc_offset, "common_preempt_count"); } -static int parse_common_flags(struct tep_handle *pevent, void *data) +static int parse_common_flags(struct tep_handle *tep, void *data) { - return __parse_common(pevent, data, - &pevent->flags_size, &pevent->flags_offset, + return __parse_common(tep, data, + &tep->flags_size, &tep->flags_offset, "common_flags"); } -static int parse_common_lock_depth(struct tep_handle *pevent, void *data) +static int parse_common_lock_depth(struct tep_handle *tep, void *data) { - return __parse_common(pevent, data, - &pevent->ld_size, &pevent->ld_offset, + return __parse_common(tep, data, + &tep->ld_size, &tep->ld_offset, "common_lock_depth"); } -static int parse_common_migrate_disable(struct tep_handle *pevent, void *data) +static int parse_common_migrate_disable(struct tep_handle *tep, void *data) { - return __parse_common(pevent, data, - &pevent->ld_size, &pevent->ld_offset, + return __parse_common(tep, data, + &tep->ld_size, &tep->ld_offset, "common_migrate_disable"); } @@ -3499,28 +3498,28 @@ static int events_id_cmp(const void *a, const void *b); /** * tep_find_event - find an event by given id - * @pevent: a handle to the pevent + * @tep: a handle to the trace event parser context * @id: the id of the event * * Returns an event that has a given @id. */ -struct tep_event *tep_find_event(struct tep_handle *pevent, int id) +struct tep_event *tep_find_event(struct tep_handle *tep, int id) { struct tep_event **eventptr; struct tep_event key; struct tep_event *pkey = &key; /* Check cache first */ - if (pevent->last_event && pevent->last_event->id == id) - return pevent->last_event; + if (tep->last_event && tep->last_event->id == id) + return tep->last_event; key.id = id; - eventptr = bsearch(&pkey, pevent->events, pevent->nr_events, - sizeof(*pevent->events), events_id_cmp); + eventptr = bsearch(&pkey, tep->events, tep->nr_events, + sizeof(*tep->events), events_id_cmp); if (eventptr) { - pevent->last_event = *eventptr; + tep->last_event = *eventptr; return *eventptr; } @@ -3529,7 +3528,7 @@ struct tep_event *tep_find_event(struct tep_handle *pevent, int id) /** * tep_find_event_by_name - find an event by given name - * @pevent: a handle to the pevent + * @tep: a handle to the trace event parser context * @sys: the system name to search for * @name: the name of the event to search for * @@ -3537,19 +3536,19 @@ struct tep_event *tep_find_event(struct tep_handle *pevent, int id) * @sys. If @sys is NULL the first event with @name is returned. */ struct tep_event * -tep_find_event_by_name(struct tep_handle *pevent, +tep_find_event_by_name(struct tep_handle *tep, const char *sys, const char *name) { struct tep_event *event = NULL; int i; - if (pevent->last_event && - strcmp(pevent->last_event->name, name) == 0 && - (!sys || strcmp(pevent->last_event->system, sys) == 0)) - return pevent->last_event; + if (tep->last_event && + strcmp(tep->last_event->name, name) == 0 && + (!sys || strcmp(tep->last_event->system, sys) == 0)) + return tep->last_event; - for (i = 0; i < pevent->nr_events; i++) { - event = pevent->events[i]; + for (i = 0; i < tep->nr_events; i++) { + event = tep->events[i]; if (strcmp(event->name, name) == 0) { if (!sys) break; @@ -3557,17 +3556,17 @@ tep_find_event_by_name(struct tep_handle *pevent, break; } } - if (i == pevent->nr_events) + if (i == tep->nr_events) event = NULL; - pevent->last_event = event; + tep->last_event = event; return event; } static unsigned long long eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg *arg) { - struct tep_handle *pevent = event->pevent; + struct tep_handle *tep = event->tep; unsigned long long val = 0; unsigned long long left, right; struct tep_print_arg *typearg = NULL; @@ -3589,7 +3588,7 @@ eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg } /* must be a number */ - val = tep_read_number(pevent, data + arg->field.field->offset, + val = tep_read_number(tep, data + arg->field.field->offset, arg->field.field->size); break; case TEP_PRINT_FLAGS: @@ -3629,11 +3628,11 @@ eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg } /* Default to long size */ - field_size = pevent->long_size; + field_size = tep->long_size; switch (larg->type) { case TEP_PRINT_DYNAMIC_ARRAY: - offset = tep_read_number(pevent, + offset = tep_read_number(tep, data + larg->dynarray.field->offset, larg->dynarray.field->size); if (larg->dynarray.field->elementsize) @@ -3662,7 +3661,7 @@ eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg default: goto default_op; /* oops, all bets off */ } - val = tep_read_number(pevent, + val = tep_read_number(tep, data + offset, field_size); if (typearg) val = eval_type(val, typearg, 1); @@ -3763,7 +3762,7 @@ eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg } break; case TEP_PRINT_DYNAMIC_ARRAY_LEN: - offset = tep_read_number(pevent, + offset = tep_read_number(tep, data + arg->dynarray.field->offset, arg->dynarray.field->size); /* @@ -3775,7 +3774,7 @@ eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg break; case TEP_PRINT_DYNAMIC_ARRAY: /* Without [], we pass the address to the dynamic data */ - offset = tep_read_number(pevent, + offset = tep_read_number(tep, data + arg->dynarray.field->offset, arg->dynarray.field->size); /* @@ -3850,7 +3849,7 @@ static void print_str_to_seq(struct trace_seq *s, const char *format, trace_seq_printf(s, format, str); } -static void print_bitmask_to_seq(struct tep_handle *pevent, +static void print_bitmask_to_seq(struct tep_handle *tep, struct trace_seq *s, const char *format, int len_arg, const void *data, int size) { @@ -3882,7 +3881,7 @@ static void print_bitmask_to_seq(struct tep_handle *pevent, * In the kernel, this is an array of long words, thus * endianness is very important. */ - if (pevent->file_bigendian) + if (tep->file_bigendian) index = size - (len + 1); else index = len; @@ -3908,7 +3907,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, struct tep_event *event, const char *format, int len_arg, struct tep_print_arg *arg) { - struct tep_handle *pevent = event->pevent; + struct tep_handle *tep = event->tep; struct tep_print_flag_sym *flag; struct tep_format_field *field; struct printk_map *printk; @@ -3945,7 +3944,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, * is a pointer. */ if (!(field->flags & TEP_FIELD_IS_ARRAY) && - field->size == pevent->long_size) { + field->size == tep->long_size) { /* Handle heterogeneous recording and processing * architectures @@ -3960,12 +3959,12 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, * on 32-bit devices: * In this case, 64 bits must be read. */ - addr = (pevent->long_size == 8) ? + addr = (tep->long_size == 8) ? *(unsigned long long *)(data + field->offset) : (unsigned long long)*(unsigned int *)(data + field->offset); /* Check if it matches a print format */ - printk = find_printk(pevent, addr); + printk = find_printk(tep, addr); if (printk) trace_seq_puts(s, printk->printk); else @@ -4022,7 +4021,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, case TEP_PRINT_HEX_STR: if (arg->hex.field->type == TEP_PRINT_DYNAMIC_ARRAY) { unsigned long offset; - offset = tep_read_number(pevent, + offset = tep_read_number(tep, data + arg->hex.field->dynarray.field->offset, arg->hex.field->dynarray.field->size); hex = data + (offset & 0xffff); @@ -4053,7 +4052,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, unsigned long offset; struct tep_format_field *field = arg->int_array.field->dynarray.field; - offset = tep_read_number(pevent, + offset = tep_read_number(tep, data + field->offset, field->size); num = data + (offset & 0xffff); @@ -4104,7 +4103,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, f = tep_find_any_field(event, arg->string.string); arg->string.offset = f->offset; } - str_offset = tep_data2host4(pevent, *(unsigned int *)(data + arg->string.offset)); + str_offset = tep_data2host4(tep, *(unsigned int *)(data + arg->string.offset)); str_offset &= 0xffff; print_str_to_seq(s, format, len_arg, ((char *)data) + str_offset); break; @@ -4122,10 +4121,10 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, f = tep_find_any_field(event, arg->bitmask.bitmask); arg->bitmask.offset = f->offset; } - bitmask_offset = tep_data2host4(pevent, *(unsigned int *)(data + arg->bitmask.offset)); + bitmask_offset = tep_data2host4(tep, *(unsigned int *)(data + arg->bitmask.offset)); bitmask_size = bitmask_offset >> 16; bitmask_offset &= 0xffff; - print_bitmask_to_seq(pevent, s, format, len_arg, + print_bitmask_to_seq(tep, s, format, len_arg, data + bitmask_offset, bitmask_size); break; } @@ -4257,7 +4256,7 @@ static void free_args(struct tep_print_arg *args) static struct tep_print_arg *make_bprint_args(char *fmt, void *data, int size, struct tep_event *event) { - struct tep_handle *pevent = event->pevent; + struct tep_handle *tep = event->tep; struct tep_format_field *field, *ip_field; struct tep_print_arg *args, *arg, **next; unsigned long long ip, val; @@ -4265,8 +4264,8 @@ static struct tep_print_arg *make_bprint_args(char *fmt, void *data, int size, s void *bptr; int vsize = 0; - field = pevent->bprint_buf_field; - ip_field = pevent->bprint_ip_field; + field = tep->bprint_buf_field; + ip_field = tep->bprint_ip_field; if (!field) { field = tep_find_field(event, "buf"); @@ -4279,11 +4278,11 @@ static struct tep_print_arg *make_bprint_args(char *fmt, void *data, int size, s do_warning_event(event, "can't find ip field for binary printk"); return NULL; } - pevent->bprint_buf_field = field; - pevent->bprint_ip_field = ip_field; + tep->bprint_buf_field = field; + tep->bprint_ip_field = ip_field; } - ip = tep_read_number(pevent, data + ip_field->offset, ip_field->size); + ip = tep_read_number(tep, data + ip_field->offset, ip_field->size); /* * The first arg is the IP pointer. @@ -4338,6 +4337,7 @@ static struct tep_print_arg *make_bprint_args(char *fmt, void *data, int size, s case 'S': case 'f': case 'F': + case 'x': break; default: /* @@ -4360,7 +4360,7 @@ static struct tep_print_arg *make_bprint_args(char *fmt, void *data, int size, s vsize = 4; break; case 1: - vsize = pevent->long_size; + vsize = tep->long_size; break; case 2: vsize = 8; @@ -4377,7 +4377,7 @@ static struct tep_print_arg *make_bprint_args(char *fmt, void *data, int size, s /* the pointers are always 4 bytes aligned */ bptr = (void *)(((unsigned long)bptr + 3) & ~3); - val = tep_read_number(pevent, bptr, vsize); + val = tep_read_number(tep, bptr, vsize); bptr += vsize; arg = alloc_arg(); if (!arg) { @@ -4434,13 +4434,13 @@ static char * get_bprint_format(void *data, int size __maybe_unused, struct tep_event *event) { - struct tep_handle *pevent = event->pevent; + struct tep_handle *tep = event->tep; unsigned long long addr; struct tep_format_field *field; struct printk_map *printk; char *format; - field = pevent->bprint_fmt_field; + field = tep->bprint_fmt_field; if (!field) { field = tep_find_field(event, "fmt"); @@ -4448,12 +4448,12 @@ get_bprint_format(void *data, int size __maybe_unused, do_warning_event(event, "can't find format field for binary printk"); return NULL; } - pevent->bprint_fmt_field = field; + tep->bprint_fmt_field = field; } - addr = tep_read_number(pevent, data + field->offset, field->size); + addr = tep_read_number(tep, data + field->offset, field->size); - printk = find_printk(pevent, addr); + printk = find_printk(tep, addr); if (!printk) { if (asprintf(&format, "%%pf: (NO FORMAT FOUND at %llx)\n", addr) < 0) return NULL; @@ -4835,13 +4835,13 @@ void tep_print_field(struct trace_seq *s, void *data, { unsigned long long val; unsigned int offset, len, i; - struct tep_handle *pevent = field->event->pevent; + struct tep_handle *tep = field->event->tep; if (field->flags & TEP_FIELD_IS_ARRAY) { offset = field->offset; len = field->size; if (field->flags & TEP_FIELD_IS_DYNAMIC) { - val = tep_read_number(pevent, data + offset, len); + val = tep_read_number(tep, data + offset, len); offset = val; len = offset >> 16; offset &= 0xffff; @@ -4861,7 +4861,7 @@ void tep_print_field(struct trace_seq *s, void *data, field->flags &= ~TEP_FIELD_IS_STRING; } } else { - val = tep_read_number(pevent, data + field->offset, + val = tep_read_number(tep, data + field->offset, field->size); if (field->flags & TEP_FIELD_IS_POINTER) { trace_seq_printf(s, "0x%llx", val); @@ -4910,7 +4910,7 @@ void tep_print_fields(struct trace_seq *s, void *data, static void pretty_print(struct trace_seq *s, void *data, int size, struct tep_event *event) { - struct tep_handle *pevent = event->pevent; + struct tep_handle *tep = event->tep; struct tep_print_fmt *print_fmt = &event->print_fmt; struct tep_print_arg *arg = print_fmt->args; struct tep_print_arg *args = NULL; @@ -5002,7 +5002,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct tep_e case '-': goto cont_process; case 'p': - if (pevent->long_size == 4) + if (tep->long_size == 4) ls = 1; else ls = 2; @@ -5063,7 +5063,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct tep_e arg = arg->next; if (show_func) { - func = find_func(pevent, val); + func = find_func(tep, val); if (func) { trace_seq_puts(s, func->func); if (show_func == 'F') @@ -5073,7 +5073,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct tep_e break; } } - if (pevent->long_size == 8 && ls == 1 && + if (tep->long_size == 8 && ls == 1 && sizeof(long) != 8) { char *p; @@ -5171,8 +5171,8 @@ out_failed: } /** - * tep_data_lat_fmt - parse the data for the latency format - * @pevent: a handle to the pevent + * tep_data_latency_format - parse the data for the latency format + * @tep: a handle to the trace event parser context * @s: the trace_seq to write to * @record: the record to read from * @@ -5180,8 +5180,8 @@ out_failed: * need rescheduling, in hard/soft interrupt, preempt count * and lock depth) and places it into the trace_seq. */ -void tep_data_lat_fmt(struct tep_handle *pevent, - struct trace_seq *s, struct tep_record *record) +void tep_data_latency_format(struct tep_handle *tep, + struct trace_seq *s, struct tep_record *record) { static int check_lock_depth = 1; static int check_migrate_disable = 1; @@ -5195,13 +5195,13 @@ void tep_data_lat_fmt(struct tep_handle *pevent, int softirq; void *data = record->data; - lat_flags = parse_common_flags(pevent, data); - pc = parse_common_pc(pevent, data); + lat_flags = parse_common_flags(tep, data); + pc = parse_common_pc(tep, data); /* lock_depth may not always exist */ if (lock_depth_exists) - lock_depth = parse_common_lock_depth(pevent, data); + lock_depth = parse_common_lock_depth(tep, data); else if (check_lock_depth) { - lock_depth = parse_common_lock_depth(pevent, data); + lock_depth = parse_common_lock_depth(tep, data); if (lock_depth < 0) check_lock_depth = 0; else @@ -5210,9 +5210,9 @@ void tep_data_lat_fmt(struct tep_handle *pevent, /* migrate_disable may not always exist */ if (migrate_disable_exists) - migrate_disable = parse_common_migrate_disable(pevent, data); + migrate_disable = parse_common_migrate_disable(tep, data); else if (check_migrate_disable) { - migrate_disable = parse_common_migrate_disable(pevent, data); + migrate_disable = parse_common_migrate_disable(tep, data); if (migrate_disable < 0) check_migrate_disable = 0; else @@ -5255,79 +5255,79 @@ void tep_data_lat_fmt(struct tep_handle *pevent, /** * tep_data_type - parse out the given event type - * @pevent: a handle to the pevent + * @tep: a handle to the trace event parser context * @rec: the record to read from * * This returns the event id from the @rec. */ -int tep_data_type(struct tep_handle *pevent, struct tep_record *rec) +int tep_data_type(struct tep_handle *tep, struct tep_record *rec) { - return trace_parse_common_type(pevent, rec->data); + return trace_parse_common_type(tep, rec->data); } /** * tep_data_pid - parse the PID from record - * @pevent: a handle to the pevent + * @tep: a handle to the trace event parser context * @rec: the record to parse * * This returns the PID from a record. */ -int tep_data_pid(struct tep_handle *pevent, struct tep_record *rec) +int tep_data_pid(struct tep_handle *tep, struct tep_record *rec) { - return parse_common_pid(pevent, rec->data); + return parse_common_pid(tep, rec->data); } /** * tep_data_preempt_count - parse the preempt count from the record - * @pevent: a handle to the pevent + * @tep: a handle to the trace event parser context * @rec: the record to parse * * This returns the preempt count from a record. */ -int tep_data_preempt_count(struct tep_handle *pevent, struct tep_record *rec) +int tep_data_preempt_count(struct tep_handle *tep, struct tep_record *rec) { - return parse_common_pc(pevent, rec->data); + return parse_common_pc(tep, rec->data); } /** * tep_data_flags - parse the latency flags from the record - * @pevent: a handle to the pevent + * @tep: a handle to the trace event parser context * @rec: the record to parse * * This returns the latency flags from a record. * * Use trace_flag_type enum for the flags (see event-parse.h). */ -int tep_data_flags(struct tep_handle *pevent, struct tep_record *rec) +int tep_data_flags(struct tep_handle *tep, struct tep_record *rec) { - return parse_common_flags(pevent, rec->data); + return parse_common_flags(tep, rec->data); } /** * tep_data_comm_from_pid - return the command line from PID - * @pevent: a handle to the pevent + * @tep: a handle to the trace event parser context * @pid: the PID of the task to search for * * This returns a pointer to the command line that has the given * @pid. */ -const char *tep_data_comm_from_pid(struct tep_handle *pevent, int pid) +const char *tep_data_comm_from_pid(struct tep_handle *tep, int pid) { const char *comm; - comm = find_cmdline(pevent, pid); + comm = find_cmdline(tep, pid); return comm; } static struct tep_cmdline * -pid_from_cmdlist(struct tep_handle *pevent, const char *comm, struct tep_cmdline *next) +pid_from_cmdlist(struct tep_handle *tep, const char *comm, struct tep_cmdline *next) { struct cmdline_list *cmdlist = (struct cmdline_list *)next; if (cmdlist) cmdlist = cmdlist->next; else - cmdlist = pevent->cmdlist; + cmdlist = tep->cmdlist; while (cmdlist && strcmp(cmdlist->comm, comm) != 0) cmdlist = cmdlist->next; @@ -5337,7 +5337,7 @@ pid_from_cmdlist(struct tep_handle *pevent, const char *comm, struct tep_cmdline /** * tep_data_pid_from_comm - return the pid from a given comm - * @pevent: a handle to the pevent + * @tep: a handle to the trace event parser context * @comm: the cmdline to find the pid from * @next: the cmdline structure to find the next comm * @@ -5348,7 +5348,7 @@ pid_from_cmdlist(struct tep_handle *pevent, const char *comm, struct tep_cmdline * next pid. * Also, it does a linear search, so it may be slow. */ -struct tep_cmdline *tep_data_pid_from_comm(struct tep_handle *pevent, const char *comm, +struct tep_cmdline *tep_data_pid_from_comm(struct tep_handle *tep, const char *comm, struct tep_cmdline *next) { struct tep_cmdline *cmdline; @@ -5357,25 +5357,25 @@ struct tep_cmdline *tep_data_pid_from_comm(struct tep_handle *pevent, const char * If the cmdlines have not been converted yet, then use * the list. */ - if (!pevent->cmdlines) - return pid_from_cmdlist(pevent, comm, next); + if (!tep->cmdlines) + return pid_from_cmdlist(tep, comm, next); if (next) { /* * The next pointer could have been still from * a previous call before cmdlines were created */ - if (next < pevent->cmdlines || - next >= pevent->cmdlines + pevent->cmdline_count) + if (next < tep->cmdlines || + next >= tep->cmdlines + tep->cmdline_count) next = NULL; else cmdline = next++; } if (!next) - cmdline = pevent->cmdlines; + cmdline = tep->cmdlines; - while (cmdline < pevent->cmdlines + pevent->cmdline_count) { + while (cmdline < tep->cmdlines + tep->cmdline_count) { if (strcmp(cmdline->comm, comm) == 0) return cmdline; cmdline++; @@ -5385,12 +5385,13 @@ struct tep_cmdline *tep_data_pid_from_comm(struct tep_handle *pevent, const char /** * tep_cmdline_pid - return the pid associated to a given cmdline + * @tep: a handle to the trace event parser context * @cmdline: The cmdline structure to get the pid from * * Returns the pid for a give cmdline. If @cmdline is NULL, then * -1 is returned. */ -int tep_cmdline_pid(struct tep_handle *pevent, struct tep_cmdline *cmdline) +int tep_cmdline_pid(struct tep_handle *tep, struct tep_cmdline *cmdline) { struct cmdline_list *cmdlist = (struct cmdline_list *)cmdline; @@ -5401,9 +5402,9 @@ int tep_cmdline_pid(struct tep_handle *pevent, struct tep_cmdline *cmdline) * If cmdlines have not been created yet, or cmdline is * not part of the array, then treat it as a cmdlist instead. */ - if (!pevent->cmdlines || - cmdline < pevent->cmdlines || - cmdline >= pevent->cmdlines + pevent->cmdline_count) + if (!tep->cmdlines || + cmdline < tep->cmdlines || + cmdline >= tep->cmdlines + tep->cmdline_count) return cmdlist->pid; return cmdline->pid; @@ -5423,7 +5424,7 @@ void tep_event_info(struct trace_seq *s, struct tep_event *event, { int print_pretty = 1; - if (event->pevent->print_raw || (event->flags & TEP_EVENT_FL_PRINTRAW)) + if (event->tep->print_raw || (event->flags & TEP_EVENT_FL_PRINTRAW)) tep_print_fields(s, record->data, record->size, event); else { @@ -5444,7 +5445,8 @@ static bool is_timestamp_in_us(char *trace_clock, bool use_trace_clock) return true; if (!strcmp(trace_clock, "local") || !strcmp(trace_clock, "global") - || !strcmp(trace_clock, "uptime") || !strcmp(trace_clock, "perf")) + || !strcmp(trace_clock, "uptime") || !strcmp(trace_clock, "perf") + || !strncmp(trace_clock, "mono", 4)) return true; /* trace_clock is setting in tsc or counter mode */ @@ -5453,14 +5455,14 @@ static bool is_timestamp_in_us(char *trace_clock, bool use_trace_clock) /** * tep_find_event_by_record - return the event from a given record - * @pevent: a handle to the pevent + * @tep: a handle to the trace event parser context * @record: The record to get the event from * * Returns the associated event for a given record, or NULL if non is * is found. */ struct tep_event * -tep_find_event_by_record(struct tep_handle *pevent, struct tep_record *record) +tep_find_event_by_record(struct tep_handle *tep, struct tep_record *record) { int type; @@ -5469,21 +5471,21 @@ tep_find_event_by_record(struct tep_handle *pevent, struct tep_record *record) return NULL; } - type = trace_parse_common_type(pevent, record->data); + type = trace_parse_common_type(tep, record->data); - return tep_find_event(pevent, type); + return tep_find_event(tep, type); } /** * tep_print_event_task - Write the event task comm, pid and CPU - * @pevent: a handle to the pevent + * @tep: a handle to the trace event parser context * @s: the trace_seq to write to * @event: the handle to the record's event * @record: The record to get the event from * * Writes the tasks comm, pid and CPU to @s. */ -void tep_print_event_task(struct tep_handle *pevent, struct trace_seq *s, +void tep_print_event_task(struct tep_handle *tep, struct trace_seq *s, struct tep_event *event, struct tep_record *record) { @@ -5491,27 +5493,26 @@ void tep_print_event_task(struct tep_handle *pevent, struct trace_seq *s, const char *comm; int pid; - pid = parse_common_pid(pevent, data); - comm = find_cmdline(pevent, pid); + pid = parse_common_pid(tep, data); + comm = find_cmdline(tep, pid); - if (pevent->latency_format) { - trace_seq_printf(s, "%8.8s-%-5d %3d", - comm, pid, record->cpu); - } else + if (tep->latency_format) + trace_seq_printf(s, "%8.8s-%-5d %3d", comm, pid, record->cpu); + else trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu); } /** * tep_print_event_time - Write the event timestamp - * @pevent: a handle to the pevent + * @tep: a handle to the trace event parser context * @s: the trace_seq to write to * @event: the handle to the record's event * @record: The record to get the event from - * @use_trace_clock: Set to parse according to the @pevent->trace_clock + * @use_trace_clock: Set to parse according to the @tep->trace_clock * * Writes the timestamp of the record into @s. */ -void tep_print_event_time(struct tep_handle *pevent, struct trace_seq *s, +void tep_print_event_time(struct tep_handle *tep, struct trace_seq *s, struct tep_event *event, struct tep_record *record, bool use_trace_clock) @@ -5522,19 +5523,18 @@ void tep_print_event_time(struct tep_handle *pevent, struct trace_seq *s, int p; bool use_usec_format; - use_usec_format = is_timestamp_in_us(pevent->trace_clock, - use_trace_clock); + use_usec_format = is_timestamp_in_us(tep->trace_clock, use_trace_clock); if (use_usec_format) { secs = record->ts / NSEC_PER_SEC; nsecs = record->ts - secs * NSEC_PER_SEC; } - if (pevent->latency_format) { - tep_data_lat_fmt(pevent, s, record); + if (tep->latency_format) { + tep_data_latency_format(tep, s, record); } if (use_usec_format) { - if (pevent->flags & TEP_NSEC_OUTPUT) { + if (tep->flags & TEP_NSEC_OUTPUT) { usecs = nsecs; p = 9; } else { @@ -5554,14 +5554,14 @@ void tep_print_event_time(struct tep_handle *pevent, struct trace_seq *s, /** * tep_print_event_data - Write the event data section - * @pevent: a handle to the pevent + * @tep: a handle to the trace event parser context * @s: the trace_seq to write to * @event: the handle to the record's event * @record: The record to get the event from * * Writes the parsing of the record's data to @s. */ -void tep_print_event_data(struct tep_handle *pevent, struct trace_seq *s, +void tep_print_event_data(struct tep_handle *tep, struct trace_seq *s, struct tep_event *event, struct tep_record *record) { @@ -5578,15 +5578,15 @@ void tep_print_event_data(struct tep_handle *pevent, struct trace_seq *s, tep_event_info(s, event, record); } -void tep_print_event(struct tep_handle *pevent, struct trace_seq *s, +void tep_print_event(struct tep_handle *tep, struct trace_seq *s, struct tep_record *record, bool use_trace_clock) { struct tep_event *event; - event = tep_find_event_by_record(pevent, record); + event = tep_find_event_by_record(tep, record); if (!event) { int i; - int type = trace_parse_common_type(pevent, record->data); + int type = trace_parse_common_type(tep, record->data); do_warning("ug! no event found for type %d", type); trace_seq_printf(s, "[UNKNOWN TYPE %d]", type); @@ -5596,9 +5596,9 @@ void tep_print_event(struct tep_handle *pevent, struct trace_seq *s, return; } - tep_print_event_task(pevent, s, event, record); - tep_print_event_time(pevent, s, event, record, use_trace_clock); - tep_print_event_data(pevent, s, event, record); + tep_print_event_task(tep, s, event, record); + tep_print_event_time(tep, s, event, record, use_trace_clock); + tep_print_event_data(tep, s, event, record); } static int events_id_cmp(const void *a, const void *b) @@ -5649,32 +5649,26 @@ static int events_system_cmp(const void *a, const void *b) return events_id_cmp(a, b); } -struct tep_event **tep_list_events(struct tep_handle *pevent, enum tep_event_sort_type sort_type) +static struct tep_event **list_events_copy(struct tep_handle *tep) { struct tep_event **events; - int (*sort)(const void *a, const void *b); - - events = pevent->sort_events; - - if (events && pevent->last_type == sort_type) - return events; - if (!events) { - events = malloc(sizeof(*events) * (pevent->nr_events + 1)); - if (!events) - return NULL; + if (!tep) + return NULL; - memcpy(events, pevent->events, sizeof(*events) * pevent->nr_events); - events[pevent->nr_events] = NULL; + events = malloc(sizeof(*events) * (tep->nr_events + 1)); + if (!events) + return NULL; - pevent->sort_events = events; + memcpy(events, tep->events, sizeof(*events) * tep->nr_events); + events[tep->nr_events] = NULL; + return events; +} - /* the internal events are sorted by id */ - if (sort_type == TEP_EVENT_SORT_ID) { - pevent->last_type = sort_type; - return events; - } - } +static void list_events_sort(struct tep_event **events, int nr_events, + enum tep_event_sort_type sort_type) +{ + int (*sort)(const void *a, const void *b); switch (sort_type) { case TEP_EVENT_SORT_ID: @@ -5687,11 +5681,82 @@ struct tep_event **tep_list_events(struct tep_handle *pevent, enum tep_event_sor sort = events_system_cmp; break; default: + sort = NULL; + } + + if (sort) + qsort(events, nr_events, sizeof(*events), sort); +} + +/** + * tep_list_events - Get events, sorted by given criteria. + * @tep: a handle to the tep context + * @sort_type: desired sort order of the events in the array + * + * Returns an array of pointers to all events, sorted by the given + * @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. + */ +struct tep_event **tep_list_events(struct tep_handle *tep, + enum tep_event_sort_type sort_type) +{ + struct tep_event **events; + + if (!tep) + return NULL; + + events = tep->sort_events; + if (events && tep->last_type == sort_type) return events; + + if (!events) { + events = list_events_copy(tep); + if (!events) + return NULL; + + tep->sort_events = events; + + /* the internal events are sorted by id */ + if (sort_type == TEP_EVENT_SORT_ID) { + tep->last_type = sort_type; + return events; + } } - qsort(events, pevent->nr_events, sizeof(*events), sort); - pevent->last_type = sort_type; + list_events_sort(events, tep->nr_events, sort_type); + tep->last_type = sort_type; + + return events; +} + + +/** + * tep_list_events_copy - Thread safe version of tep_list_events() + * @tep: a handle to the tep context + * @sort_type: desired sort order of the events in the array + * + * Returns an array of pointers to all events, sorted by the given + * @sort_type criteria. The last element of the array is NULL. The returned + * array is newly allocated inside the function and must be freed by the caller + */ +struct tep_event **tep_list_events_copy(struct tep_handle *tep, + enum tep_event_sort_type sort_type) +{ + struct tep_event **events; + + if (!tep) + return NULL; + + events = list_events_copy(tep); + if (!events) + return NULL; + + /* the internal events are sorted by id */ + if (sort_type == TEP_EVENT_SORT_ID) + return events; + + list_events_sort(events, tep->nr_events, sort_type); return events; } @@ -5950,7 +6015,7 @@ static void parse_header_field(const char *field, /** * tep_parse_header_page - parse the data stored in the header page - * @pevent: the handle to the pevent + * @tep: a handle to the trace event parser context * @buf: the buffer storing the header page format string * @size: the size of @buf * @long_size: the long size to use if there is no header @@ -5960,7 +6025,7 @@ static void parse_header_field(const char *field, * * /sys/kernel/debug/tracing/events/header_page */ -int tep_parse_header_page(struct tep_handle *pevent, char *buf, unsigned long size, +int tep_parse_header_page(struct tep_handle *tep, char *buf, unsigned long size, int long_size) { int ignore; @@ -5970,22 +6035,22 @@ int tep_parse_header_page(struct tep_handle *pevent, char *buf, unsigned long si * Old kernels did not have header page info. * Sorry but we just use what we find here in user space. */ - pevent->header_page_ts_size = sizeof(long long); - pevent->header_page_size_size = long_size; - pevent->header_page_data_offset = sizeof(long long) + long_size; - pevent->old_format = 1; + tep->header_page_ts_size = sizeof(long long); + tep->header_page_size_size = long_size; + tep->header_page_data_offset = sizeof(long long) + long_size; + tep->old_format = 1; return -1; } init_input_buf(buf, size); - parse_header_field("timestamp", &pevent->header_page_ts_offset, - &pevent->header_page_ts_size, 1); - parse_header_field("commit", &pevent->header_page_size_offset, - &pevent->header_page_size_size, 1); - parse_header_field("overwrite", &pevent->header_page_overwrite, + parse_header_field("timestamp", &tep->header_page_ts_offset, + &tep->header_page_ts_size, 1); + parse_header_field("commit", &tep->header_page_size_offset, + &tep->header_page_size_size, 1); + parse_header_field("overwrite", &tep->header_page_overwrite, &ignore, 0); - parse_header_field("data", &pevent->header_page_data_offset, - &pevent->header_page_data_size, 1); + parse_header_field("data", &tep->header_page_data_offset, + &tep->header_page_data_size, 1); return 0; } @@ -6013,11 +6078,11 @@ static void free_handler(struct event_handler *handle) free(handle); } -static int find_event_handle(struct tep_handle *pevent, struct tep_event *event) +static int find_event_handle(struct tep_handle *tep, struct tep_event *event) { struct event_handler *handle, **next; - for (next = &pevent->handlers; *next; + for (next = &tep->handlers; *next; next = &(*next)->next) { handle = *next; if (event_matches(event, handle->id, @@ -6055,7 +6120,7 @@ static int find_event_handle(struct tep_handle *pevent, struct tep_event *event) * /sys/kernel/debug/tracing/events/.../.../format */ enum tep_errno __tep_parse_format(struct tep_event **eventp, - struct tep_handle *pevent, const char *buf, + struct tep_handle *tep, const char *buf, unsigned long size, const char *sys) { struct tep_event *event; @@ -6097,8 +6162,8 @@ enum tep_errno __tep_parse_format(struct tep_event **eventp, goto event_alloc_failed; } - /* Add pevent to event so that it can be referenced */ - event->pevent = pevent; + /* Add tep to event so that it can be referenced */ + event->tep = tep; ret = event_read_format(event); if (ret < 0) { @@ -6110,7 +6175,7 @@ enum tep_errno __tep_parse_format(struct tep_event **eventp, * If the event has an override, don't print warnings if the event * print format fails to parse. */ - if (pevent && find_event_handle(pevent, event)) + if (tep && find_event_handle(tep, event)) show_warning = 0; ret = event_read_print(event); @@ -6162,18 +6227,18 @@ enum tep_errno __tep_parse_format(struct tep_event **eventp, } static enum tep_errno -__parse_event(struct tep_handle *pevent, +__parse_event(struct tep_handle *tep, struct tep_event **eventp, const char *buf, unsigned long size, const char *sys) { - int ret = __tep_parse_format(eventp, pevent, buf, size, sys); + int ret = __tep_parse_format(eventp, tep, buf, size, sys); struct tep_event *event = *eventp; if (event == NULL) return ret; - if (pevent && add_event(pevent, event)) { + if (tep && add_event(tep, event)) { ret = TEP_ERRNO__MEM_ALLOC_FAILED; goto event_add_failed; } @@ -6191,7 +6256,7 @@ event_add_failed: /** * tep_parse_format - parse the event format - * @pevent: the handle to the pevent + * @tep: a handle to the trace event parser context * @eventp: returned format * @buf: the buffer storing the event format string * @size: the size of @buf @@ -6204,17 +6269,17 @@ event_add_failed: * * /sys/kernel/debug/tracing/events/.../.../format */ -enum tep_errno tep_parse_format(struct tep_handle *pevent, +enum tep_errno tep_parse_format(struct tep_handle *tep, struct tep_event **eventp, const char *buf, unsigned long size, const char *sys) { - return __parse_event(pevent, eventp, buf, size, sys); + return __parse_event(tep, eventp, buf, size, sys); } /** * tep_parse_event - parse the event format - * @pevent: the handle to the pevent + * @tep: a handle to the trace event parser context * @buf: the buffer storing the event format string * @size: the size of @buf * @sys: the system the event belongs to @@ -6226,11 +6291,11 @@ enum tep_errno tep_parse_format(struct tep_handle *pevent, * * /sys/kernel/debug/tracing/events/.../.../format */ -enum tep_errno tep_parse_event(struct tep_handle *pevent, const char *buf, +enum tep_errno tep_parse_event(struct tep_handle *tep, const char *buf, unsigned long size, const char *sys) { struct tep_event *event = NULL; - return __parse_event(pevent, &event, buf, size, sys); + return __parse_event(tep, &event, buf, size, sys); } int get_field_val(struct trace_seq *s, struct tep_format_field *field, @@ -6292,8 +6357,8 @@ void *tep_get_field_raw(struct trace_seq *s, struct tep_event *event, offset = field->offset; if (field->flags & TEP_FIELD_IS_DYNAMIC) { - offset = tep_read_number(event->pevent, - data + offset, field->size); + offset = tep_read_number(event->tep, + data + offset, field->size); *len = offset >> 16; offset &= 0xffff; } else @@ -6386,7 +6451,8 @@ int tep_get_any_field_val(struct trace_seq *s, struct tep_event *event, * @record: The record with the field name. * @err: print default error if failed. * - * Returns: 0 on success, -1 field not found, or 1 if buffer is full. + * Returns positive value on success, negative in case of an error, + * or 0 if buffer is full. */ int tep_print_num_field(struct trace_seq *s, const char *fmt, struct tep_event *event, const char *name, @@ -6418,14 +6484,15 @@ int tep_print_num_field(struct trace_seq *s, const char *fmt, * @record: The record with the field name. * @err: print default error if failed. * - * Returns: 0 on success, -1 field not found, or 1 if buffer is full. + * Returns positive value on success, negative in case of an error, + * or 0 if buffer is full. */ 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) { struct tep_format_field *field = tep_find_field(event, name); - struct tep_handle *pevent = event->pevent; + struct tep_handle *tep = event->tep; unsigned long long val; struct func_map *func; char tmp[128]; @@ -6436,7 +6503,7 @@ int tep_print_func_field(struct trace_seq *s, const char *fmt, if (tep_read_number_field(field, record->data, &val)) goto failed; - func = find_func(pevent, val); + func = find_func(tep, val); if (func) snprintf(tmp, 128, "%s/0x%llx", func->func, func->addr - val); @@ -6468,7 +6535,7 @@ static void free_func_handle(struct tep_function_handler *func) /** * tep_register_print_function - register a helper function - * @pevent: the handle to the pevent + * @tep: a handle to the trace event parser context * @func: the function to process the helper function * @ret_type: the return type of the helper function * @name: the name of the helper function @@ -6481,7 +6548,7 @@ static void free_func_handle(struct tep_function_handler *func) * The @parameters is a variable list of tep_func_arg_type enums that * must end with TEP_FUNC_ARG_VOID. */ -int tep_register_print_function(struct tep_handle *pevent, +int tep_register_print_function(struct tep_handle *tep, tep_func_handler func, enum tep_func_arg_type ret_type, char *name, ...) @@ -6493,7 +6560,7 @@ int tep_register_print_function(struct tep_handle *pevent, va_list ap; int ret; - func_handle = find_func_handler(pevent, name); + func_handle = find_func_handler(tep, name); if (func_handle) { /* * This is most like caused by the users own @@ -6501,7 +6568,7 @@ int tep_register_print_function(struct tep_handle *pevent, * system defaults. */ pr_stat("override of function helper '%s'", name); - remove_func_handler(pevent, name); + remove_func_handler(tep, name); } func_handle = calloc(1, sizeof(*func_handle)); @@ -6548,8 +6615,8 @@ int tep_register_print_function(struct tep_handle *pevent, } va_end(ap); - func_handle->next = pevent->func_handlers; - pevent->func_handlers = func_handle; + func_handle->next = tep->func_handlers; + tep->func_handlers = func_handle; return 0; out_free: @@ -6560,7 +6627,7 @@ int tep_register_print_function(struct tep_handle *pevent, /** * tep_unregister_print_function - unregister a helper function - * @pevent: the handle to the pevent + * @tep: a handle to the trace event parser context * @func: the function to process the helper function * @name: the name of the helper function * @@ -6568,20 +6635,20 @@ int tep_register_print_function(struct tep_handle *pevent, * * Returns 0 if the handler was removed successully, -1 otherwise. */ -int tep_unregister_print_function(struct tep_handle *pevent, +int tep_unregister_print_function(struct tep_handle *tep, tep_func_handler func, char *name) { struct tep_function_handler *func_handle; - func_handle = find_func_handler(pevent, name); + func_handle = find_func_handler(tep, name); if (func_handle && func_handle->func == func) { - remove_func_handler(pevent, name); + remove_func_handler(tep, name); return 0; } return -1; } -static struct tep_event *search_event(struct tep_handle *pevent, int id, +static struct tep_event *search_event(struct tep_handle *tep, int id, const char *sys_name, const char *event_name) { @@ -6589,7 +6656,7 @@ static struct tep_event *search_event(struct tep_handle *pevent, int id, if (id >= 0) { /* search by id */ - event = tep_find_event(pevent, id); + event = tep_find_event(tep, id); if (!event) return NULL; if (event_name && (strcmp(event_name, event->name) != 0)) @@ -6597,7 +6664,7 @@ static struct tep_event *search_event(struct tep_handle *pevent, int id, if (sys_name && (strcmp(sys_name, event->system) != 0)) return NULL; } else { - event = tep_find_event_by_name(pevent, sys_name, event_name); + event = tep_find_event_by_name(tep, sys_name, event_name); if (!event) return NULL; } @@ -6606,7 +6673,7 @@ static struct tep_event *search_event(struct tep_handle *pevent, int id, /** * tep_register_event_handler - register a way to parse an event - * @pevent: the handle to the pevent + * @tep: a handle to the trace event parser context * @id: the id of the event to register * @sys_name: the system name the event belongs to * @event_name: the name of the event @@ -6627,14 +6694,14 @@ static struct tep_event *search_event(struct tep_handle *pevent, int id, * negative TEP_ERRNO_... in case of an error * */ -int tep_register_event_handler(struct tep_handle *pevent, int id, +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) { struct tep_event *event; struct event_handler *handle; - event = search_event(pevent, id, sys_name, event_name); + event = search_event(tep, id, sys_name, event_name); if (event == NULL) goto not_found; @@ -6669,8 +6736,8 @@ int tep_register_event_handler(struct tep_handle *pevent, int id, } handle->func = func; - handle->next = pevent->handlers; - pevent->handlers = handle; + handle->next = tep->handlers; + tep->handlers = handle; handle->context = context; return TEP_REGISTER_SUCCESS; @@ -6697,7 +6764,7 @@ static int handle_matches(struct event_handler *handler, int id, /** * tep_unregister_event_handler - unregister an existing event handler - * @pevent: the handle to the pevent + * @tep: a handle to the trace event parser context * @id: the id of the event to unregister * @sys_name: the system name the handler belongs to * @event_name: the name of the event handler @@ -6711,7 +6778,7 @@ static int handle_matches(struct event_handler *handler, int id, * * Returns 0 if handler was removed successfully, -1 if event was not found. */ -int tep_unregister_event_handler(struct tep_handle *pevent, int id, +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) { @@ -6719,7 +6786,7 @@ int tep_unregister_event_handler(struct tep_handle *pevent, int id, struct event_handler *handle; struct event_handler **next; - event = search_event(pevent, id, sys_name, event_name); + event = search_event(tep, id, sys_name, event_name); if (event == NULL) goto not_found; @@ -6733,7 +6800,7 @@ int tep_unregister_event_handler(struct tep_handle *pevent, int id, } not_found: - for (next = &pevent->handlers; *next; next = &(*next)->next) { + for (next = &tep->handlers; *next; next = &(*next)->next) { handle = *next; if (handle_matches(handle, id, sys_name, event_name, func, context)) @@ -6750,23 +6817,23 @@ not_found: } /** - * tep_alloc - create a pevent handle + * tep_alloc - create a tep handle */ struct tep_handle *tep_alloc(void) { - struct tep_handle *pevent = calloc(1, sizeof(*pevent)); + struct tep_handle *tep = calloc(1, sizeof(*tep)); - if (pevent) { - pevent->ref_count = 1; - pevent->host_bigendian = tep_host_bigendian(); + if (tep) { + tep->ref_count = 1; + tep->host_bigendian = tep_is_bigendian(); } - return pevent; + return tep; } -void tep_ref(struct tep_handle *pevent) +void tep_ref(struct tep_handle *tep) { - pevent->ref_count++; + tep->ref_count++; } int tep_get_ref(struct tep_handle *tep) @@ -6816,10 +6883,10 @@ void tep_free_event(struct tep_event *event) } /** - * tep_free - free a pevent handle - * @pevent: the pevent handle to free + * tep_free - free a tep handle + * @tep: the tep handle to free */ -void tep_free(struct tep_handle *pevent) +void tep_free(struct tep_handle *tep) { struct cmdline_list *cmdlist, *cmdnext; struct func_list *funclist, *funcnext; @@ -6828,21 +6895,21 @@ void tep_free(struct tep_handle *pevent) struct event_handler *handle; int i; - if (!pevent) + if (!tep) return; - cmdlist = pevent->cmdlist; - funclist = pevent->funclist; - printklist = pevent->printklist; + cmdlist = tep->cmdlist; + funclist = tep->funclist; + printklist = tep->printklist; - pevent->ref_count--; - if (pevent->ref_count) + tep->ref_count--; + if (tep->ref_count) return; - if (pevent->cmdlines) { - for (i = 0; i < pevent->cmdline_count; i++) - free(pevent->cmdlines[i].comm); - free(pevent->cmdlines); + if (tep->cmdlines) { + for (i = 0; i < tep->cmdline_count; i++) + free(tep->cmdlines[i].comm); + free(tep->cmdlines); } while (cmdlist) { @@ -6852,12 +6919,12 @@ void tep_free(struct tep_handle *pevent) cmdlist = cmdnext; } - if (pevent->func_map) { - for (i = 0; i < (int)pevent->func_count; i++) { - free(pevent->func_map[i].func); - free(pevent->func_map[i].mod); + if (tep->func_map) { + for (i = 0; i < (int)tep->func_count; i++) { + free(tep->func_map[i].func); + free(tep->func_map[i].mod); } - free(pevent->func_map); + free(tep->func_map); } while (funclist) { @@ -6868,16 +6935,16 @@ void tep_free(struct tep_handle *pevent) funclist = funcnext; } - while (pevent->func_handlers) { - func_handler = pevent->func_handlers; - pevent->func_handlers = func_handler->next; + while (tep->func_handlers) { + func_handler = tep->func_handlers; + tep->func_handlers = func_handler->next; free_func_handle(func_handler); } - if (pevent->printk_map) { - for (i = 0; i < (int)pevent->printk_count; i++) - free(pevent->printk_map[i].printk); - free(pevent->printk_map); + if (tep->printk_map) { + for (i = 0; i < (int)tep->printk_count; i++) + free(tep->printk_map[i].printk); + free(tep->printk_map); } while (printklist) { @@ -6887,24 +6954,24 @@ void tep_free(struct tep_handle *pevent) printklist = printknext; } - for (i = 0; i < pevent->nr_events; i++) - tep_free_event(pevent->events[i]); + for (i = 0; i < tep->nr_events; i++) + tep_free_event(tep->events[i]); - while (pevent->handlers) { - handle = pevent->handlers; - pevent->handlers = handle->next; + while (tep->handlers) { + handle = tep->handlers; + tep->handlers = handle->next; free_handler(handle); } - free(pevent->trace_clock); - free(pevent->events); - free(pevent->sort_events); - free(pevent->func_resolver); + free(tep->trace_clock); + free(tep->events); + free(tep->sort_events); + free(tep->func_resolver); - free(pevent); + free(tep); } -void tep_unref(struct tep_handle *pevent) +void tep_unref(struct tep_handle *tep) { - tep_free(pevent); + tep_free(tep); } diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index aec48f2aea8a..642f68ab5fb2 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -64,8 +64,8 @@ typedef int (*tep_event_handler_func)(struct trace_seq *s, struct tep_event *event, void *context); -typedef int (*tep_plugin_load_func)(struct tep_handle *pevent); -typedef int (*tep_plugin_unload_func)(struct tep_handle *pevent); +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; @@ -85,12 +85,12 @@ struct tep_plugin_option { * TEP_PLUGIN_LOADER: (required) * The function name to initialized the plugin. * - * int TEP_PLUGIN_LOADER(struct tep_handle *pevent) + * 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 *pevent) + * int TEP_PLUGIN_UNLOADER(struct tep_handle *tep) * * TEP_PLUGIN_OPTIONS: (optional) * Plugin options that can be set before loading @@ -278,7 +278,7 @@ struct tep_print_fmt { }; struct tep_event { - struct tep_handle *pevent; + struct tep_handle *tep; char *name; int id; int flags; @@ -393,9 +393,9 @@ struct tep_plugin_list; #define INVALID_PLUGIN_LIST_OPTION ((char **)((unsigned long)-1)) -struct tep_plugin_list *tep_load_plugins(struct tep_handle *pevent); +struct tep_plugin_list *tep_load_plugins(struct tep_handle *tep); void tep_unload_plugins(struct tep_plugin_list *plugin_list, - struct tep_handle *pevent); + struct tep_handle *tep); char **tep_plugin_list_options(void); void tep_plugin_free_options_list(char **list); int tep_plugin_add_options(const char *name, @@ -409,8 +409,10 @@ void tep_print_plugins(struct trace_seq *s, 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_host_bigendian(void) +static inline int tep_is_bigendian(void) { unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 }; unsigned int val; @@ -428,37 +430,37 @@ enum trace_flag_type { TRACE_FLAG_SOFTIRQ = 0x10, }; -int tep_set_function_resolver(struct tep_handle *pevent, +int tep_set_function_resolver(struct tep_handle *tep, tep_func_resolver_t *func, void *priv); -void tep_reset_function_resolver(struct tep_handle *pevent); -int tep_register_comm(struct tep_handle *pevent, const char *comm, int pid); -int tep_override_comm(struct tep_handle *pevent, const char *comm, int pid); -int tep_register_trace_clock(struct tep_handle *pevent, const char *trace_clock); -int tep_register_function(struct tep_handle *pevent, char *name, +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_trace_clock(struct tep_handle *tep, const char *trace_clock); +int tep_register_function(struct tep_handle *tep, char *name, unsigned long long addr, char *mod); -int tep_register_print_string(struct tep_handle *pevent, const char *fmt, +int tep_register_print_string(struct tep_handle *tep, const char *fmt, unsigned long long addr); -int tep_pid_is_registered(struct tep_handle *pevent, int pid); +bool tep_is_pid_registered(struct tep_handle *tep, int pid); -void tep_print_event_task(struct tep_handle *pevent, struct trace_seq *s, +void tep_print_event_task(struct tep_handle *tep, struct trace_seq *s, struct tep_event *event, struct tep_record *record); -void tep_print_event_time(struct tep_handle *pevent, struct trace_seq *s, +void tep_print_event_time(struct tep_handle *tep, struct trace_seq *s, struct tep_event *event, struct tep_record *record, bool use_trace_clock); -void tep_print_event_data(struct tep_handle *pevent, struct trace_seq *s, +void tep_print_event_data(struct tep_handle *tep, struct trace_seq *s, struct tep_event *event, struct tep_record *record); -void tep_print_event(struct tep_handle *pevent, struct trace_seq *s, +void tep_print_event(struct tep_handle *tep, struct trace_seq *s, struct tep_record *record, bool use_trace_clock); -int tep_parse_header_page(struct tep_handle *pevent, char *buf, unsigned long size, +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 *pevent, const char *buf, +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 *pevent, +enum tep_errno tep_parse_format(struct tep_handle *tep, struct tep_event **eventp, const char *buf, unsigned long size, const char *sys); @@ -490,50 +492,50 @@ enum tep_reg_handler { TEP_REGISTER_SUCCESS_OVERWRITE, }; -int tep_register_event_handler(struct tep_handle *pevent, int id, +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 *pevent, int id, +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 *pevent, +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 *pevent, +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 *pevent, unsigned long long addr); +const char *tep_find_function(struct tep_handle *tep, unsigned long long addr); unsigned long long -tep_find_function_address(struct tep_handle *pevent, unsigned long long addr); -unsigned long long tep_read_number(struct tep_handle *pevent, const void *ptr, int size); +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 *pevent, int id); +struct tep_event *tep_find_event(struct tep_handle *tep, int id); struct tep_event * -tep_find_event_by_name(struct tep_handle *pevent, const char *sys, const char *name); +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 *pevent, struct tep_record *record); - -void tep_data_lat_fmt(struct tep_handle *pevent, - struct trace_seq *s, struct tep_record *record); -int tep_data_type(struct tep_handle *pevent, struct tep_record *rec); -int tep_data_pid(struct tep_handle *pevent, struct tep_record *rec); -int tep_data_preempt_count(struct tep_handle *pevent, struct tep_record *rec); -int tep_data_flags(struct tep_handle *pevent, struct tep_record *rec); -const char *tep_data_comm_from_pid(struct tep_handle *pevent, int pid); +tep_find_event_by_record(struct tep_handle *tep, struct tep_record *record); + +void tep_data_latency_format(struct tep_handle *tep, + struct trace_seq *s, 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 *pevent, const char *comm, +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 *pevent, struct tep_cmdline *cmdline); +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); @@ -541,10 +543,12 @@ void tep_print_fields(struct trace_seq *s, void *data, int size __maybe_unused, struct tep_event *event); void tep_event_info(struct trace_seq *s, struct tep_event *event, struct tep_record *record); -int tep_strerror(struct tep_handle *pevent, enum tep_errno errnum, +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 *pevent, enum tep_event_sort_type); +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); @@ -552,24 +556,28 @@ enum tep_endian { TEP_LITTLE_ENDIAN = 0, TEP_BIG_ENDIAN }; -int tep_get_cpus(struct tep_handle *pevent); -void tep_set_cpus(struct tep_handle *pevent, int cpus); -int tep_get_long_size(struct tep_handle *pevent); -void tep_set_long_size(struct tep_handle *pevent, int long_size); -int tep_get_page_size(struct tep_handle *pevent); -void tep_set_page_size(struct tep_handle *pevent, int _page_size); -int tep_file_bigendian(struct tep_handle *pevent); -void tep_set_file_bigendian(struct tep_handle *pevent, enum tep_endian endian); -int tep_is_host_bigendian(struct tep_handle *pevent); -void tep_set_host_bigendian(struct tep_handle *pevent, enum tep_endian endian); -int tep_is_latency_format(struct tep_handle *pevent); -void tep_set_latency_format(struct tep_handle *pevent, int lat); -int tep_get_header_page_size(struct tep_handle *pevent); +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); +bool tep_is_latency_format(struct tep_handle *tep); +void tep_set_latency_format(struct tep_handle *tep, int lat); +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_print_raw(struct tep_handle *tep, int print_raw); +void tep_set_test_filters(struct tep_handle *tep, int test_filters); struct tep_handle *tep_alloc(void); -void tep_free(struct tep_handle *pevent); -void tep_ref(struct tep_handle *pevent); -void tep_unref(struct tep_handle *pevent); +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); /* access to the internal parser */ @@ -581,8 +589,8 @@ const char *tep_get_input_buf(void); unsigned long long tep_get_input_buf_ptr(void); /* for debugging */ -void tep_print_funcs(struct tep_handle *pevent); -void tep_print_printk(struct tep_handle *pevent); +void tep_print_funcs(struct tep_handle *tep); +void tep_print_printk(struct tep_handle *tep); /* ----------------------- filtering ----------------------- */ @@ -709,13 +717,13 @@ struct tep_filter_type { #define TEP_FILTER_ERROR_BUFSZ 1024 struct tep_event_filter { - struct tep_handle *pevent; + 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 *pevent); +struct tep_event_filter *tep_filter_alloc(struct tep_handle *tep); /* for backward compatibility */ #define FILTER_NONE TEP_ERRNO__NO_FILTER @@ -723,12 +731,6 @@ struct tep_event_filter *tep_filter_alloc(struct tep_handle *pevent); #define FILTER_MISS TEP_ERRNO__FILTER_MISS #define FILTER_MATCH TEP_ERRNO__FILTER_MATCH -enum tep_filter_trivial_type { - TEP_FILTER_TRIVIAL_FALSE, - TEP_FILTER_TRIVIAL_TRUE, - TEP_FILTER_TRIVIAL_BOTH, -}; - enum tep_errno tep_filter_add_filter_str(struct tep_event_filter *filter, const char *filter_str); @@ -743,9 +745,6 @@ int tep_event_filtered(struct tep_event_filter *filter, void tep_filter_reset(struct tep_event_filter *filter); -int tep_filter_clear_trivial(struct tep_event_filter *filter, - enum tep_filter_trivial_type type); - void tep_filter_free(struct tep_event_filter *filter); char *tep_filter_make_string(struct tep_event_filter *filter, int event_id); @@ -753,15 +752,8 @@ 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_event_has_trivial(struct tep_event_filter *filter, - int event_id, - enum tep_filter_trivial_type type); - int tep_filter_copy(struct tep_event_filter *dest, struct tep_event_filter *source); -int tep_update_trivial(struct tep_event_filter *dest, struct tep_event_filter *source, - enum tep_filter_trivial_type type); - int tep_filter_compare(struct tep_event_filter *filter1, struct tep_event_filter *filter2); #endif /* _PARSE_EVENTS_H */ diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c index e74f16c88398..8ca28de9337a 100644 --- a/tools/lib/traceevent/event-plugin.c +++ b/tools/lib/traceevent/event-plugin.c @@ -269,7 +269,7 @@ void tep_print_plugins(struct trace_seq *s, } static void -load_plugin(struct tep_handle *pevent, const char *path, +load_plugin(struct tep_handle *tep, const char *path, const char *file, void *data) { struct tep_plugin_list **plugin_list = data; @@ -316,7 +316,7 @@ load_plugin(struct tep_handle *pevent, const char *path, *plugin_list = list; pr_stat("registering plugin: %s", plugin); - func(pevent); + func(tep); return; out_free: @@ -324,9 +324,9 @@ load_plugin(struct tep_handle *pevent, const char *path, } static void -load_plugins_dir(struct tep_handle *pevent, const char *suffix, +load_plugins_dir(struct tep_handle *tep, const char *suffix, const char *path, - void (*load_plugin)(struct tep_handle *pevent, + void (*load_plugin)(struct tep_handle *tep, const char *path, const char *name, void *data), @@ -359,15 +359,15 @@ load_plugins_dir(struct tep_handle *pevent, const char *suffix, if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0) continue; - load_plugin(pevent, path, name, data); + load_plugin(tep, path, name, data); } closedir(dir); } static void -load_plugins(struct tep_handle *pevent, const char *suffix, - void (*load_plugin)(struct tep_handle *pevent, +load_plugins(struct tep_handle *tep, const char *suffix, + void (*load_plugin)(struct tep_handle *tep, const char *path, const char *name, void *data), @@ -378,7 +378,7 @@ load_plugins(struct tep_handle *pevent, const char *suffix, char *envdir; int ret; - if (pevent->flags & TEP_DISABLE_PLUGINS) + if (tep->flags & TEP_DISABLE_PLUGINS) return; /* @@ -386,8 +386,8 @@ load_plugins(struct tep_handle *pevent, const char *suffix, * check that first. */ #ifdef PLUGIN_DIR - if (!(pevent->flags & TEP_DISABLE_SYS_PLUGINS)) - load_plugins_dir(pevent, suffix, PLUGIN_DIR, + if (!(tep->flags & TEP_DISABLE_SYS_PLUGINS)) + load_plugins_dir(tep, suffix, PLUGIN_DIR, load_plugin, data); #endif @@ -397,7 +397,7 @@ load_plugins(struct tep_handle *pevent, const char *suffix, */ envdir = getenv("TRACEEVENT_PLUGIN_DIR"); if (envdir) - load_plugins_dir(pevent, suffix, envdir, load_plugin, data); + load_plugins_dir(tep, suffix, envdir, load_plugin, data); /* * Now let the home directory override the environment @@ -413,22 +413,22 @@ load_plugins(struct tep_handle *pevent, const char *suffix, return; } - load_plugins_dir(pevent, suffix, path, load_plugin, data); + load_plugins_dir(tep, suffix, path, load_plugin, data); free(path); } struct tep_plugin_list* -tep_load_plugins(struct tep_handle *pevent) +tep_load_plugins(struct tep_handle *tep) { struct tep_plugin_list *list = NULL; - load_plugins(pevent, ".so", load_plugin, &list); + load_plugins(tep, ".so", load_plugin, &list); return list; } void -tep_unload_plugins(struct tep_plugin_list *plugin_list, struct tep_handle *pevent) +tep_unload_plugins(struct tep_plugin_list *plugin_list, struct tep_handle *tep) { tep_plugin_unload_func func; struct tep_plugin_list *list; @@ -438,7 +438,7 @@ tep_unload_plugins(struct tep_plugin_list *plugin_list, struct tep_handle *peven plugin_list = list->next; func = dlsym(list->handle, TEP_PLUGIN_UNLOADER_NAME); if (func) - func(pevent); + func(tep); dlclose(list->handle); free(list->name); free(list); diff --git a/tools/lib/traceevent/kbuffer-parse.c b/tools/lib/traceevent/kbuffer-parse.c index af2a1f3b7424..b887e7437d67 100644 --- a/tools/lib/traceevent/kbuffer-parse.c +++ b/tools/lib/traceevent/kbuffer-parse.c @@ -727,3 +727,52 @@ 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; +} diff --git a/tools/lib/traceevent/kbuffer.h b/tools/lib/traceevent/kbuffer.h index 03dce757553f..ed4d697fc137 100644 --- a/tools/lib/traceevent/kbuffer.h +++ b/tools/lib/traceevent/kbuffer.h @@ -65,4 +65,17 @@ 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 */ diff --git a/tools/lib/traceevent/libtraceevent.pc.template b/tools/lib/traceevent/libtraceevent.pc.template index 42e4d6cb6b9e..86384fcd57f1 100644 --- a/tools/lib/traceevent/libtraceevent.pc.template +++ b/tools/lib/traceevent/libtraceevent.pc.template @@ -1,6 +1,6 @@ prefix=INSTALL_PREFIX -libdir=${prefix}/lib64 -includedir=${prefix}/include/traceevent +libdir=LIB_DIR +includedir=HEADER_DIR Name: libtraceevent URL: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index cb5ce66dab6e..552592d153fb 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c @@ -154,7 +154,7 @@ add_filter_type(struct tep_event_filter *filter, int id) filter_type = &filter->event_filters[i]; filter_type->event_id = id; - filter_type->event = tep_find_event(filter->pevent, id); + filter_type->event = tep_find_event(filter->tep, id); filter_type->filter = NULL; filter->filters++; @@ -164,9 +164,9 @@ add_filter_type(struct tep_event_filter *filter, int id) /** * tep_filter_alloc - create a new event filter - * @pevent: The pevent that this filter is associated with + * @tep: The tep that this filter is associated with */ -struct tep_event_filter *tep_filter_alloc(struct tep_handle *pevent) +struct tep_event_filter *tep_filter_alloc(struct tep_handle *tep) { struct tep_event_filter *filter; @@ -175,8 +175,8 @@ struct tep_event_filter *tep_filter_alloc(struct tep_handle *pevent) return NULL; memset(filter, 0, sizeof(*filter)); - filter->pevent = pevent; - tep_ref(pevent); + filter->tep = tep; + tep_ref(tep); return filter; } @@ -256,7 +256,7 @@ static int event_match(struct tep_event *event, } static enum tep_errno -find_event(struct tep_handle *pevent, struct event_list **events, +find_event(struct tep_handle *tep, struct event_list **events, char *sys_name, char *event_name) { struct tep_event *event; @@ -299,8 +299,8 @@ find_event(struct tep_handle *pevent, struct event_list **events, } } - for (i = 0; i < pevent->nr_events; i++) { - event = pevent->events[i]; + for (i = 0; i < tep->nr_events; i++) { + event = tep->events[i]; if (event_match(event, sys_name ? &sreg : NULL, &ereg)) { match = 1; if (add_event(events, event) < 0) { @@ -1257,7 +1257,7 @@ static void filter_init_error_buf(struct tep_event_filter *filter) enum tep_errno tep_filter_add_filter_str(struct tep_event_filter *filter, const char *filter_str) { - struct tep_handle *pevent = filter->pevent; + struct tep_handle *tep = filter->tep; struct event_list *event; struct event_list *events = NULL; const char *filter_start; @@ -1313,7 +1313,7 @@ enum tep_errno tep_filter_add_filter_str(struct tep_event_filter *filter, } /* Find this event */ - ret = find_event(pevent, &events, strim(sys_name), strim(event_name)); + ret = find_event(tep, &events, strim(sys_name), strim(event_name)); if (ret < 0) { free_events(events); free(this_event); @@ -1334,7 +1334,7 @@ enum tep_errno tep_filter_add_filter_str(struct tep_event_filter *filter, if (ret < 0) rtn = ret; - if (ret >= 0 && pevent->test_filters) { + if (ret >= 0 && tep->test_filters) { char *test; test = tep_filter_make_string(filter, event->event->id); if (test) { @@ -1346,9 +1346,6 @@ enum tep_errno tep_filter_add_filter_str(struct tep_event_filter *filter, free_events(events); - if (rtn >= 0 && pevent->test_filters) - exit(0); - return rtn; } @@ -1380,7 +1377,7 @@ int tep_filter_strerror(struct tep_event_filter *filter, enum tep_errno err, return 0; } - return tep_strerror(filter->pevent, err, buf, buflen); + return tep_strerror(filter->tep, err, buf, buflen); } /** @@ -1443,7 +1440,7 @@ void tep_filter_reset(struct tep_event_filter *filter) void tep_filter_free(struct tep_event_filter *filter) { - tep_unref(filter->pevent); + tep_unref(filter->tep); tep_filter_reset(filter); @@ -1462,10 +1459,10 @@ static int copy_filter_type(struct tep_event_filter *filter, const char *name; char *str; - /* Can't assume that the pevent's are the same */ + /* Can't assume that the tep's are the same */ sys = filter_type->event->system; name = filter_type->event->name; - event = tep_find_event_by_name(filter->pevent, sys, name); + event = tep_find_event_by_name(filter->tep, sys, name); if (!event) return -1; @@ -1522,167 +1519,6 @@ int tep_filter_copy(struct tep_event_filter *dest, struct tep_event_filter *sour return ret; } - -/** - * tep_update_trivial - update the trivial filters with the given filter - * @dest - the filter to update - * @source - the filter as the source of the update - * @type - the type of trivial filter to update. - * - * Scan dest for trivial events matching @type to replace with the source. - * - * Returns 0 on success and -1 if there was a problem updating, but - * events may have still been updated on error. - */ -int tep_update_trivial(struct tep_event_filter *dest, struct tep_event_filter *source, - enum tep_filter_trivial_type type) -{ - struct tep_handle *src_pevent; - struct tep_handle *dest_pevent; - struct tep_event *event; - struct tep_filter_type *filter_type; - struct tep_filter_arg *arg; - char *str; - int i; - - src_pevent = source->pevent; - dest_pevent = dest->pevent; - - /* Do nothing if either of the filters has nothing to filter */ - if (!dest->filters || !source->filters) - return 0; - - for (i = 0; i < dest->filters; i++) { - filter_type = &dest->event_filters[i]; - arg = filter_type->filter; - if (arg->type != TEP_FILTER_ARG_BOOLEAN) - continue; - if ((arg->boolean.value && type == TEP_FILTER_TRIVIAL_FALSE) || - (!arg->boolean.value && type == TEP_FILTER_TRIVIAL_TRUE)) - continue; - - event = filter_type->event; - - if (src_pevent != dest_pevent) { - /* do a look up */ - event = tep_find_event_by_name(src_pevent, - event->system, - event->name); - if (!event) - return -1; - } - - str = tep_filter_make_string(source, event->id); - if (!str) - continue; - - /* Don't bother if the filter is trivial too */ - if (strcmp(str, "TRUE") != 0 && strcmp(str, "FALSE") != 0) - filter_event(dest, event, str, NULL); - free(str); - } - return 0; -} - -/** - * tep_filter_clear_trivial - clear TRUE and FALSE filters - * @filter: the filter to remove trivial filters from - * @type: remove only true, false, or both - * - * Removes filters that only contain a TRUE or FALES boolean arg. - * - * Returns 0 on success and -1 if there was a problem. - */ -int tep_filter_clear_trivial(struct tep_event_filter *filter, - enum tep_filter_trivial_type type) -{ - struct tep_filter_type *filter_type; - int count = 0; - int *ids = NULL; - int i; - - if (!filter->filters) - return 0; - - /* - * Two steps, first get all ids with trivial filters. - * then remove those ids. - */ - for (i = 0; i < filter->filters; i++) { - int *new_ids; - - filter_type = &filter->event_filters[i]; - if (filter_type->filter->type != TEP_FILTER_ARG_BOOLEAN) - continue; - switch (type) { - case TEP_FILTER_TRIVIAL_FALSE: - if (filter_type->filter->boolean.value) - continue; - break; - case TEP_FILTER_TRIVIAL_TRUE: - if (!filter_type->filter->boolean.value) - continue; - default: - break; - } - - new_ids = realloc(ids, sizeof(*ids) * (count + 1)); - if (!new_ids) { - free(ids); - return -1; - } - - ids = new_ids; - ids[count++] = filter_type->event_id; - } - - if (!count) - return 0; - - for (i = 0; i < count; i++) - tep_filter_remove_event(filter, ids[i]); - - free(ids); - return 0; -} - -/** - * tep_filter_event_has_trivial - return true event contains trivial filter - * @filter: the filter with the information - * @event_id: the id of the event to test - * @type: trivial type to test for (TRUE, FALSE, EITHER) - * - * Returns 1 if the event contains a matching trivial type - * otherwise 0. - */ -int tep_filter_event_has_trivial(struct tep_event_filter *filter, - int event_id, - enum tep_filter_trivial_type type) -{ - struct tep_filter_type *filter_type; - - if (!filter->filters) - return 0; - - filter_type = find_filter_type(filter, event_id); - - if (!filter_type) - return 0; - - if (filter_type->filter->type != TEP_FILTER_ARG_BOOLEAN) - return 0; - - switch (type) { - case TEP_FILTER_TRIVIAL_FALSE: - return !filter_type->filter->boolean.value; - - case TEP_FILTER_TRIVIAL_TRUE: - return filter_type->filter->boolean.value; - default: - return 1; - } -} - static int test_filter(struct tep_event *event, struct tep_filter_arg *arg, struct tep_record *record, enum tep_errno *err); @@ -1692,8 +1528,8 @@ get_comm(struct tep_event *event, struct tep_record *record) const char *comm; int pid; - pid = tep_data_pid(event->pevent, record); - comm = tep_data_comm_from_pid(event->pevent, pid); + pid = tep_data_pid(event->tep, record); + comm = tep_data_comm_from_pid(event->tep, pid); return comm; } @@ -1861,7 +1697,7 @@ static int test_num(struct tep_event *event, struct tep_filter_arg *arg, static const char *get_field_str(struct tep_filter_arg *arg, struct tep_record *record) { struct tep_event *event; - struct tep_handle *pevent; + struct tep_handle *tep; unsigned long long addr; const char *val = NULL; unsigned int size; @@ -1891,12 +1727,12 @@ static const char *get_field_str(struct tep_filter_arg *arg, struct tep_record * } else { event = arg->str.field->event; - pevent = event->pevent; + tep = event->tep; addr = get_value(event, arg->str.field, record); if (arg->str.field->flags & (TEP_FIELD_IS_POINTER | TEP_FIELD_IS_LONG)) /* convert to a kernel symbol */ - val = tep_find_function(pevent, addr); + val = tep_find_function(tep, addr); if (val == NULL) { /* just use the hex of the string name */ @@ -2036,7 +1872,7 @@ int tep_event_filtered(struct tep_event_filter *filter, int event_id) enum tep_errno tep_filter_match(struct tep_event_filter *filter, struct tep_record *record) { - struct tep_handle *pevent = filter->pevent; + struct tep_handle *tep = filter->tep; struct tep_filter_type *filter_type; int event_id; int ret; @@ -2047,7 +1883,7 @@ enum tep_errno tep_filter_match(struct tep_event_filter *filter, if (!filter->filters) return TEP_ERRNO__NO_FILTER; - event_id = tep_data_type(pevent, record); + event_id = tep_data_type(tep, record); filter_type = find_filter_type(filter, event_id); if (!filter_type) @@ -2409,14 +2245,6 @@ int tep_filter_compare(struct tep_event_filter *filter1, struct tep_event_filter break; if (filter_type1->filter->type != filter_type2->filter->type) break; - switch (filter_type1->filter->type) { - case TEP_FILTER_TRIVIAL_FALSE: - case TEP_FILTER_TRIVIAL_TRUE: - /* trivial types just need the type compared */ - continue; - default: - break; - } /* The best way to compare complex filters is with strings */ str1 = arg_to_str(filter1, filter_type1->filter); str2 = arg_to_str(filter2, filter_type2->filter); diff --git a/tools/lib/traceevent/plugin_cfg80211.c b/tools/lib/traceevent/plugin_cfg80211.c index a51b366f47da..3d43b56a6c98 100644 --- a/tools/lib/traceevent/plugin_cfg80211.c +++ b/tools/lib/traceevent/plugin_cfg80211.c @@ -25,9 +25,9 @@ process___le16_to_cpup(struct trace_seq *s, unsigned long long *args) return val ? (long long) le16toh(*val) : 0; } -int TEP_PLUGIN_LOADER(struct tep_handle *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *tep) { - tep_register_print_function(pevent, + tep_register_print_function(tep, process___le16_to_cpup, TEP_FUNC_ARG_INT, "__le16_to_cpup", @@ -36,8 +36,8 @@ int TEP_PLUGIN_LOADER(struct tep_handle *pevent) return 0; } -void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *tep) { - tep_unregister_print_function(pevent, process___le16_to_cpup, + tep_unregister_print_function(tep, process___le16_to_cpup, "__le16_to_cpup"); } diff --git a/tools/lib/traceevent/plugin_function.c b/tools/lib/traceevent/plugin_function.c index a73eca34a8f9..7770fcb78e0f 100644 --- a/tools/lib/traceevent/plugin_function.c +++ b/tools/lib/traceevent/plugin_function.c @@ -126,7 +126,7 @@ static int add_and_get_index(const char *parent, const char *child, int cpu) static int function_handler(struct trace_seq *s, struct tep_record *record, struct tep_event *event, void *context) { - struct tep_handle *pevent = event->pevent; + struct tep_handle *tep = event->tep; unsigned long long function; unsigned long long pfunction; const char *func; @@ -136,12 +136,12 @@ static int function_handler(struct trace_seq *s, struct tep_record *record, if (tep_get_field_val(s, event, "ip", record, &function, 1)) return trace_seq_putc(s, '!'); - func = tep_find_function(pevent, function); + 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(pevent, pfunction); + parent = tep_find_function(tep, pfunction); if (parent && ftrace_indent->set) index = add_and_get_index(parent, func, record->cpu); @@ -164,9 +164,9 @@ static int function_handler(struct trace_seq *s, struct tep_record *record, return 0; } -int TEP_PLUGIN_LOADER(struct tep_handle *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *tep) { - tep_register_event_handler(pevent, -1, "ftrace", "function", + tep_register_event_handler(tep, -1, "ftrace", "function", function_handler, NULL); tep_plugin_add_options("ftrace", plugin_options); @@ -174,11 +174,11 @@ int TEP_PLUGIN_LOADER(struct tep_handle *pevent) return 0; } -void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *tep) { int i, x; - tep_unregister_event_handler(pevent, -1, "ftrace", "function", + tep_unregister_event_handler(tep, -1, "ftrace", "function", function_handler, NULL); for (i = 0; i <= cpus; i++) { diff --git a/tools/lib/traceevent/plugin_hrtimer.c b/tools/lib/traceevent/plugin_hrtimer.c index 5db5e401275f..bb434e0ed03a 100644 --- a/tools/lib/traceevent/plugin_hrtimer.c +++ b/tools/lib/traceevent/plugin_hrtimer.c @@ -67,23 +67,23 @@ static int timer_start_handler(struct trace_seq *s, return 0; } -int TEP_PLUGIN_LOADER(struct tep_handle *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *tep) { - tep_register_event_handler(pevent, -1, + tep_register_event_handler(tep, -1, "timer", "hrtimer_expire_entry", timer_expire_handler, NULL); - tep_register_event_handler(pevent, -1, "timer", "hrtimer_start", + tep_register_event_handler(tep, -1, "timer", "hrtimer_start", timer_start_handler, NULL); return 0; } -void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *tep) { - tep_unregister_event_handler(pevent, -1, + tep_unregister_event_handler(tep, -1, "timer", "hrtimer_expire_entry", timer_expire_handler, NULL); - tep_unregister_event_handler(pevent, -1, "timer", "hrtimer_start", + tep_unregister_event_handler(tep, -1, "timer", "hrtimer_start", timer_start_handler, NULL); } diff --git a/tools/lib/traceevent/plugin_jbd2.c b/tools/lib/traceevent/plugin_jbd2.c index a5e34135dd6a..04fc125f38cb 100644 --- a/tools/lib/traceevent/plugin_jbd2.c +++ b/tools/lib/traceevent/plugin_jbd2.c @@ -48,16 +48,16 @@ process_jiffies_to_msecs(struct trace_seq *s, unsigned long long *args) return jiffies; } -int TEP_PLUGIN_LOADER(struct tep_handle *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *tep) { - tep_register_print_function(pevent, + 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(pevent, + tep_register_print_function(tep, process_jiffies_to_msecs, TEP_FUNC_ARG_LONG, "jiffies_to_msecs", @@ -66,11 +66,11 @@ int TEP_PLUGIN_LOADER(struct tep_handle *pevent) return 0; } -void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *tep) { - tep_unregister_print_function(pevent, process_jbd2_dev_to_name, + tep_unregister_print_function(tep, process_jbd2_dev_to_name, "jbd2_dev_to_name"); - tep_unregister_print_function(pevent, process_jiffies_to_msecs, + tep_unregister_print_function(tep, process_jiffies_to_msecs, "jiffies_to_msecs"); } diff --git a/tools/lib/traceevent/plugin_kmem.c b/tools/lib/traceevent/plugin_kmem.c index 0e3c601f9ed1..edaec5d962c3 100644 --- a/tools/lib/traceevent/plugin_kmem.c +++ b/tools/lib/traceevent/plugin_kmem.c @@ -39,57 +39,57 @@ static int call_site_handler(struct trace_seq *s, struct tep_record *record, if (tep_read_number_field(field, data, &val)) return 1; - func = tep_find_function(event->pevent, val); + func = tep_find_function(event->tep, val); if (!func) return 1; - addr = tep_find_function_address(event->pevent, val); + 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 *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *tep) { - tep_register_event_handler(pevent, -1, "kmem", "kfree", + tep_register_event_handler(tep, -1, "kmem", "kfree", call_site_handler, NULL); - tep_register_event_handler(pevent, -1, "kmem", "kmalloc", + tep_register_event_handler(tep, -1, "kmem", "kmalloc", call_site_handler, NULL); - tep_register_event_handler(pevent, -1, "kmem", "kmalloc_node", + tep_register_event_handler(tep, -1, "kmem", "kmalloc_node", call_site_handler, NULL); - tep_register_event_handler(pevent, -1, "kmem", "kmem_cache_alloc", + tep_register_event_handler(tep, -1, "kmem", "kmem_cache_alloc", call_site_handler, NULL); - tep_register_event_handler(pevent, -1, "kmem", + tep_register_event_handler(tep, -1, "kmem", "kmem_cache_alloc_node", call_site_handler, NULL); - tep_register_event_handler(pevent, -1, "kmem", "kmem_cache_free", + tep_register_event_handler(tep, -1, "kmem", "kmem_cache_free", call_site_handler, NULL); return 0; } -void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *tep) { - tep_unregister_event_handler(pevent, -1, "kmem", "kfree", + tep_unregister_event_handler(tep, -1, "kmem", "kfree", call_site_handler, NULL); - tep_unregister_event_handler(pevent, -1, "kmem", "kmalloc", + tep_unregister_event_handler(tep, -1, "kmem", "kmalloc", call_site_handler, NULL); - tep_unregister_event_handler(pevent, -1, "kmem", "kmalloc_node", + tep_unregister_event_handler(tep, -1, "kmem", "kmalloc_node", call_site_handler, NULL); - tep_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_alloc", + tep_unregister_event_handler(tep, -1, "kmem", "kmem_cache_alloc", call_site_handler, NULL); - tep_unregister_event_handler(pevent, -1, "kmem", + tep_unregister_event_handler(tep, -1, "kmem", "kmem_cache_alloc_node", call_site_handler, NULL); - tep_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_free", + tep_unregister_event_handler(tep, -1, "kmem", "kmem_cache_free", call_site_handler, NULL); } diff --git a/tools/lib/traceevent/plugin_kvm.c b/tools/lib/traceevent/plugin_kvm.c index 64b9c25a1fd3..c8e623065a7e 100644 --- a/tools/lib/traceevent/plugin_kvm.c +++ b/tools/lib/traceevent/plugin_kvm.c @@ -389,8 +389,8 @@ static int kvm_mmu_print_role(struct trace_seq *s, struct tep_record *record, * We can only use the structure if file is of the same * endianness. */ - if (tep_file_bigendian(event->pevent) == - tep_is_host_bigendian(event->pevent)) { + 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, @@ -445,40 +445,40 @@ process_is_writable_pte(struct trace_seq *s, unsigned long long *args) return pte & PT_WRITABLE_MASK; } -int TEP_PLUGIN_LOADER(struct tep_handle *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *tep) { init_disassembler(); - tep_register_event_handler(pevent, -1, "kvm", "kvm_exit", + tep_register_event_handler(tep, -1, "kvm", "kvm_exit", kvm_exit_handler, NULL); - tep_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", + tep_register_event_handler(tep, -1, "kvm", "kvm_emulate_insn", kvm_emulate_insn_handler, NULL); - tep_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit", + tep_register_event_handler(tep, -1, "kvm", "kvm_nested_vmexit", kvm_nested_vmexit_handler, NULL); - tep_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject", + tep_register_event_handler(tep, -1, "kvm", "kvm_nested_vmexit_inject", kvm_nested_vmexit_inject_handler, NULL); - tep_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", + tep_register_event_handler(tep, -1, "kvmmmu", "kvm_mmu_get_page", kvm_mmu_get_page_handler, NULL); - tep_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page", + tep_register_event_handler(tep, -1, "kvmmmu", "kvm_mmu_sync_page", kvm_mmu_print_role, NULL); - tep_register_event_handler(pevent, -1, + tep_register_event_handler(tep, -1, "kvmmmu", "kvm_mmu_unsync_page", kvm_mmu_print_role, NULL); - tep_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page", + tep_register_event_handler(tep, -1, "kvmmmu", "kvm_mmu_zap_page", kvm_mmu_print_role, NULL); - tep_register_event_handler(pevent, -1, "kvmmmu", + tep_register_event_handler(tep, -1, "kvmmmu", "kvm_mmu_prepare_zap_page", kvm_mmu_print_role, NULL); - tep_register_print_function(pevent, + tep_register_print_function(tep, process_is_writable_pte, TEP_FUNC_ARG_INT, "is_writable_pte", @@ -487,37 +487,37 @@ int TEP_PLUGIN_LOADER(struct tep_handle *pevent) return 0; } -void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *tep) { - tep_unregister_event_handler(pevent, -1, "kvm", "kvm_exit", + tep_unregister_event_handler(tep, -1, "kvm", "kvm_exit", kvm_exit_handler, NULL); - tep_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", + tep_unregister_event_handler(tep, -1, "kvm", "kvm_emulate_insn", kvm_emulate_insn_handler, NULL); - tep_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit", + tep_unregister_event_handler(tep, -1, "kvm", "kvm_nested_vmexit", kvm_nested_vmexit_handler, NULL); - tep_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject", + tep_unregister_event_handler(tep, -1, "kvm", "kvm_nested_vmexit_inject", kvm_nested_vmexit_inject_handler, NULL); - tep_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", + tep_unregister_event_handler(tep, -1, "kvmmmu", "kvm_mmu_get_page", kvm_mmu_get_page_handler, NULL); - tep_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page", + tep_unregister_event_handler(tep, -1, "kvmmmu", "kvm_mmu_sync_page", kvm_mmu_print_role, NULL); - tep_unregister_event_handler(pevent, -1, + tep_unregister_event_handler(tep, -1, "kvmmmu", "kvm_mmu_unsync_page", kvm_mmu_print_role, NULL); - tep_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page", + tep_unregister_event_handler(tep, -1, "kvmmmu", "kvm_mmu_zap_page", kvm_mmu_print_role, NULL); - tep_unregister_event_handler(pevent, -1, "kvmmmu", + tep_unregister_event_handler(tep, -1, "kvmmmu", "kvm_mmu_prepare_zap_page", kvm_mmu_print_role, NULL); - tep_unregister_print_function(pevent, process_is_writable_pte, + tep_unregister_print_function(tep, process_is_writable_pte, "is_writable_pte"); } diff --git a/tools/lib/traceevent/plugin_mac80211.c b/tools/lib/traceevent/plugin_mac80211.c index e38b9477aad2..884303c26b5c 100644 --- a/tools/lib/traceevent/plugin_mac80211.c +++ b/tools/lib/traceevent/plugin_mac80211.c @@ -87,17 +87,17 @@ static int drv_bss_info_changed(struct trace_seq *s, return 0; } -int TEP_PLUGIN_LOADER(struct tep_handle *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *tep) { - tep_register_event_handler(pevent, -1, "mac80211", + 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 *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *tep) { - tep_unregister_event_handler(pevent, -1, "mac80211", + tep_unregister_event_handler(tep, -1, "mac80211", "drv_bss_info_changed", drv_bss_info_changed, NULL); } diff --git a/tools/lib/traceevent/plugin_sched_switch.c b/tools/lib/traceevent/plugin_sched_switch.c index 834c9e378ff8..957389a0ff7a 100644 --- a/tools/lib/traceevent/plugin_sched_switch.c +++ b/tools/lib/traceevent/plugin_sched_switch.c @@ -62,7 +62,7 @@ static void write_and_save_comm(struct tep_format_field *field, comm = &s->buffer[len]; /* Help out the comm to ids. This will handle dups */ - tep_register_comm(field->event->pevent, comm, pid); + tep_register_comm(field->event->tep, comm, pid); } static int sched_wakeup_handler(struct trace_seq *s, @@ -135,27 +135,27 @@ static int sched_switch_handler(struct trace_seq *s, return 0; } -int TEP_PLUGIN_LOADER(struct tep_handle *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *tep) { - tep_register_event_handler(pevent, -1, "sched", "sched_switch", + tep_register_event_handler(tep, -1, "sched", "sched_switch", sched_switch_handler, NULL); - tep_register_event_handler(pevent, -1, "sched", "sched_wakeup", + tep_register_event_handler(tep, -1, "sched", "sched_wakeup", sched_wakeup_handler, NULL); - tep_register_event_handler(pevent, -1, "sched", "sched_wakeup_new", + tep_register_event_handler(tep, -1, "sched", "sched_wakeup_new", sched_wakeup_handler, NULL); return 0; } -void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *tep) { - tep_unregister_event_handler(pevent, -1, "sched", "sched_switch", + tep_unregister_event_handler(tep, -1, "sched", "sched_switch", sched_switch_handler, NULL); - tep_unregister_event_handler(pevent, -1, "sched", "sched_wakeup", + tep_unregister_event_handler(tep, -1, "sched", "sched_wakeup", sched_wakeup_handler, NULL); - tep_unregister_event_handler(pevent, -1, "sched", "sched_wakeup_new", + tep_unregister_event_handler(tep, -1, "sched", "sched_wakeup_new", sched_wakeup_handler, NULL); } diff --git a/tools/lib/traceevent/plugin_scsi.c b/tools/lib/traceevent/plugin_scsi.c index 4eba25cc1431..5d0387a4b65a 100644 --- a/tools/lib/traceevent/plugin_scsi.c +++ b/tools/lib/traceevent/plugin_scsi.c @@ -414,9 +414,9 @@ unsigned long long process_scsi_trace_parse_cdb(struct trace_seq *s, return 0; } -int TEP_PLUGIN_LOADER(struct tep_handle *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *tep) { - tep_register_print_function(pevent, + tep_register_print_function(tep, process_scsi_trace_parse_cdb, TEP_FUNC_ARG_STRING, "scsi_trace_parse_cdb", @@ -427,8 +427,8 @@ int TEP_PLUGIN_LOADER(struct tep_handle *pevent) return 0; } -void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *tep) { - tep_unregister_print_function(pevent, process_scsi_trace_parse_cdb, + tep_unregister_print_function(tep, process_scsi_trace_parse_cdb, "scsi_trace_parse_cdb"); } diff --git a/tools/lib/traceevent/plugin_xen.c b/tools/lib/traceevent/plugin_xen.c index bc0496e4c296..993b208d0323 100644 --- a/tools/lib/traceevent/plugin_xen.c +++ b/tools/lib/traceevent/plugin_xen.c @@ -120,9 +120,9 @@ unsigned long long process_xen_hypercall_name(struct trace_seq *s, return 0; } -int TEP_PLUGIN_LOADER(struct tep_handle *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *tep) { - tep_register_print_function(pevent, + tep_register_print_function(tep, process_xen_hypercall_name, TEP_FUNC_ARG_STRING, "xen_hypercall_name", @@ -131,8 +131,8 @@ int TEP_PLUGIN_LOADER(struct tep_handle *pevent) return 0; } -void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *tep) { - tep_unregister_print_function(pevent, process_xen_hypercall_name, + tep_unregister_print_function(tep, process_xen_hypercall_name, "xen_hypercall_name"); } |