From patchwork Fri Nov 5 12:16:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 12604555 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C6041C433EF for ; Fri, 5 Nov 2021 12:16:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AC3A461262 for ; Fri, 5 Nov 2021 12:16:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230179AbhKEMTJ (ORCPT ); Fri, 5 Nov 2021 08:19:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53494 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229500AbhKEMTI (ORCPT ); Fri, 5 Nov 2021 08:19:08 -0400 Received: from mail-wm1-x332.google.com (mail-wm1-x332.google.com [IPv6:2a00:1450:4864:20::332]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EE47CC061714 for ; Fri, 5 Nov 2021 05:16:28 -0700 (PDT) Received: by mail-wm1-x332.google.com with SMTP id j128-20020a1c2386000000b003301a98dd62so9393859wmj.5 for ; Fri, 05 Nov 2021 05:16:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=22aTLEdbmNssmXsXLUPGha8YaQ9f4/Hl2qNvKdwGtzc=; b=UCMAIe51AB2eyr/vQNeSqdm+zl1gb8jz2NvtivAT+VbTfz+8bCjNFtF9rTUCT5FTUC u/w3snDFM3vUctr09hH33vSO+fhBhZFRJIWSmhhShQ0bLhcJqwNWRKR0t3Klo1hUpA75 OJ35UiFvTPcrAEtMyHK8MBUlL1+hZUTqP2LSfAt2MOfU3vgno8UQX6mzhAs6V65lB7DU bI0bN9Q6iOo/8b0IcZwNv0DmYgdmKFX8Iv9kDPwqW92gHNJNGt2IClUIFdhrGeiDIDJH lbLGVwDX2cQ9xQBFF3senQFcDg8HSCde0MVxLvYusXQdp2fCPJP7ZEyjNRB8MR9Ol1fm tbjQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=22aTLEdbmNssmXsXLUPGha8YaQ9f4/Hl2qNvKdwGtzc=; b=lEPUEZSFjpTYUTQpplIyrJjmBY3bftghV23+R8owl5XcwnKro6vSc+vQy92f6OKQ7z e+/PxMkHDRTgmUgyGCuCKrKhbiMCULyzHGGCy5eyxYkdCsh+Oa9gGNpm+go6E6Ns4BuF WGzlvOPS4A3+AJwFiMrRCMWv7zqBQTfoW5IYIVymUIHTjyt2WVD+rOOF8McFjd5oEGA4 7UtpE1TmbfBJFCwbWwaN6zJLK1k2+CZ2paxe/tW+cA2OmTTGwFzOCbGiNxzfcczc0l8W HedXPqRIkwCv/kJjcYj7tLGm3ywrr86LwBtJVbmS6EzwOCVf0giwSYNMHNIt3a8B8u9N mR6w== X-Gm-Message-State: AOAM533z3CPCXcxl+k8G1usecUa2X+Ec2T1YbS5jcNeHStrVMIThZNhf KQVgy+8V3fG+QJxDtx/aB0k= X-Google-Smtp-Source: ABdhPJywIq9/VizicmApON0XMIuFQgfVBB+CCjeYV8rc1jg01lP7WQJnGTmHJ4DrQqbRhfvcsO2/Jg== X-Received: by 2002:a05:600c:1d28:: with SMTP id l40mr2275145wms.192.1636114587360; Fri, 05 Nov 2021 05:16:27 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id x13sm7936531wrr.47.2021.11.05.05.16.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 Nov 2021 05:16:26 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v5 01/12] libtracefs: New APIs for dynamic events Date: Fri, 5 Nov 2021 14:16:13 +0200 Message-Id: <20211105121624.398717-2-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211105121624.398717-1-tz.stoyanov@gmail.com> References: <20211105121624.398717-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org Ftrace supports dynamic events, created by the user - kprobes, uprobes, eprobes and synthetic events. There are two interfaces for managing these events - new common "dynamic_events" file and event specific "kprobe_events", "uprobe_events", "synthetic_events" files. The configuration syntax for all dynamic events is almost the same. To simplify support of dynamic events in the tracefs library, new APIs are introduced. They handle both configuration interfaces - the common "dynamic_events" file is preferred, if available. On the old kernels, where this file is missing, the event specific files are used. The new APIs can be used to create, delete and get ftrace dynamic events from any type: enum tracefs_dynevent_type; tracefs_dynevent_create(); tracefs_dynevent_destroy(); tracefs_dynevent_destroy_all(); tracefs_dynevent_free(); tracefs_dynevent_list_free(); tracefs_dynevent_get_all(); There is no public API for allocation of a new dynamic event, as that logic is specific for each dynamic event type. Signed-off-by: Tzvetomir Stoyanov (VMware) --- include/tracefs-local.h | 18 + include/tracefs.h | 23 ++ src/Makefile | 1 + src/tracefs-dynevents.c | 718 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 760 insertions(+) create mode 100644 src/tracefs-dynevents.c diff --git a/include/tracefs-local.h b/include/tracefs-local.h index 684eccf..a59e806 100644 --- a/include/tracefs-local.h +++ b/include/tracefs-local.h @@ -94,4 +94,22 @@ int synth_add_start_field(struct tracefs_synth *synth, const char *start_field, const char *name, enum tracefs_hist_key_type type); + +/* Internal interface for ftrace dynamic events */ + +struct tracefs_dynevent { + char *trace_file; + char *prefix; + char *system; + char *event; + char *address; + char *format; + enum tracefs_dynevent_type type; +}; + +struct tracefs_dynevent * +dynevent_alloc(enum tracefs_dynevent_type type, const char *system, + const char *event, const char *address, const char *format); +int dynevent_get_count(unsigned int types, const char *system); + #endif /* _TRACE_FS_LOCAL_H */ diff --git a/include/tracefs.h b/include/tracefs.h index a2cda30..eceb1f5 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -238,6 +238,29 @@ ssize_t tracefs_trace_pipe_stream(int fd, struct tracefs_instance *instance, int ssize_t tracefs_trace_pipe_print(struct tracefs_instance *instance, int flags); void tracefs_trace_pipe_stop(struct tracefs_instance *instance); +/* Dynamic events */ +struct tracefs_dynevent; +enum tracefs_dynevent_type { + TRACEFS_DYNEVENT_UNKNOWN = 0, + TRACEFS_DYNEVENT_KPROBE = 1 << 0, + TRACEFS_DYNEVENT_KRETPROBE = 1 << 1, + TRACEFS_DYNEVENT_UPROBE = 1 << 2, + TRACEFS_DYNEVENT_URETPROBE = 1 << 3, + TRACEFS_DYNEVENT_EPROBE = 1 << 4, + TRACEFS_DYNEVENT_SYNTH = 1 << 5, + TRACEFS_DYNEVENT_MAX = 1 << 6, +}; +int tracefs_dynevent_create(struct tracefs_dynevent *devent); +int tracefs_dynevent_destroy(struct tracefs_dynevent *devent, bool force); +int tracefs_dynevent_destroy_all(unsigned int types, bool force); +void tracefs_dynevent_free(struct tracefs_dynevent *devent); +void tracefs_dynevent_list_free(struct tracefs_dynevent **events); +struct tracefs_dynevent ** +tracefs_dynevent_get_all(unsigned int types, const char *system); +enum tracefs_dynevent_type +tracefs_dynevent_info(struct tracefs_dynevent *dynevent, char **system, + char **event, char **prefix, char **addr, char **format); + enum tracefs_kprobe_type { TRACEFS_ALL_KPROBES, TRACEFS_KPROBE, diff --git a/src/Makefile b/src/Makefile index 4e38d98..99cd7da 100644 --- a/src/Makefile +++ b/src/Makefile @@ -11,6 +11,7 @@ OBJS += tracefs-marker.o OBJS += tracefs-kprobes.o OBJS += tracefs-hist.o OBJS += tracefs-filter.o +OBJS += tracefs-dynevents.o # Order matters for the the three below OBJS += sqlhist-lex.o diff --git a/src/tracefs-dynevents.c b/src/tracefs-dynevents.c new file mode 100644 index 0000000..6d909e3 --- /dev/null +++ b/src/tracefs-dynevents.c @@ -0,0 +1,718 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * Copyright (C) 2021 VMware Inc, Steven Rostedt + * + * Updates: + * Copyright (C) 2021, VMware, Tzvetomir Stoyanov + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include "tracefs.h" +#include "tracefs-local.h" + +#define DYNEVENTS_EVENTS "dynamic_events" +#define KPROBE_EVENTS "kprobe_events" +#define UPROBE_EVENTS "uprobe_events" +#define SYNTH_EVENTS "synthetic_events" +#define DYNEVENTS_DEFAULT_GROUP "dynamic" + +static const int max_dyn_index = ffs(TRACEFS_DYNEVENT_MAX) - 1; + +struct dyn_events_desc; +static int dyn_generic_parse(struct dyn_events_desc *, + const char *, char *, struct tracefs_dynevent **); +static int dyn_synth_parse(struct dyn_events_desc *, + const char *, char *, struct tracefs_dynevent **); +static int dyn_generic_del(struct dyn_events_desc *, struct tracefs_dynevent *); +static int dyn_synth_del(struct dyn_events_desc *, struct tracefs_dynevent *); + +struct dyn_events_desc { + enum tracefs_dynevent_type type; + const char *file; + const char *prefix; + int (*del)(struct dyn_events_desc *desc, struct tracefs_dynevent *dyn); + int (*parse)(struct dyn_events_desc *desc, const char *group, + char *line, struct tracefs_dynevent **ret_dyn); +} dynevents[] = { + {TRACEFS_DYNEVENT_KPROBE, NULL, "p", dyn_generic_del, dyn_generic_parse}, + {TRACEFS_DYNEVENT_KRETPROBE, NULL, "r", dyn_generic_del, dyn_generic_parse}, + {TRACEFS_DYNEVENT_UPROBE, NULL, "p", dyn_generic_del, dyn_generic_parse}, + {TRACEFS_DYNEVENT_URETPROBE, NULL, "r", dyn_generic_del, dyn_generic_parse}, + {TRACEFS_DYNEVENT_EPROBE, NULL, "e", dyn_generic_del, dyn_generic_parse}, + {TRACEFS_DYNEVENT_SYNTH, NULL, "s", dyn_synth_del, dyn_synth_parse}, +}; + +static int dyn_generic_del(struct dyn_events_desc *desc, struct tracefs_dynevent *dyn) +{ + char *str; + int ret; + + if (dyn->system) + ret = asprintf(&str, "-:%s/%s", dyn->system, dyn->event); + else + ret = asprintf(&str, "-:%s", dyn->event); + + if (ret < 0) + return -1; + + ret = tracefs_instance_file_append(NULL, desc->file, str); + free(str); + + return ret < 0 ? ret : 0; +} + +/** + * tracefs_dynevent_free - Free a dynamic event context + * @devent: Pointer to a dynamic event context + * + * The dynamic event, described by this context, is not + * removed from the system by this API. It only frees the memory. + */ +void tracefs_dynevent_free(struct tracefs_dynevent *devent) +{ + if (!devent) + return; + free(devent->system); + free(devent->event); + free(devent->address); + free(devent->format); + free(devent->prefix); + free(devent->trace_file); + free(devent); +} + +static void parse_prefix(char *word, char **prefix, char **system, char **name) +{ + char *sav; + + *prefix = NULL; + *system = NULL; + *name = NULL; + + *prefix = strtok_r(word, ":", &sav); + *system = strtok_r(NULL, "/", &sav); + if (!(*system)) + return; + + *name = strtok_r(NULL, " \t", &sav); + if (!(*name)) { + *name = *system; + *system = NULL; + } +} + +/* + * Parse lines from dynamic_events, kprobe_events and uprobe_events files + * PREFIX[:[SYSTEM/]EVENT] [ADDRSS] [FORMAT] + */ +static int dyn_generic_parse(struct dyn_events_desc *desc, const char *group, + char *line, struct tracefs_dynevent **ret_dyn) +{ + struct tracefs_dynevent *dyn; + char *word; + char *format = NULL; + char *address; + char *system; + char *prefix; + char *event; + char *sav; + + if (strncmp(line, desc->prefix, strlen(desc->prefix))) + return -1; + + word = strtok_r(line, " \t", &sav); + if (!word || *word == '\0') + return -1; + + parse_prefix(word, &prefix, &system, &event); + if (!prefix) + return -1; + + if (desc->type != TRACEFS_DYNEVENT_SYNTH) { + address = strtok_r(NULL, " \t", &sav); + if (!address || *address == '\0') + return -1; + } + + format = strtok_r(NULL, "", &sav); + + /* KPROBEs and UPROBEs share the same prefix, check the format */ + if (desc->type & (TRACEFS_DYNEVENT_UPROBE | TRACEFS_DYNEVENT_URETPROBE)) { + if (!strchr(address, '/')) + return -1; + } + + if (group && (!system || strcmp(group, system) != 0)) + return -1; + + if (!ret_dyn) + return 0; + + dyn = calloc(1, sizeof(*dyn)); + if (!dyn) + return -1; + + dyn->type = desc->type; + dyn->trace_file = strdup(desc->file); + if (!dyn->trace_file) + goto error; + + dyn->prefix = strdup(prefix); + if (!dyn->prefix) + goto error; + + if (system) { + dyn->system = strdup(system); + if (!dyn->system) + goto error; + } + + if (event) { + dyn->event = strdup(event); + if (!dyn->event) + goto error; + } + + if (address) { + dyn->address = strdup(address); + if (!dyn->address) + goto error; + } + + if (format) { + dyn->format = strdup(format); + if (!dyn->format) + goto error; + } + + *ret_dyn = dyn; + return 0; +error: + tracefs_dynevent_free(dyn); + return -1; +} + +static int dyn_synth_del(struct dyn_events_desc *desc, struct tracefs_dynevent *dyn) +{ + char *str; + int ret; + + if (!strcmp(desc->file, DYNEVENTS_EVENTS)) + return dyn_generic_del(desc, dyn); + + ret = asprintf(&str, "!%s", dyn->event); + if (ret < 0) + return -1; + + ret = tracefs_instance_file_append(NULL, desc->file, str); + free(str); + + return ret < 0 ? ret : 0; +} + +/* + * Parse lines from synthetic_events file + * EVENT ARG [ARG] + */ +static int dyn_synth_parse(struct dyn_events_desc *desc, const char *group, + char *line, struct tracefs_dynevent **ret_dyn) +{ + struct tracefs_dynevent *dyn; + char *format; + char *event; + char *sav; + + if (!strcmp(desc->file, DYNEVENTS_EVENTS)) + return dyn_generic_parse(desc, group, line, ret_dyn); + + /* synthetic_events file has slightly different syntax */ + event = strtok_r(line, " \t", &sav); + if (!event || *event == '\0') + return -1; + + format = strtok_r(NULL, "", &sav); + if (!format || *format == '\0') + return -1; + + if (!ret_dyn) + return 0; + + dyn = calloc(1, sizeof(*dyn)); + if (!dyn) + return -1; + + dyn->type = desc->type; + dyn->trace_file = strdup(desc->file); + if (!dyn->trace_file) + goto error; + + dyn->event = strdup(event); + if (!dyn->event) + goto error; + + dyn->format = strdup(format+1); + if (!dyn->format) + goto error; + + *ret_dyn = dyn; + return 0; +error: + tracefs_dynevent_free(dyn); + return -1; +} + +static void init_devent_desc(void) +{ + int i; + + BUILD_BUG_ON(ARRAY_SIZE(dynevents) != max_dyn_index); + + /* Use ftrace dynamic_events, if available */ + if (tracefs_file_exists(NULL, DYNEVENTS_EVENTS)) { + for (i = 0; i < max_dyn_index; i++) + dynevents[i].file = DYNEVENTS_EVENTS; + return; + } + + if (tracefs_file_exists(NULL, KPROBE_EVENTS)) { + dynevents[ffs(TRACEFS_DYNEVENT_KPROBE) - 1].file = KPROBE_EVENTS; + dynevents[ffs(TRACEFS_DYNEVENT_KRETPROBE) - 1].file = KPROBE_EVENTS; + } + if (tracefs_file_exists(NULL, UPROBE_EVENTS)) { + dynevents[ffs(TRACEFS_DYNEVENT_UPROBE) - 1].file = UPROBE_EVENTS; + dynevents[ffs(TRACEFS_DYNEVENT_URETPROBE) - 1].file = UPROBE_EVENTS; + } + if (tracefs_file_exists(NULL, SYNTH_EVENTS)) { + dynevents[ffs(TRACEFS_DYNEVENT_SYNTH) - 1].file = SYNTH_EVENTS; + dynevents[ffs(TRACEFS_DYNEVENT_SYNTH) - 1].prefix = ""; + } +} + +static struct dyn_events_desc *get_devent_desc(enum tracefs_dynevent_type type) +{ + + static bool init; + + if (type >= TRACEFS_DYNEVENT_MAX) + return NULL; + + if (!init) { + init_devent_desc(); + init = true; + } + + return &dynevents[ffs(type) - 1]; +} + +/** + * dynevent_alloc - Allocate new dynamic event + * @type: Type of the dynamic event + * @system: The system name (NULL for the default dynamic) + * @event: Name of the event + * @addr: The function and offset (or address) to insert the probe + * @format: The format string to define the probe. + * + * Allocate a dynamic event context that will be in the @system group + * (or dynamic if @system is NULL). Have the name of @event and + * will be associated to @addr, if applicable for that event type + * (function name, with or without offset, or a address). And the @format will + * define the format of the kprobe. + * The dynamic event is not created in the system. + * + * Return a pointer to a dynamic event context on success, or NULL on error. + * The returned pointer must be freed with tracefs_dynevent_free() + * + * errno will be set to EINVAL if event is NULL. + */ +__hidden struct tracefs_dynevent * +dynevent_alloc(enum tracefs_dynevent_type type, const char *system, + const char *event, const char *address, const char *format) +{ + struct tracefs_dynevent *devent; + struct dyn_events_desc *desc; + + if (!event) { + errno = EINVAL; + return NULL; + } + + desc = get_devent_desc(type); + if (!desc || !desc->file) { + errno = ENOTSUP; + return NULL; + } + + devent = calloc(1, sizeof(*devent)); + if (!devent) + return NULL; + + devent->type = type; + devent->trace_file = strdup(desc->file); + if (!devent->trace_file) + goto err; + + if (!system) + system = DYNEVENTS_DEFAULT_GROUP; + devent->system = strdup(system); + if (!devent->system) + goto err; + + devent->event = strdup(event); + if (!devent->event) + goto err; + + devent->prefix = strdup(desc->prefix); + if (!devent->prefix) + goto err; + + if (address) { + devent->address = strdup(address); + if (!devent->address) + goto err; + } + if (format) { + devent->format = strdup(format); + if (!devent->format) + goto err; + } + + return devent; +err: + tracefs_dynevent_free(devent); + return NULL; +} + +/** + * tracefs_dynevent_create - Create a dynamic event in the system + * @devent: Pointer to a dynamic event context, describing the event + * + * Return 0 on success, or -1 on error. + */ +int tracefs_dynevent_create(struct tracefs_dynevent *devent) +{ + char *str; + int ret; + + if (!devent) + return -1; + + if (devent->system && devent->system[0]) + ret = asprintf(&str, "%s%s%s/%s %s %s\n", + devent->prefix, strlen(devent->prefix) ? ":" : "", + devent->system, devent->event, + devent->address ? devent->address : "", + devent->format ? devent->format : ""); + else + ret = asprintf(&str, "%s%s%s %s %s\n", + devent->prefix, strlen(devent->prefix) ? ":" : "", + devent->event, + devent->address ? devent->address : "", + devent->format ? devent->format : ""); + if (ret < 0) + return -1; + + ret = tracefs_instance_file_append(NULL, devent->trace_file, str); + free(str); + + return ret < 0 ? ret : 0; +} + +static void disable_events(const char *system, const char *event, + char **list) +{ + struct tracefs_instance *instance; + int i; + + /* + * Note, this will not fail even on error. + * That is because even if something fails, it may still + * work enough to clear the kprobes. If that's the case + * the clearing after the loop will succeed and the function + * is a success, even though other parts had failed. If + * one of the kprobe events is enabled in one of the + * instances that fail, then the clearing will fail too + * and the function will return an error. + */ + + tracefs_event_disable(NULL, system, event); + /* No need to test results */ + + if (!list) + return; + + for (i = 0; list[i]; i++) { + instance = tracefs_instance_alloc(NULL, list[i]); + /* If this fails, try the next one */ + if (!instance) + continue; + tracefs_event_disable(instance, system, event); + tracefs_instance_free(instance); + } +} + +/** + * tracefs_dynevent_destroy - Remove a dynamic event from the system + * @devent: A dynamic event context, describing the dynamic event that will be deleted. + * @force: Will attempt to disable all events before removing them. + * + * The dynamic event context is not freed by this API. It only removes the event from the system. + * If there are any enabled events, and @force is not set, then it will error with -1 and errno + * to be EBUSY. + * + * Return 0 on success, or -1 on error. + */ +int tracefs_dynevent_destroy(struct tracefs_dynevent *devent, bool force) +{ + struct dyn_events_desc *desc; + char **instance_list; + + if (!devent) + return -1; + + if (force) { + instance_list = tracefs_instances(NULL); + disable_events(devent->system, devent->event, instance_list); + tracefs_list_free(instance_list); + } + + desc = get_devent_desc(devent->type); + if (!desc) + return -1; + + return desc->del(desc, devent); +} + +static int get_all_dynevents(enum tracefs_dynevent_type type, const char *system, + struct tracefs_dynevent ***ret_all) +{ + struct dyn_events_desc *desc; + struct tracefs_dynevent *devent, **tmp, **all = NULL; + char *content; + int count = 0; + char *line; + char *next; + int ret; + + desc = get_devent_desc(type); + if (!desc) + return -1; + + content = tracefs_instance_file_read(NULL, desc->file, NULL); + if (!content) + return -1; + + line = content; + do { + next = strchr(line, '\n'); + if (next) + *next = '\0'; + ret = desc->parse(desc, system, line, ret_all ? &devent : NULL); + if (!ret) { + if (ret_all) { + tmp = realloc(all, (count + 1) * sizeof(*tmp)); + if (!tmp) + goto error; + all = tmp; + all[count] = devent; + } + count++; + } + line = next + 1; + } while (next); + + free(content); + if (ret_all) + *ret_all = all; + return count; + +error: + free(content); + free(all); + return -1; +} + +/** + * tracefs_dynevent_list_free - Deletes an array of pointers to dynamic event contexts + * @events: An array of pointers to dynamic event contexts. The last element of the array + * must be a NULL pointer. + */ +void tracefs_dynevent_list_free(struct tracefs_dynevent **events) +{ + int i; + + if (!events) + return; + + for (i = 0; events[i]; i++) + tracefs_dynevent_free(events[i]); + + free(events); +} + +/** + * tracefs_dynevent_get_all - return an array of pointers to dynamic events of given types + * @types: Dynamic event type, or bitmask of dynamic event types. If 0 is passed, all types + * are considered. + * @system: Get events from that system only. If @system is NULL, events from all systems + * are returned. + * + * Returns an array of pointers to dynamic events of given types that exist in the system. + * The array must be freed with tracefs_dynevent_list_free(). If there are no events a NULL + * pointer is returned. + */ +struct tracefs_dynevent ** +tracefs_dynevent_get_all(unsigned int types, const char *system) +{ + struct tracefs_dynevent **events, **tmp, **all_events = NULL; + int count, all = 0; + int i; + + for (i = 1; i < TRACEFS_DYNEVENT_MAX; i <<= 1) { + if (types) { + if (i > types) + break; + if (!(types & i)) + continue; + } + count = get_all_dynevents(i, system, &events); + if (count > 0) { + tmp = realloc(all_events, (all + count + 1) * sizeof(*tmp)); + if (!tmp) + goto error; + all_events = tmp; + memcpy(all_events + all, events, count * sizeof(*events)); + all += count; + /* Add a NULL pointer at the end */ + all_events[all] = NULL; + } + } + + return all_events; + +error: + if (all_events) { + for (i = 0; i < all; i++) + free(all_events[i]); + free(all_events); + } + return NULL; +} + +/** + * tracefs_dynevent_destroy_all - removes all dynamic events of given types from the system + * @types: Dynamic event type, or bitmask of dynamic event types. If 0 is passed, all types + * are considered. + * @force: Will attempt to disable all events before removing them. + * + * Will remove all dynamic events of the given types from the system. If there are any enabled + * events, and @force is not set, then the removal of these will fail. If @force is set, then + * it will attempt to disable all the events in all instances before removing them. + * + * Returns zero if all requested events are removed successfully, or -1 if some of them are not + * removed. + */ +int tracefs_dynevent_destroy_all(unsigned int types, bool force) +{ + struct tracefs_dynevent **all; + int ret = 0; + int i; + + all = tracefs_dynevent_get_all(types, NULL); + if (!all) + return 0; + + for (i = 0; all[i]; i++) { + if (tracefs_dynevent_destroy(all[i], force)) + ret = -1; + } + + tracefs_dynevent_list_free(all); + + return ret; +} + +/** + * dynevent_get_count - Count dynamic events of given types and system + * @types: Dynamic event type, or bitmask of dynamic event types. If 0 is passed, all types + * are considered. + * @system: Count events from that system only. If @system is NULL, events from all systems + * are counted. + * + * Return the count of requested dynamic events + */ +__hidden int dynevent_get_count(unsigned int types, const char *system) +{ + int count, all = 0; + int i; + + for (i = 1; i < TRACEFS_DYNEVENT_MAX; i <<= 1) { + if (types) { + if (i > types) + break; + if (!(types & i)) + continue; + } + count = get_all_dynevents(i, system, NULL); + if (count > 0) + all += count; + } + + return all; +} + +/** + * tracefs_dynevent_info - return details of a dynamic event + * @dynevent: A dynamic event context, describing given dynamic event. + * @group: return, group in which the dynamic event is configured + * @event: return, name of the dynamic event + * @prefix: return, prefix string of the dynamic event + * @addr: return, the function and offset (or address) of the dynamic event + * @format: return, the format string of the dynamic event + * + * Returns the type of the dynamic event, or TRACEFS_DYNEVENT_UNKNOWN in case of an error. + * Any of the @group, @event, @prefix, @addr and @format parameters are optional. + * If a valid pointer is passed, in case of success - a string is allocated and returned. + * These strings must be freed with free(). + */ + +enum tracefs_dynevent_type +tracefs_dynevent_info(struct tracefs_dynevent *dynevent, char **system, + char **event, char **prefix, char **addr, char **format) +{ + char **lv[] = { system, event, prefix, addr, format }; + char **rv[] = { &dynevent->system, &dynevent->event, &dynevent->prefix, + &dynevent->address, &dynevent->format }; + int i; + + if (!dynevent) + return TRACEFS_DYNEVENT_UNKNOWN; + + for (i = 0; i < ARRAY_SIZE(lv); i++) { + if (lv[i]) { + if (*rv[i]) { + *lv[i] = strdup(*rv[i]); + if (!*lv[i]) + goto error; + } else { + *lv[i] = NULL; + } + } + } + + return dynevent->type; + +error: + for (i--; i >= 0; i--) { + if (lv[i]) + free(*lv[i]); + } + + return TRACEFS_DYNEVENT_UNKNOWN; +} From patchwork Fri Nov 5 12:16:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 12604553 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 66DC2C433F5 for ; Fri, 5 Nov 2021 12:16:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4E76061262 for ; Fri, 5 Nov 2021 12:16:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230317AbhKEMTK (ORCPT ); Fri, 5 Nov 2021 08:19:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53498 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229500AbhKEMTJ (ORCPT ); Fri, 5 Nov 2021 08:19:09 -0400 Received: from mail-wr1-x42e.google.com (mail-wr1-x42e.google.com [IPv6:2a00:1450:4864:20::42e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CFC37C061714 for ; Fri, 5 Nov 2021 05:16:29 -0700 (PDT) Received: by mail-wr1-x42e.google.com with SMTP id c4so13388676wrd.9 for ; Fri, 05 Nov 2021 05:16:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=g5y4JKxCW95q80MrAIv4cs6zp/FN3hiMfsAH+/jv0vI=; b=ArL6OSdi+veAi5X5WiLWl/hzrANiYn0h9mt4QCkHdqsev6mYSh15yH0V5yeLexMxVR NnFYyyqdLc/uBUMrZom941qXCKahOq6m4ttsTd3P7q+JQYINs48IciK988A6apw3Noiz eQrdWWWHVTDHbvSJtqwGrv7DfFOa2Ca70YMZEtHp7ymyAV2/j9LN2D2dxwW06cQ+Lk2b 1Jsm8EUcwNAvhZsBrPxvmFxhcV1XsMGXOPam9rCsnt8pcfbhv4qnCFWdMVWc3nQLnTzZ qsWANlB3zPlzyTuY5UBC1pb/qLhwFv5lO4Yvmc3JqJtaBdMUuWiBYdfOSFYbgdp/MW2Y WIZw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=g5y4JKxCW95q80MrAIv4cs6zp/FN3hiMfsAH+/jv0vI=; b=RYeRLlLDQ4xzlsApvwPol6/qHvyA1+JA2WUkgJdNFVT8tXjdSwKfOZFIG2zecsMUKk uriDorUmZyCRJ7xyWBdqsECh1sKXmVOuSvkQgU6ndCsE1KxkVKk0TdfnuB5pBZNgon86 lNmDaQ7lnCmN7TgW+/p6WhZfGIUO3wjKMcEWNFEppJIEiNwWSH86nWP87P4nTWcgb00K /iTyZ0FkFTSF8ndcyujYurLwUN087Zh8AqItZQPX17eo9Jvd+tW50gliro2dOdSoBNSO ygCZTdpSO7iJrKNs5eBVbHY0n4UcIMEicJpiBtwbxSwqxM0C5ZjWTcoUe5/rCMcZXMFa ZprQ== X-Gm-Message-State: AOAM53137rLGgIFuH82aSTBTq4tmLZ1o+vWuhnEvaegRsJzgTyjAsi00 XcTbpa4Vr4Q9oVkI3Bwtd0s= X-Google-Smtp-Source: ABdhPJyUMxd5eHShu+UW68joo1m1Muw1UDN+KbpomeD6mQKGFF6LIeUR57U8OsOdQSALEq9OA+7HGg== X-Received: by 2002:adf:ec90:: with SMTP id z16mr47021171wrn.247.1636114588474; Fri, 05 Nov 2021 05:16:28 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id x13sm7936531wrr.47.2021.11.05.05.16.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 Nov 2021 05:16:27 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v5 02/12] libtracefs: New APIs for kprobe allocation Date: Fri, 5 Nov 2021 14:16:14 +0200 Message-Id: <20211105121624.398717-3-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211105121624.398717-1-tz.stoyanov@gmail.com> References: <20211105121624.398717-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org In order to be consistent with the other APIs, new APIs for kprobe allocation are introduced: tracefs_kprobe_alloc(); tracefs_kretprobe_alloc(); These APIs allocate new kpobe dynamic event, that can be used with tracefs_dynevent_... set of APIs. Signed-off-by: Tzvetomir Stoyanov (VMware) --- include/tracefs.h | 5 ++ src/tracefs-kprobes.c | 109 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/include/tracefs.h b/include/tracefs.h index eceb1f5..dfd9b51 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -267,6 +267,11 @@ enum tracefs_kprobe_type { TRACEFS_KRETPROBE, }; +struct tracefs_dynevent * +tracefs_kprobe_alloc(const char *system, const char *event, const char *addr, const char *format); +struct tracefs_dynevent * +tracefs_kretprobe_alloc(const char *system, const char *event, + const char *addr, const char *format, unsigned int max); int tracefs_kprobe_raw(const char *system, const char *event, const char *addr, const char *format); int tracefs_kretprobe_raw(const char *system, const char *event, diff --git a/src/tracefs-kprobes.c b/src/tracefs-kprobes.c index 6fdd8f9..b9aeb9d 100644 --- a/src/tracefs-kprobes.c +++ b/src/tracefs-kprobes.c @@ -20,6 +20,115 @@ #define KPROBE_EVENTS "kprobe_events" #define KPROBE_DEFAULT_GROUP "kprobes" +static struct tracefs_dynevent * +kprobe_alloc(enum tracefs_dynevent_type type, const char *system, const char *event, + const char *addr, const char *format) +{ + struct tracefs_dynevent *kp; + const char *sys = system; + const char *ename = event; + char *tmp; + + if (!addr) { + errno = EBADMSG; + return NULL; + } + if (!sys) + sys = KPROBE_DEFAULT_GROUP; + + if (!event) { + ename = strdup(addr); + if (!ename) + return NULL; + tmp = strchr(ename, ':'); + if (tmp) + *tmp = '\0'; + } + + kp = dynevent_alloc(type, sys, ename, addr, format); + if (!event) + free((char *)ename); + + return kp; +} + +/** + * tracefs_kprobe_alloc - Allocate new kprobe + * @system: The system name (NULL for the default kprobes) + * @event: The event to create (NULL to use @addr for the event) + * @addr: The function and offset (or address) to insert the probe + * @format: The format string to define the probe. + * + * Allocate a kprobe context that will be in the @system group (or kprobes if + * @system is NULL). Have the name of @event (or @addr if @event is NULL). Will + * be inserted to @addr (function name, with or without offset, or a address). + * And the @format will define the format of the kprobe. + * + * See the Linux documentation file under: + * Documentation/trace/kprobetrace.rst + * + * The kprobe is not created in the system. + * + * Return a pointer to a kprobe context on success, or NULL on error. + * The returned pointer must be freed with tracefs_dynevent_free() + * + * errno will be set to EBADMSG if addr is NULL. + */ +struct tracefs_dynevent * +tracefs_kprobe_alloc(const char *system, const char *event, const char *addr, const char *format) + +{ + return kprobe_alloc(TRACEFS_DYNEVENT_KPROBE, system, event, addr, format); +} + +/** + * tracefs_kretprobe_alloc - Allocate new kretprobe + * @system: The system name (NULL for the default kprobes) + * @event: The event to create (NULL to use @addr for the event) + * @addr: The function and offset (or address) to insert the retprobe + * @format: The format string to define the retprobe. + * @max: Maximum number of instances of the specified function that + * can be probed simultaneously, or 0 for the default value. + * + * Allocate a kretprobe that will be in the @system group (or kprobes if + * @system is NULL). Have the name of @event (or @addr if @event is + * NULL). Will be inserted to @addr (function name, with or without + * offset, or a address). And the @format will define the raw format + * of the kprobe. See the Linux documentation file under: + * Documentation/trace/kprobetrace.rst + * The kretprobe is not created in the system. + * + * Return a pointer to a kprobe context on success, or NULL on error. + * The returned pointer must be freed with tracefs_dynevent_free() + * + * errno will be set to EBADMSG if addr is NULL. + */ +struct tracefs_dynevent * +tracefs_kretprobe_alloc(const char *system, const char *event, + const char *addr, const char *format, unsigned int max) +{ + struct tracefs_dynevent *kp; + int ret; + + kp = kprobe_alloc(TRACEFS_DYNEVENT_KRETPROBE, system, event, addr, format); + if (!kp) + return NULL; + + if (!max) + return kp; + + free(kp->prefix); + kp->prefix = NULL; + ret = asprintf(&kp->prefix, "r%d:", max); + if (ret < 0) + goto error; + + return kp; +error: + tracefs_dynevent_free(kp); + return NULL; +} + static int insert_kprobe(const char *type, const char *system, const char *event, const char *addr, const char *format) From patchwork Fri Nov 5 12:16:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 12604557 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 73259C4332F for ; Fri, 5 Nov 2021 12:16:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5CBB46125F for ; Fri, 5 Nov 2021 12:16:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231386AbhKEMTL (ORCPT ); Fri, 5 Nov 2021 08:19:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53506 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229500AbhKEMTK (ORCPT ); Fri, 5 Nov 2021 08:19:10 -0400 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F0F75C061714 for ; Fri, 5 Nov 2021 05:16:30 -0700 (PDT) Received: by mail-wr1-x42b.google.com with SMTP id d3so13397920wrh.8 for ; Fri, 05 Nov 2021 05:16:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=XJdkg/DlWu5oe4f4IN0Mj44ojw6UTNspDKNrK2yAX6w=; b=pqR6/ATB+x6HiJK+pbZ2kwg5AWr52h6Tm+VAr0rqcKaZYQ3sczz8MwvI1ZMI3ZofKU ijV6gQZvFC8PSgp8qrLIYvp8CMgflSv9Cajkay5j0sPF3hEZPzCsGL0IjZPUaRzc9aoE zIFmQtRaJnHirXFNoYS+TB6jrpknRGh8AauQYIzJek+RfzXlFpQQ31dBj0PiIQ7BgaSE RnxNOxxH6WxhY8dCXRbPbrAhzdpiJbZXLQyUZzMF8usxLL6pjCtmaEfX0CDafomiaWVf 5N2ELtbKRnbYYP8QsTZTHPStxldsEjITfjNmmHxeAi+m5qDIW7WCCNt0G3gs2Bhy+y6e V4qA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=XJdkg/DlWu5oe4f4IN0Mj44ojw6UTNspDKNrK2yAX6w=; b=0HKgz05Olfp8PmOPdAS5NkKMhhDCGQuW4IWZKor6FfJKLQn5CP2uQOyaQ5+F9pqNge MFOMb/TbYugEDeLkgBw8fKI8scNd2XCSjAPrO/hM+5QRLpjtQv1/wXyCFs2VGsxdY4N+ EpfHjoMJzXH7tFLdBfp0xGkBZHu3mzLWk+P0OFYDUIioSTj0ICfI6v7sWu+Q++yakrwq tH5XNFZC6dS3JZ+3uIH+GCH/2lC1xzWHufU8DyMPZsAX9moc3jM1y+khISBLP1fTH3kp W4//Kb1HLOCvXLr6QM3Ph0ZCGiG4kQHgz+zfNjODK20T9vg9dzilw6x/cT+l675kSej8 Y68A== X-Gm-Message-State: AOAM533rHQJUi5B9GH+GBi1HTs91O563sEEzwwnBehErH9aRwfW7Dp5n VBNv285dmF3GB+JPoWShpPGD+CAqJHVgaw== X-Google-Smtp-Source: ABdhPJzfy7RepKjmhy8hOA9frHFwZCSd31gHNfy/vtSGeW8u47Mr92Zh4tyT+zgT/5f2JBv20EW6xQ== X-Received: by 2002:a5d:58f9:: with SMTP id f25mr67844177wrd.206.1636114589546; Fri, 05 Nov 2021 05:16:29 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id x13sm7936531wrr.47.2021.11.05.05.16.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 Nov 2021 05:16:29 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v5 03/12] libtracefs: Remove redundant kprobes APIs Date: Fri, 5 Nov 2021 14:16:15 +0200 Message-Id: <20211105121624.398717-4-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211105121624.398717-1-tz.stoyanov@gmail.com> References: <20211105121624.398717-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The newly introduced set of APIs tracefs_dynevent_...() can be used to manage kprobes. These legacy APIs are removed as redundant: tracefs_kprobe_clear_all(); tracefs_kprobe_clear_probe(); tracefs_get_kprobes() tracefs_kprobe_info() There is one functionality, missing in the new clear API - clearing all dynamic events from specific system only. If this is needed, tracefs_dynevent_destroy() can be extended with that use case. Signed-off-by: Tzvetomir Stoyanov (VMware) --- include/tracefs.h | 11 -- src/tracefs-kprobes.c | 370 ------------------------------------------ 2 files changed, 381 deletions(-) diff --git a/include/tracefs.h b/include/tracefs.h index dfd9b51..25d9e9a 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -261,12 +261,6 @@ enum tracefs_dynevent_type tracefs_dynevent_info(struct tracefs_dynevent *dynevent, char **system, char **event, char **prefix, char **addr, char **format); -enum tracefs_kprobe_type { - TRACEFS_ALL_KPROBES, - TRACEFS_KPROBE, - TRACEFS_KRETPROBE, -}; - struct tracefs_dynevent * tracefs_kprobe_alloc(const char *system, const char *event, const char *addr, const char *format); struct tracefs_dynevent * @@ -276,11 +270,6 @@ int tracefs_kprobe_raw(const char *system, const char *event, const char *addr, const char *format); int tracefs_kretprobe_raw(const char *system, const char *event, const char *addr, const char *format); -char **tracefs_get_kprobes(enum tracefs_kprobe_type type); -enum tracefs_kprobe_type tracefs_kprobe_info(const char *group, const char *event, - char **type, char **addr, char **format); -int tracefs_kprobe_clear_all(bool force); -int tracefs_kprobe_clear_probe(const char *system, const char *event, bool force); enum tracefs_hist_key_type { TRACEFS_HIST_KEY_NORMAL = 0, diff --git a/src/tracefs-kprobes.c b/src/tracefs-kprobes.c index b9aeb9d..3f46b8d 100644 --- a/src/tracefs-kprobes.c +++ b/src/tracefs-kprobes.c @@ -213,373 +213,3 @@ int tracefs_kretprobe_raw(const char *system, const char *event, { return insert_kprobe("r", system, event, addr, format); } - -/* - * Helper function to parse kprobes. - * @content: The content of kprobe_events on the first iteration. - * NULL on next iterations. - * @saveptr: Same as saveptr for strtok_r - * @type: Where to store the type (before ':') - * @system: Store the system of the kprobe (NULL to have event contain - * both system and event, as in "kprobes/myprobe"). - * @event: Where to store the event. - * @addr: Where to store the addr (may be NULL to ignore) - * @format: Where to store the format (may be NULL to ignore) - */ -static int parse_kprobe(char *content, char **saveptr, - char **type, char **system, char **event, - char **addr, char **format) -{ - char *p; - - p = strtok_r(content, ":", saveptr); - if (!p) - return 1; /* eof */ - *type = p; - - if (system) { - p = strtok_r(NULL, "/", saveptr); - if (!p) - return -1; - *system = p; - } - - p = strtok_r(NULL, " ", saveptr); - if (!p) - return -1; - *event = p; - - if (addr || format) { - p = strtok_r(NULL, " ", saveptr); - if (!p) - return -1; - if (addr) - *addr = p; - } - - p = strtok_r(NULL, "\n", saveptr); - if (!p) - return -1; - if (format) - *format = p; - - return 0; -} - -/** - * tracefs_get_kprobes - return a list kprobes (by group/event name) - * @type: The type of kprobes to return. - * - * If @type is TRACEFS_ALL_KPROBES all kprobes in the kprobe_events - * are returned. Otherwise if it is TRACEFS_KPROBE, then only - * normal kprobes (p:) are returned, or if type is TRACEFS_KRETPROBE - * then only kretprobes (r:) are returned. - * - * Returns a list of strings that contain the kprobes that exist - * in the kprobe_events files. The strings returned are in the - * "group/event" format. - * The list must be freed with tracefs_list_free(). - * If there are no kprobes, a list is still returned, but it contains - * only a NULL pointer. - * On error, NULL is returned. - */ -char **tracefs_get_kprobes(enum tracefs_kprobe_type type) -{ - char **list = NULL; - char *content; - char *saveptr; - char *event; - char *ktype; - int ret; - - errno = 0; - content = tracefs_instance_file_read(NULL, KPROBE_EVENTS, NULL); - if (!content) { - if (errno) - return NULL; - /* content is NULL on empty file, return an empty list */ - return trace_list_create_empty(); - } - - ret = parse_kprobe(content, &saveptr, &ktype, NULL, &event, NULL, NULL); - - while (!ret) { - char **tmp; - - if (type != TRACEFS_ALL_KPROBES) { - switch (*ktype) { - case 'p': - if (type != TRACEFS_KPROBE) - goto next; - break; - case 'r': - if (type != TRACEFS_KRETPROBE) - goto next; - break; - default: - goto next; - } - } - - tmp = tracefs_list_add(list, event); - if (!tmp) - goto fail; - list = tmp; - next: - ret = parse_kprobe(NULL, &saveptr, &ktype, NULL, &event, NULL, NULL); - } - - if (!list) - list = trace_list_create_empty(); - out: - free(content); - return list; - fail: - tracefs_list_free(list); - list = NULL; - goto out; -} - -/** - * tracefs_kprobe_info - return the type of kprobe specified. - * @group: The group the kprobe is in (NULL for the default "kprobes") - * @event: The name of the kprobe to find. - * @type: String to return kprobe type (before ':') NULL to ignore. - * @addr: String to return address kprobe is attached to. NULL to ignore. - * @format: String to return kprobe format. NULL to ignore. - * - * If @type, @addr, or @format is non NULL, then the returned string - * must be freed with free(). They will also be set to NULL, and - * even on error, they may contain strings to be freed. If they are - * not NULL, then they still need to be freed. - * - * Returns TRACEFS_ALL_KPROBES if an error occurs or the kprobe is not found, - * or the probe is of an unknown type. - * TRACEFS_KPROBE if the type of kprobe found is a normal kprobe. - * TRACEFS_KRETPROBE if the type of kprobe found is a kretprobe. - */ -enum tracefs_kprobe_type tracefs_kprobe_info(const char *group, const char *event, - char **type, char **addr, char **format) -{ - enum tracefs_kprobe_type rtype = TRACEFS_ALL_KPROBES; - char *saveptr; - char *content; - char *system; - char *probe; - char *ktype; - char *kaddr; - char *kfmt; - int ret; - - if (!group) - group = KPROBE_DEFAULT_GROUP; - - if (type) - *type = NULL; - if (addr) - *addr = NULL; - if (format) - *format = NULL; - - content = tracefs_instance_file_read(NULL, KPROBE_EVENTS, NULL); - if (!content) - return rtype; - - ret = parse_kprobe(content, &saveptr, &ktype, &system, &probe, - &kaddr, &kfmt); - - while (!ret) { - - if (!strcmp(system, group) && !strcmp(probe, event)) { - if (type) - *type = strdup(ktype); - if (addr) - *addr = strdup(kaddr); - if (format) - *format = strdup(kfmt); - - switch (*ktype) { - case 'p': rtype = TRACEFS_KPROBE; break; - case 'r': rtype = TRACEFS_KRETPROBE; break; - } - break; - } - ret = parse_kprobe(NULL, &saveptr, &ktype, &system, &probe, - &kaddr, &kfmt); - } - free(content); - return rtype; -} - -static void disable_events(const char *system, const char *event, - char **list) -{ - struct tracefs_instance *instance; - int i; - - /* - * Note, this will not fail even on error. - * That is because even if something fails, it may still - * work enough to clear the kprobes. If that's the case - * the clearing after the loop will succeed and the function - * is a success, even though other parts had failed. If - * one of the kprobe events is enabled in one of the - * instances that fail, then the clearing will fail too - * and the function will return an error. - */ - - tracefs_event_disable(NULL, system, event); - /* No need to test results */ - - if (!list) - return; - - for (i = 0; list[i]; i++) { - instance = tracefs_instance_alloc(NULL, list[i]); - /* If this fails, try the next one */ - if (!instance) - continue; - tracefs_event_disable(instance, system, event); - tracefs_instance_free(instance); - } - return; -} - -static int clear_kprobe(const char *system, const char *event) -{ - /* '-' + ':' + '/' + '\n' + '\0' = 5 bytes */ - int len = strlen(system) + strlen(event) + 5; - char content[len]; - - sprintf(content, "-:%s/%s", system, event); - return tracefs_instance_file_append(NULL, KPROBE_EVENTS, content); -} - -static int kprobe_clear_probes(const char *group, bool force) -{ - char **instance_list; - char **kprobe_list; - char *saveptr; - char *system; - char *kprobe; - char *event; - int ret; - int i; - - kprobe_list = tracefs_get_kprobes(TRACEFS_ALL_KPROBES); - if (!kprobe_list) - return -1; - - instance_list = tracefs_instances(NULL); - /* - * Even if the above failed and instance_list is NULL, - * keep going, as the enabled event may simply be in the - * top level. - */ - - /* - * If a system is defined, the default is to pass unless - * an event fails to be removed. If a system is not defined, - * the default is to fail, unless all are removed. - */ - ret = group ? 0 : -1; - - for (i = 0; kprobe_list[i]; i++) { - kprobe = kprobe_list[i]; - - system = strtok_r(kprobe, "/", &saveptr); - if (!system) - goto out; - - event = strtok_r(NULL," ", &saveptr); - if (!event) - goto out; - - /* Skip if this does not match a given system */ - if (group && strcmp(system, group) != 0) - continue; - - if (force) - disable_events(system, event, instance_list); - - if (group) { - ret = clear_kprobe(system, event); - if (ret < 0) - goto out; - } else { - ret = tracefs_instance_file_clear(NULL, KPROBE_EVENTS); - /* On success stop the loop */ - if (!ret) - goto out; - } - - /* Set the default for whether a system is defined or not */ - ret = group ? 0 : -1; - } - out: - tracefs_list_free(instance_list); - tracefs_list_free(kprobe_list); - return ret; -} - -/** - * tracefs_kprobe_clear_all - clear kprobe events - * @force: Will attempt to disable all kprobe events and clear them - * - * Will remove all defined kprobe events. If any of them are enabled, - * and @force is not set, then it will error with -1 and errno to be - * EBUSY. If @force is set, then it will attempt to disable all the kprobe - * events in all instances, and try again. - * - * Returns zero on success, -1 otherwise. - */ -int tracefs_kprobe_clear_all(bool force) -{ - if (tracefs_instance_file_clear(NULL, KPROBE_EVENTS) == 0) - return 0; - - if (!force) - return -1; - - /* Attempt to disable all kprobe events */ - return kprobe_clear_probes(NULL, force); -} - -/** - * tracefs_kprobe_clear_all - clear kprobe events - * @system: System to clear (NULL means default) - * @event: Name of probe to clear in system (NULL for all probes in system) - * @force: Will attempt to disable all kprobe events and clear them - * - * Will remove the kprobes that match the @system and @event. If @system - * is NULL, then "kprobes" is used and will ignore all other system - * groups of kprobes. The @event is NULL then all events under the given - * @system are removed, otherwise only the event that matches. - * - * Returns zero on success, -1 otherwise. - */ -int tracefs_kprobe_clear_probe(const char *system, const char *event, bool force) -{ - char **instance_list; - int ret; - - if (!system) - system = "kprobes"; - - if (!event) - return kprobe_clear_probes(system, force); - - /* - * Since we know we are disabling a specific event, try - * to disable it first before clearing it. - */ - if (force) { - instance_list = tracefs_instances(NULL); - disable_events(system, event, instance_list); - tracefs_list_free(instance_list); - } - - ret = clear_kprobe(system, event); - - return ret < 0 ? -1 : 0; -} From patchwork Fri Nov 5 12:16:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 12604559 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9BD79C433F5 for ; Fri, 5 Nov 2021 12:16:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 832F961212 for ; Fri, 5 Nov 2021 12:16:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231689AbhKEMTN (ORCPT ); Fri, 5 Nov 2021 08:19:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53510 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231579AbhKEMTL (ORCPT ); Fri, 5 Nov 2021 08:19:11 -0400 Received: from mail-wr1-x433.google.com (mail-wr1-x433.google.com [IPv6:2a00:1450:4864:20::433]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C4B2CC061714 for ; Fri, 5 Nov 2021 05:16:31 -0700 (PDT) Received: by mail-wr1-x433.google.com with SMTP id c4so13388828wrd.9 for ; Fri, 05 Nov 2021 05:16:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=pU+NtIrc4CdGL98+rjHnfDjwBrEOwB3aWXlLt46NXCs=; b=BKdNEaj8lBTogocX2wLv+Ozj845XjF/GEg7/WwzXPlL5KfpVJ9NF0tQHzJJLsAjRBi V8YTrxwl4aPifzIGiCOO/q8HMCOXdh7pITs8Mez0TQNNMI8PPrIwE2SMN/lfp6Q3u2qn tcag3jvVB4VRlosGAeASIjofRdgiL2zAwLjz+N2fJ2fZpIRBqnJtU/8UtTHLQQecspeD +Jml8f6hj1Dj6sgc+ajFzOkzx5u4HtjkDRYmWAJY49msobDyN5V0LE0R6Hk3kh4Xmw91 9pwZgO8kJCjT9VF0JDJ7qmmmlMPXWzWSluMgJThIsULuWkgXSjpHmiLZyS4UFCZDRALi P43A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=pU+NtIrc4CdGL98+rjHnfDjwBrEOwB3aWXlLt46NXCs=; b=0V99dnoYR0/JOeSORkOsOL4Rc0S1BkDqQfi+4y70p+WdV2trP7JMuQyn4pmDsjVez8 lnyRnoUxz4okPpJ2diqPXaentGDH6N/MEm5SmnHUdaykr1XyWEPO/rYgzuQWWP1+AC5W jDwQ4JgAZvvaXToMrk2FE6g+HZ5/3mSKyX68m5EVDGIystVKKQagAsL4YsgClNqhr7KZ FR0Zym6cRq6lS85E12ePl3zeIf8tG7cw55DvhDmbsee/xbhEPFt2VgLrtmD/aEXSmvqo VP5FJ+aOUEr2Di8q6QeVOd7j9mqpukB2qHdoSDJDZIeOtTGFthX8vBm82FNw4N8Bckxf 0Evw== X-Gm-Message-State: AOAM531/pl3nBcn3wzQr1FVhTsdFaPIwgkK98Tk6OsPwGx6IlgXHZisw qgmZSYdwAurP3tdmaWtPEM4g4Zwr021jhA== X-Google-Smtp-Source: ABdhPJxjUmy1ZtwJz18R/6WMI1KavzznltAV5NvqCy4HhiI0VO+2jboRrBuazrJCPwuQ/F+jygLL7A== X-Received: by 2002:a05:6000:1b8f:: with SMTP id r15mr73564845wru.27.1636114590412; Fri, 05 Nov 2021 05:16:30 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id x13sm7936531wrr.47.2021.11.05.05.16.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 Nov 2021 05:16:29 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v5 04/12] libtracefs: Reimplement kprobe raw APIs Date: Fri, 5 Nov 2021 14:16:16 +0200 Message-Id: <20211105121624.398717-5-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211105121624.398717-1-tz.stoyanov@gmail.com> References: <20211105121624.398717-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org In order to unify the code and use the new dynamic event helpers, these kprobe APIs are rewritten: kracefs_kprobe_raw() kracefs_kretprobe_raw() The definition and logic of the APIs remain the same. Signed-off-by: Tzvetomir Stoyanov (VMware) --- src/tracefs-kprobes.c | 37 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/src/tracefs-kprobes.c b/src/tracefs-kprobes.c index 3f46b8d..a8c0163 100644 --- a/src/tracefs-kprobes.c +++ b/src/tracefs-kprobes.c @@ -129,37 +129,20 @@ error: return NULL; } -static int insert_kprobe(const char *type, const char *system, - const char *event, const char *addr, - const char *format) +static int kprobe_raw(enum tracefs_dynevent_type type, const char *system, + const char *event, const char *addr, const char *format) { - char *str; + static struct tracefs_dynevent *kp; int ret; - if (!tracefs_file_exists(NULL, KPROBE_EVENTS)) - return -1; - - errno = EBADMSG; - if (!addr || !format) - return -1; - - if (!event) - event = addr; - - if (system) - ret = asprintf(&str, "%s:%s/%s %s %s\n", - type, system, event, addr, format); - else - ret = asprintf(&str, "%s:%s %s %s\n", - type, event, addr, format); - - if (ret < 0) + kp = kprobe_alloc(type, system, event, addr, format); + if (!kp) return -1; - ret = tracefs_instance_file_append(NULL, KPROBE_EVENTS, str); - free(str); + ret = tracefs_dynevent_create(kp); + tracefs_dynevent_free(kp); - return ret < 0 ? ret : 0; + return ret; } /** @@ -185,7 +168,7 @@ static int insert_kprobe(const char *type, const char *system, int tracefs_kprobe_raw(const char *system, const char *event, const char *addr, const char *format) { - return insert_kprobe("p", system, event, addr, format); + return kprobe_raw(TRACEFS_DYNEVENT_KPROBE, system, event, addr, format); } /** @@ -211,5 +194,5 @@ int tracefs_kprobe_raw(const char *system, const char *event, int tracefs_kretprobe_raw(const char *system, const char *event, const char *addr, const char *format) { - return insert_kprobe("r", system, event, addr, format); + return kprobe_raw(TRACEFS_DYNEVENT_KRETPROBE, system, event, addr, format); } From patchwork Fri Nov 5 12:16:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 12604561 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3ABE1C433F5 for ; Fri, 5 Nov 2021 12:16:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 278436126A for ; Fri, 5 Nov 2021 12:16:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231579AbhKEMTN (ORCPT ); Fri, 5 Nov 2021 08:19:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53516 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229500AbhKEMTM (ORCPT ); Fri, 5 Nov 2021 08:19:12 -0400 Received: from mail-wr1-x429.google.com (mail-wr1-x429.google.com [IPv6:2a00:1450:4864:20::429]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0FEEBC061714 for ; Fri, 5 Nov 2021 05:16:33 -0700 (PDT) Received: by mail-wr1-x429.google.com with SMTP id w29so1847288wra.12 for ; Fri, 05 Nov 2021 05:16:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=fNbq/tKPHzkamp54df4h4ozNQ5WgXzPGTFvJjqi4FxM=; b=XDJ7+NyebCXmuHvkIOEHociOoxoACvkR3UKvRLeMJdcSZIhMTUajAin3/+up/aIXHE OVtr6C45lLADpGZYYfcJrXjGKSUt8xdLCWfPJ5HtzTk5ykOqNFuiosF8pqR9wns5lRlJ 4Q/2ruF/vy3rWE6to7sHz8MuFRtk09KDR9oYLlVMyFSJt6UTq4pTLbeRsMKzKe6IZLWU XH9C0OO306TXM6P5g9z0mwvSmybr/HXQ167SCT2S4bz993Q1NY7qgRlIuTxo7iMcZOYu E0AMEN/WchX9gmlloc6M/hKSHn9nVKBW8H15LAZ4FyDg85S7KscVIbicWCSK1n6aYtXR xZyg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=fNbq/tKPHzkamp54df4h4ozNQ5WgXzPGTFvJjqi4FxM=; b=rbEMCMkqYdLv8e9E1DrgRCn518JAmKgDzPdEaG0R6Fy4caUVR8ga4OD8lJaXxXimLM pzDLAacYn8sBeUHZzavPZX9TfS9i1M88AdSNmgJhAXekmIVZ6sA1frtOTma/hT7OTvBx Cj0RZfPn01oi0AxFx/UwhAPpa0Lxx8anyvU6/NO/bVuHNwXIqCogUNRw8K+jKAK8XQgX T0ixTTIRWenV4Go2SXiE0Y3+Y/rGNFOzB74+JeuuTI8PLzflU/XHJvO9E6mkmDOEbxez qGTdkK59jNI2i5aVzPQTnmGaXUdFpiREp1hqxO4i03osL1bQLpHPw5JEKJn2JAHH+L+Q SJtw== X-Gm-Message-State: AOAM5336C+09Gtun2xRWBWxAJrNLkruas19ThlC0cjwPXyg3ziYkGKKd W5hvAP52BfEw6rlvHJDoPBU= X-Google-Smtp-Source: ABdhPJwZvQP1yfVlbI44gXQMgLS0EVaWKs9p0a2l5QH/U6sD9WYe2wfF026lnbi8kOhcWWHbk43/zQ== X-Received: by 2002:a5d:59ab:: with SMTP id p11mr28095829wrr.340.1636114591640; Fri, 05 Nov 2021 05:16:31 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id x13sm7936531wrr.47.2021.11.05.05.16.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 Nov 2021 05:16:31 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v5 05/12] libtracefs: Extend kprobes unit test Date: Fri, 5 Nov 2021 14:16:17 +0200 Message-Id: <20211105121624.398717-6-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211105121624.398717-1-tz.stoyanov@gmail.com> References: <20211105121624.398717-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org As there are a lot of changes in the libtracefs kprobes APIs, the unit test of that functionality should be updated. A new test section is added, for testing the all kprobes APIs. Signed-off-by: Tzvetomir Stoyanov (VMware) --- utest/tracefs-utest.c | 423 +++++++++++++++++++++++++----------------- 1 file changed, 253 insertions(+), 170 deletions(-) diff --git a/utest/tracefs-utest.c b/utest/tracefs-utest.c index 09bb8f2..5b656d4 100644 --- a/utest/tracefs-utest.c +++ b/utest/tracefs-utest.c @@ -28,22 +28,6 @@ #define TRACE_ON "tracing_on" #define TRACE_CLOCK "trace_clock" -#define KPROBE_EVENTS "kprobe_events" - -#define KPROBE_1_NAME "mkdir" -#define KPROBE_1_GROUP "kprobes" -#define KPROBE_1_ADDR "do_mkdirat" -#define KPROBE_1_FMT "path=+u0($arg2):ustring" - -#define KPROBE_2_NAME "open" -#define KPROBE_2_GROUP "myprobe" -#define KPROBE_2_ADDR "do_sys_openat2" -#define KPROBE_2_FMT "file=+u0($arg2):ustring flags=+0($arg3):x64" - -#define KRETPROBE_NAME "retopen" -#define KRETPROBE_ADDR "do_sys_openat2" -#define KRETPROBE_FMT "ret=$retval" - #define SQL_1_EVENT "wakeup_1" #define SQL_1_SQL "select sched_switch.next_pid as woke_pid, sched_waking.common_pid as waking_pid from sched_waking join sched_switch on sched_switch.next_pid = sched_waking.pid" @@ -398,6 +382,27 @@ static void test_trace_sql(void) test_instance_trace_sql(test_instance); } +static struct tracefs_dynevent **get_dynevents_check(enum tracefs_dynevent_type types, int count) +{ + struct tracefs_dynevent **devents; + int i; + + devents = tracefs_dynevent_get_all(types, NULL); + if (count) { + CU_TEST(devents != NULL); + if (!devents) + return NULL; + i = 0; + while (devents[i]) + i++; + CU_TEST(i == count); + } else { + CU_TEST(devents == NULL); + } + + return devents; +} + static void test_trace_file(void) { const char *tmp = get_rand_str(); @@ -457,28 +462,252 @@ static void test_instance_file_read(struct tracefs_instance *inst, const char *f free(file); } +#define KPROBE_DEFAULT_GROUP "kprobes" +struct kprobe_test { + enum tracefs_dynevent_type type; + char *prefix; + char *system; + char *event; + char *address; + char *format; +}; + +static bool check_kprobes(struct kprobe_test *kprobes, int count, + struct tracefs_dynevent **devents, bool in_system, + struct tracefs_instance *instance) +{ + + enum tracefs_dynevent_type ktype; + char *ename; + char *kaddress; + char *kevent; + char *ksystem; + char *kformat; + char *kprefix; + int found = 0; + int ret; + int i, j; + + for (i = 0; devents && devents[i]; i++) { + ktype = tracefs_dynevent_info(devents[i], &ksystem, + &kevent, &kprefix, &kaddress, &kformat); + for (j = 0; j < count; j++) { + if (ktype != kprobes[j].type) + continue; + if (kprobes[j].event) + ename = kprobes[j].event; + else + ename = kprobes[j].address; + if (strcmp(ename, kevent)) + continue; + if (kprobes[j].system) { + CU_TEST(strcmp(kprobes[j].system, ksystem) == 0); + } else { + CU_TEST(strcmp(KPROBE_DEFAULT_GROUP, ksystem) == 0); + } + CU_TEST(strcmp(kprobes[j].address, kaddress) == 0); + if (kprobes[j].format) { + CU_TEST(strcmp(kprobes[j].format, kformat) == 0); + } + if (kprobes[j].prefix) { + CU_TEST(strcmp(kprobes[j].prefix, kprefix) == 0); + } + ret = tracefs_event_enable(instance, ksystem, kevent); + if (in_system) { + CU_TEST(ret == 0); + } else { + CU_TEST(ret != 0); + } + ret = tracefs_event_disable(instance, ksystem, kevent); + if (in_system) { + CU_TEST(ret == 0); + } else { + CU_TEST(ret != 0); + } + + found++; + break; + } + free(ksystem); + free(kevent); + free(kprefix); + free(kaddress); + free(kformat); + } + + CU_TEST(found == count); + if (found != count) + return false; + + return true; +} + +static void test_kprobes_instance(struct tracefs_instance *instance) +{ + struct kprobe_test ktests[] = { + { TRACEFS_DYNEVENT_KPROBE, "p", NULL, "mkdir", "do_mkdirat", "path=+u0($arg2):ustring" }, + { TRACEFS_DYNEVENT_KPROBE, "p", NULL, "close", "close_fd", NULL }, + { TRACEFS_DYNEVENT_KPROBE, "p", "ptest", "open2", "do_sys_openat2", + "file=+u0($arg2):ustring flags=+0($arg3):x64" }, + }; + struct kprobe_test kretests[] = { + { TRACEFS_DYNEVENT_KRETPROBE, NULL, NULL, "retopen", "do_sys_openat2", "ret=$retval" }, + { TRACEFS_DYNEVENT_KRETPROBE, NULL, NULL, NULL, "do_sys_open", "ret=$retval" }, + }; + int kretprobe_count = sizeof(kretests) / sizeof((kretests)[0]); + int kprobe_count = sizeof(ktests) / sizeof((ktests)[0]); + struct tracefs_dynevent **dkretprobe; + struct tracefs_dynevent **dkprobe; + struct tracefs_dynevent **devents; + char *tmp; + int ret; + int i; + + dkprobe = calloc(kprobe_count + 1, sizeof(*dkprobe)); + dkretprobe = calloc(kretprobe_count + 1, sizeof(*dkretprobe)); + + /* Invalid parameters */ + CU_TEST(tracefs_kprobe_alloc("test", NULL, NULL, "test") == NULL); + CU_TEST(tracefs_kretprobe_alloc("test", NULL, NULL, "test", 0) == NULL); + CU_TEST(tracefs_dynevent_create(NULL) != 0); + CU_TEST(tracefs_dynevent_info(NULL, &tmp, &tmp, &tmp, &tmp, &tmp) == TRACEFS_DYNEVENT_UNKNOWN); + CU_TEST(tracefs_kprobe_raw("test", "test", NULL, "test") != 0); + CU_TEST(tracefs_kretprobe_raw("test", "test", NULL, "test") != 0); + + /* kprobes APIs */ + ret = tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, true); + CU_TEST(ret == 0); + get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, 0); + + for (i = 0; i < kprobe_count; i++) { + dkprobe[i] = tracefs_kprobe_alloc(ktests[i].system, ktests[i].event, + ktests[i].address, ktests[i].format); + CU_TEST(dkprobe[i] != NULL); + } + dkprobe[i] = NULL; + get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, 0); + CU_TEST(check_kprobes(ktests, kprobe_count, dkprobe, false, instance)); + + for (i = 0; i < kretprobe_count; i++) { + dkretprobe[i] = tracefs_kretprobe_alloc(kretests[i].system, kretests[i].event, + kretests[i].address, kretests[i].format, 0); + CU_TEST(dkretprobe[i] != NULL); + } + dkretprobe[i] = NULL; + get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, 0); + CU_TEST(check_kprobes(kretests, kretprobe_count, dkretprobe, false, instance)); + + for (i = 0; i < kprobe_count; i++) { + CU_TEST(tracefs_dynevent_create(dkprobe[i]) == 0); + } + devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, + kprobe_count); + CU_TEST(check_kprobes(ktests, kprobe_count, devents, true, instance)); + CU_TEST(check_kprobes(kretests, kretprobe_count, dkretprobe, false, instance)); + tracefs_dynevent_list_free(devents); + devents = NULL; + + for (i = 0; i < kretprobe_count; i++) { + CU_TEST(tracefs_dynevent_create(dkretprobe[i]) == 0); + } + devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, + kprobe_count + kretprobe_count); + CU_TEST(check_kprobes(ktests, kprobe_count, devents, true, instance)); + CU_TEST(check_kprobes(kretests, kretprobe_count, devents, true, instance)); + tracefs_dynevent_list_free(devents); + devents = NULL; + + for (i = 0; i < kretprobe_count; i++) { + CU_TEST(tracefs_dynevent_destroy(dkretprobe[i], false) == 0); + } + devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, + kprobe_count); + CU_TEST(check_kprobes(ktests, kprobe_count, devents, true, instance)); + CU_TEST(check_kprobes(kretests, kretprobe_count, dkretprobe, false, instance)); + tracefs_dynevent_list_free(devents); + devents = NULL; + + for (i = 0; i < kprobe_count; i++) { + CU_TEST(tracefs_dynevent_destroy(dkprobe[i], false) == 0); + } + get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, 0); + CU_TEST(check_kprobes(ktests, kprobe_count, dkprobe, false, instance)); + CU_TEST(check_kprobes(kretests, kretprobe_count, dkretprobe, false, instance)); + tracefs_dynevent_list_free(devents); + devents = NULL; + + for (i = 0; i < kprobe_count; i++) + tracefs_dynevent_free(dkprobe[i]); + for (i = 0; i < kretprobe_count; i++) + tracefs_dynevent_free(dkretprobe[i]); + + /* kprobes raw APIs */ + ret = tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, true); + CU_TEST(ret == 0); + get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, 0); + + for (i = 0; i < kprobe_count; i++) { + ret = tracefs_kprobe_raw(ktests[i].system, ktests[i].event, + ktests[i].address, ktests[i].format); + CU_TEST(ret == 0); + } + + devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, kprobe_count); + CU_TEST(check_kprobes(ktests, kprobe_count, devents, true, instance)); + tracefs_dynevent_list_free(devents); + devents = NULL; + + for (i = 0; i < kretprobe_count; i++) { + ret = tracefs_kretprobe_raw(kretests[i].system, kretests[i].event, + kretests[i].address, kretests[i].format); + CU_TEST(ret == 0); + } + + devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE, kprobe_count); + CU_TEST(check_kprobes(ktests, kprobe_count, devents, true, instance)); + tracefs_dynevent_list_free(devents); + devents = NULL; + + devents = get_dynevents_check(TRACEFS_DYNEVENT_KRETPROBE, kretprobe_count); + CU_TEST(check_kprobes(kretests, kretprobe_count, devents, true, instance)); + tracefs_dynevent_list_free(devents); + devents = NULL; + + devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, + kprobe_count + kretprobe_count); + CU_TEST(check_kprobes(ktests, kprobe_count, devents, true, instance)); + CU_TEST(check_kprobes(kretests, kretprobe_count, devents, true, instance)); + tracefs_dynevent_list_free(devents); + devents = NULL; + + ret = tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, true); + CU_TEST(ret == 0); + get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, 0); + free(dkretprobe); + free(dkprobe); +} + +static void test_kprobes(void) +{ + test_kprobes_instance(test_instance); +} + static void test_instance_file(void) { struct tracefs_instance *instance = NULL; struct tracefs_instance *second = NULL; - enum tracefs_kprobe_type type; const char *name = get_rand_str(); const char *inst_name = NULL; const char *tdir; char *inst_file; char *inst_dir; struct stat st; - char **kprobes; - char *kformat; - char *ktype; - char *kaddr; - char *fname; char *file1; char *file2; char *tracer; + char *fname; int size; int ret; - int i; tdir = tracefs_tracing_dir(); CU_TEST(tdir != NULL); @@ -541,153 +770,6 @@ static void test_instance_file(void) free(file1); free(file2); - ret = tracefs_kprobe_clear_all(true); - CU_TEST(ret == 0); - ret = tracefs_kprobe_raw(NULL, KPROBE_1_NAME, KPROBE_1_ADDR, KPROBE_1_FMT); - CU_TEST(ret == 0); - ret = tracefs_kprobe_raw(KPROBE_2_GROUP, KPROBE_2_NAME, KPROBE_2_ADDR, - KPROBE_2_FMT); - CU_TEST(ret == 0); - - ret = tracefs_kretprobe_raw(KPROBE_2_GROUP, KRETPROBE_NAME, KRETPROBE_ADDR, - KRETPROBE_FMT); - CU_TEST(ret == 0); - - type = tracefs_kprobe_info(KPROBE_1_GROUP, KPROBE_1_NAME, &ktype, - &kaddr, &kformat); - CU_TEST(type == TRACEFS_KPROBE); - CU_TEST(ktype && *ktype == 'p'); - CU_TEST(kaddr && !strcmp(kaddr, KPROBE_1_ADDR)); - CU_TEST(kformat && !strcmp(kformat, KPROBE_1_FMT)); - free(ktype); - free(kaddr); - free(kformat); - - type = tracefs_kprobe_info(KPROBE_2_GROUP, KPROBE_2_NAME, &ktype, - &kaddr, &kformat); - CU_TEST(type == TRACEFS_KPROBE); - CU_TEST(ktype && *ktype == 'p'); - CU_TEST(kaddr && !strcmp(kaddr, KPROBE_2_ADDR)); - CU_TEST(kformat && !strcmp(kformat, KPROBE_2_FMT)); - free(ktype); - free(kaddr); - free(kformat); - - type = tracefs_kprobe_info(KPROBE_2_GROUP, KRETPROBE_NAME, &ktype, - &kaddr, &kformat); - CU_TEST(type == TRACEFS_KRETPROBE); - CU_TEST(ktype && *ktype == 'r'); - CU_TEST(kaddr && !strcmp(kaddr, KRETPROBE_ADDR)); - CU_TEST(kformat && !strcmp(kformat, KRETPROBE_FMT)); - free(ktype); - free(kaddr); - free(kformat); - - kprobes = tracefs_get_kprobes(TRACEFS_ALL_KPROBES); - CU_TEST(kprobes != NULL); - - for (i = 0; kprobes[i]; i++) { - char *system = strtok(kprobes[i], "/"); - char *event = strtok(NULL, ""); - bool found = false; - if (!strcmp(system, KPROBE_1_GROUP)) { - CU_TEST(!strcmp(event, KPROBE_1_NAME)); - found = true; - } else if (!strcmp(system, KPROBE_2_GROUP)) { - switch (tracefs_kprobe_info(system, event, NULL, NULL, NULL)) { - case TRACEFS_KPROBE: - CU_TEST(!strcmp(event, KPROBE_2_NAME)); - found = true; - break; - case TRACEFS_KRETPROBE: - CU_TEST(!strcmp(event, KRETPROBE_NAME)); - found = true; - break; - default: - break; - } - } - CU_TEST(found); - } - tracefs_list_free(kprobes); - CU_TEST(i == 3); - - kprobes = tracefs_get_kprobes(TRACEFS_KPROBE); - CU_TEST(kprobes != NULL); - - for (i = 0; kprobes[i]; i++) { - char *system = strtok(kprobes[i], "/"); - char *event = strtok(NULL, ""); - bool found = false; - if (!strcmp(system, KPROBE_1_GROUP)) { - CU_TEST(!strcmp(event, KPROBE_1_NAME)); - found = true; - } else if (!strcmp(system, KPROBE_2_GROUP)) { - CU_TEST(!strcmp(event, KPROBE_2_NAME)); - found = true; - } - CU_TEST(found); - } - tracefs_list_free(kprobes); - CU_TEST(i == 2); - - kprobes = tracefs_get_kprobes(TRACEFS_KRETPROBE); - CU_TEST(kprobes != NULL); - - for (i = 0; kprobes[i]; i++) { - char *system = strtok(kprobes[i], "/"); - char *event = strtok(NULL, ""); - bool found = false; - if (!strcmp(system, KPROBE_2_GROUP)) { - CU_TEST(!strcmp(event, KRETPROBE_NAME)); - found = true; - } - CU_TEST(found); - } - tracefs_list_free(kprobes); - CU_TEST(i == 1); - - ret = tracefs_event_enable(instance, KPROBE_1_GROUP, KPROBE_1_NAME); - CU_TEST(ret == 0); - ret = tracefs_event_enable(instance, KPROBE_2_GROUP, KPROBE_2_NAME); - CU_TEST(ret == 0); - ret = tracefs_event_enable(instance, KPROBE_2_GROUP, KRETPROBE_NAME); - CU_TEST(ret == 0); - - ret = tracefs_kprobe_clear_all(false); - CU_TEST(ret < 0); - - ret = tracefs_kprobe_clear_probe(KPROBE_2_GROUP, NULL, false); - CU_TEST(ret < 0); - - ret = tracefs_kprobe_clear_probe(KPROBE_2_GROUP, NULL, true); - CU_TEST(ret == 0); - - kprobes = tracefs_get_kprobes(TRACEFS_ALL_KPROBES); - CU_TEST(kprobes != NULL); - - for (i = 0; kprobes[i]; i++) { - char *system = strtok(kprobes[i], "/"); - char *event = strtok(NULL, ""); - bool found = false; - if (!strcmp(system, KPROBE_1_GROUP)) { - CU_TEST(!strcmp(event, KPROBE_1_NAME)); - found = true; - } - CU_TEST(found); - } - tracefs_list_free(kprobes); - CU_TEST(i == 1); - - ret = tracefs_kprobe_clear_all(true); - CU_TEST(ret == 0); - - kprobes = tracefs_get_kprobes(TRACEFS_ALL_KPROBES); - CU_TEST(kprobes != NULL); - - CU_TEST(kprobes[0] == NULL); - tracefs_list_free(kprobes); - tracefs_put_tracing_file(inst_file); free(fname); @@ -1442,4 +1524,5 @@ void test_tracefs_lib(void) test_custom_trace_dir); CU_add_test(suite, "ftrace marker", test_ftrace_marker); + CU_add_test(suite, "kprobes", test_kprobes); } From patchwork Fri Nov 5 12:16:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 12604563 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A8687C433F5 for ; Fri, 5 Nov 2021 12:16:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8D1886125F for ; Fri, 5 Nov 2021 12:16:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229500AbhKEMTO (ORCPT ); Fri, 5 Nov 2021 08:19:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53520 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231701AbhKEMTN (ORCPT ); Fri, 5 Nov 2021 08:19:13 -0400 Received: from mail-wr1-x435.google.com (mail-wr1-x435.google.com [IPv6:2a00:1450:4864:20::435]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EE3E4C061205 for ; Fri, 5 Nov 2021 05:16:33 -0700 (PDT) Received: by mail-wr1-x435.google.com with SMTP id d5so13435037wrc.1 for ; Fri, 05 Nov 2021 05:16:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ABZjsyOO/AhAnAmWhGbPrjgUy8/xMGWdTj2ZLDLOEzw=; b=i449WZA6Je0Ivsjvh+y4VVYxASh+5k+HPhEAzD5lUvbnN0OcMPdJmtG/TunCuc7pAY g2ka2flpv4CM6cBFTFTUzHgDBm52n+YBhNBi/buPH6jC7zp4tG2+9oYakiBUKeC5j2bC U0cmucOenyU0vr6c1AjycJkxLMmn9SYQMAQE/HACodaRiqJmY6spSHBcPhPRFzrhdqfz JeItiPOwaGwuTYyLOomnwBqJ1XN5tI7n1MsxPZGdHkV51ryAwLSBqeUYesco/WCDzSOM I9/7F2J/BEoIrT7W4FedyGuv4eeNKFkH0ypGAMt0jaBQgAozl5/3enBDsAs/2GhRjSTU EgCQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ABZjsyOO/AhAnAmWhGbPrjgUy8/xMGWdTj2ZLDLOEzw=; b=awGjSOa/r9FA0WmpxSgxkm5P5yAcoHtncdKEgfZuDi2yIJmq1nY3GGXl9PXzMkX2EF 9/tK5UaCJW+8DGt6Yul7rIZD7VLa3mBVn0uapoWrGT+MBp8CQ6rex7xiakcGEA4aULEs 7pAjuEP9LyjQPJ+YA++JvejbXUHTauEqWT3+A7FEUUOw8zvHXOCvF30aihbmKYYvvoqB XJv5Ap5yC+GKHyOn+gHCA9NmW4cvYreMtjjMDc+m6gn4Dqmuvg0Z2DmVrzXeRYhpFtHT Y6aWI0EIsNad0tSvMTSDGriisNZLGU8tZmJYhrE+z4bcDy/Mrwl+73nYiXd8QCsWJkr9 6w5w== X-Gm-Message-State: AOAM530TgVzt/jtJfdhAL5mIiiodjJrOhoZtqi7k6R0VDdq3Gd50DaGC SJ5CkHTwA8qcHhxaybZnPpIJtJ1EPuNcoA== X-Google-Smtp-Source: ABdhPJy2dFMoKs26ss7WEMuZINZdRuM8S6f8Yzc5rJ2MNN/QzejHe4k2m+tmf56ziwer5F6bB2K8Bg== X-Received: by 2002:adf:fe4f:: with SMTP id m15mr44046344wrs.81.1636114592548; Fri, 05 Nov 2021 05:16:32 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id x13sm7936531wrr.47.2021.11.05.05.16.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 Nov 2021 05:16:32 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v5 06/12] libtracefs: Rename tracefs_synth_init API Date: Fri, 5 Nov 2021 14:16:18 +0200 Message-Id: <20211105121624.398717-7-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211105121624.398717-1-tz.stoyanov@gmail.com> References: <20211105121624.398717-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org In order to be consistent with the others library APIs, the tracefs_synth_init() is renamed to tracefs_synth_alloc(). Signed-off-by: Tzvetomir Stoyanov (VMware) --- Documentation/libtracefs-synth.txt | 20 ++++++++++---------- Documentation/libtracefs-synth2.txt | 10 +++++----- include/tracefs.h | 18 +++++++++--------- src/tracefs-hist.c | 22 +++++++++++----------- src/tracefs-sqlhist.c | 6 +++--- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/Documentation/libtracefs-synth.txt b/Documentation/libtracefs-synth.txt index 77076e1..2fd9019 100644 --- a/Documentation/libtracefs-synth.txt +++ b/Documentation/libtracefs-synth.txt @@ -3,7 +3,7 @@ libtracefs(3) NAME ---- -tracefs_synth_init, tracefs_synth_add_match_field, tracefs_synth_add_compare_field, tracefs_synth_add_start_field, +tracefs_synth_alloc, tracefs_synth_add_match_field, tracefs_synth_add_compare_field, tracefs_synth_add_start_field, tracefs_synth_add_end_field, tracefs_synth_append_start_filter, tracefs_synth_append_end_filter, tracefs_synth_free, - Creation of a synthetic event descriptor @@ -13,7 +13,7 @@ SYNOPSIS -- *#include * -struct tracefs_synth pass:[*]tracefs_synth_init(struct tep_handle pass:[*]tep, +struct tracefs_synth pass:[*]tracefs_synth_alloc(struct tep_handle pass:[*]tep, const char pass:[*]name, const char pass:[*]start_system, const char pass:[*]start_event, @@ -69,7 +69,7 @@ as a field for both events to calculate the delta in nanoseconds, or use *TRACEFS_TIMESTAMP_USECS" as the compare fields for both events to calculate the delta in microseconds. This is used as the example below. -*tracefs_synth_init*() allocates and initializes a synthetic event. +*tracefs_synth_alloc*() allocates and initializes a synthetic event. It does not create the synthetic event, but supplies the minimal information to do so. See *tracefs_synth_create*(3) for how to create the synthetic event in the system. It requires a _tep_ handler that can be created by @@ -156,11 +156,11 @@ _field_, _compare_, and _val_ are ignored unless _type_ is equal to filters on the ending event. *tracefs_synth_free*() frees the allocated descriptor returned by -*tracefs_synth_init*(). +*tracefs_synth_alloc*(). RETURN VALUE ------------ -*tracefs_synth_init*() returns an allocated struct tracefs_synth descriptor +*tracefs_synth_alloc*() returns an allocated struct tracefs_synth descriptor on sucess or NULL on error. All other functions that return an integer returns zero on success or -1 @@ -209,11 +209,11 @@ static void make_event(void) tep = tracefs_local_events(NULL); /* Initialize the synthetic event */ - synth = tracefs_synth_init(tep, "wakeup_lat", - NULL, start_event, - NULL, end_event, - start_field, end_field, - match_name); + synth = tracefs_synth_alloc(tep, "wakeup_lat", + NULL, start_event, + NULL, end_event, + start_field, end_field, + match_name); /* The tep is no longer needed */ tep_free(tep); diff --git a/Documentation/libtracefs-synth2.txt b/Documentation/libtracefs-synth2.txt index 4c44253..f734b44 100644 --- a/Documentation/libtracefs-synth2.txt +++ b/Documentation/libtracefs-synth2.txt @@ -142,11 +142,11 @@ static void make_event(void) tep = tracefs_local_events(NULL); /* Initialize the synthetic event */ - synth = tracefs_synth_init(tep, "wakeup_lat", - NULL, start_event, - NULL, end_event, - start_field, end_field, - match_name); + synth = tracefs_synth_alloc(tep, "wakeup_lat", + NULL, start_event, + NULL, end_event, + start_field, end_field, + match_name); /* The tep is no longer needed */ tep_free(tep); diff --git a/include/tracefs.h b/include/tracefs.h index 25d9e9a..1092609 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -479,15 +479,15 @@ enum tracefs_synth_handler { TRACEFS_SYNTH_HANDLE_CHANGE, }; -struct tracefs_synth *tracefs_synth_init(struct tep_handle *tep, - const char *name, - const char *start_system, - const char *start_event, - const char *end_system, - const char *end_event, - const char *start_match_field, - const char *end_match_field, - const char *match_name); +struct tracefs_synth *tracefs_synth_alloc(struct tep_handle *tep, + const char *name, + const char *start_system, + const char *start_event, + const char *end_system, + const char *end_event, + const char *start_match_field, + const char *end_match_field, + const char *match_name); int tracefs_synth_add_match_field(struct tracefs_synth *synth, const char *start_match_field, const char *end_match_field, diff --git a/src/tracefs-hist.c b/src/tracefs-hist.c index 27bab00..9009dba 100644 --- a/src/tracefs-hist.c +++ b/src/tracefs-hist.c @@ -692,7 +692,7 @@ static void action_free(struct action *action) * @synth: The tracefs_synth descriptor * * Frees the resources allocated for a @synth created with - * tracefs_synth_init(). It does not touch the system. That is, + * tracefs_synth_alloc(). It does not touch the system. That is, * any synthetic event created, will not be destroyed by this * function. */ @@ -890,7 +890,7 @@ synth_init_from(struct tep_handle *tep, const char *start_system, } /** - * tracefs_synth_init - create a new tracefs_synth instance + * tracefs_synth_alloc - create a new tracefs_synth instance * @tep: The tep handle that holds the events to work on * @name: The name of the synthetic event being created * @start_system: The name of the system of the start event (can be NULL) @@ -933,15 +933,15 @@ synth_init_from(struct tep_handle *tep, const char *start_system, * event on the system is not created. That needs to be done with * tracefs_synth_create(). */ -struct tracefs_synth *tracefs_synth_init(struct tep_handle *tep, - const char *name, - const char *start_system, - const char *start_event_name, - const char *end_system, - const char *end_event_name, - const char *start_match_field, - const char *end_match_field, - const char *match_name) +struct tracefs_synth *tracefs_synth_alloc(struct tep_handle *tep, + const char *name, + const char *start_system, + const char *start_event_name, + const char *end_system, + const char *end_event_name, + const char *start_match_field, + const char *end_match_field, + const char *match_name) { struct tep_event *end_event; struct tracefs_synth *synth; diff --git a/src/tracefs-sqlhist.c b/src/tracefs-sqlhist.c index d77ce86..016f3eb 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -1419,9 +1419,9 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, assign_match(start_system, start_event, match, &start_match, &end_match); - synth = tracefs_synth_init(tep, name, start_system, - start_event, end_system, end_event, - start_match, end_match, NULL); + synth = tracefs_synth_alloc(tep, name, start_system, + start_event, end_system, end_event, + start_match, end_match, NULL); if (!synth) return synth_init_error(tep, table); From patchwork Fri Nov 5 12:16:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 12604565 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9A0DBC433EF for ; Fri, 5 Nov 2021 12:16:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 82BE061262 for ; Fri, 5 Nov 2021 12:16:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232907AbhKEMTS (ORCPT ); Fri, 5 Nov 2021 08:19:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53528 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231812AbhKEMTP (ORCPT ); Fri, 5 Nov 2021 08:19:15 -0400 Received: from mail-wr1-x436.google.com (mail-wr1-x436.google.com [IPv6:2a00:1450:4864:20::436]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1018AC061714 for ; Fri, 5 Nov 2021 05:16:35 -0700 (PDT) Received: by mail-wr1-x436.google.com with SMTP id d5so13435159wrc.1 for ; Fri, 05 Nov 2021 05:16:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=/zEYxxWK7AJUhX+N6jD72TiSKrMak0akFQ6L9/qdvx4=; b=FEpBnEPEWIVcbDA1toCmaiA54MAzuDWTvpSqq/3DhREg4Wymp/D/RXzSgu8lUWYJfj /l3zlpHgNazo2zMGJgQr8QDp3UJGkZ84pnv/IRYadl8YfFaevoV56tELQPUcbyo09bHl EHb+O4ilvHVWEr4uRMCuADx6nsMa3Ui9TCp396I0ospiuP0rpWRb37NAnoCEatirk5m5 VkALgOY6zzXGnFnxz37cmfET9iKdSR+aJ1w2cD7z2JGWmjV1UL5bPAMZPoVSHAL5b8t1 4YDfRxo3sWA4FR7757ubPp+O5Gs7Fk/O7EkBA3eWir5ZEITGaJStKMIc5qnTN1veMn7B EqOA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=/zEYxxWK7AJUhX+N6jD72TiSKrMak0akFQ6L9/qdvx4=; b=LUP/DSOEu/SO3e6Se7sdPLXABJm5mgHYzkBRx9Ia28Kld0YheohZkpdPJZbWhFlT3A 1PeDQ04D78ULk0biYn6QkR6OC0JxOGwiiYfKPw7eW/UXyFUrM3cURCsUMp+ylidwIjYO DxFg8NYDsajkn/U/W1CPtSSgSZg4rgooAoqJfO8Fdi03Wx1h/OvVY+aiIBoJHHMLxlzD 0RXLUKUDL/toOkUWWnTrGZ4vJgAftZckE9Yl+WIiV9bCNr7SRBKY6r1RIGmR3IGDcLpU /fYYTRz+99KLyGpaRQrD/V2+We6RWK9QZXRihjxMd4BUSKFHEv79qTHUVrzD2FIhwVHh tu5Q== X-Gm-Message-State: AOAM532wDTKGID41WZaNY+YdRVYweW51CeLieBebALHLRWTP4tUkOgQt tQR66zrH2ZAo+qqJw2rTdsk= X-Google-Smtp-Source: ABdhPJysONgdqBul0qRYf1Up4MDNoSCoBGhqcQWMUL5d2evxb42QFwp1zFPg3S96eRcDtd+67fM3LA== X-Received: by 2002:a5d:6449:: with SMTP id d9mr45980123wrw.332.1636114593639; Fri, 05 Nov 2021 05:16:33 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id x13sm7936531wrr.47.2021.11.05.05.16.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 Nov 2021 05:16:33 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v5 07/12] libtracefs: Use the internal dynamic events API when creating synthetic events Date: Fri, 5 Nov 2021 14:16:19 +0200 Message-Id: <20211105121624.398717-8-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211105121624.398717-1-tz.stoyanov@gmail.com> References: <20211105121624.398717-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org Synthetic events are type of ftrace dynamic events. The tracefs library has dedicated APIs to manage dynamic events of all types. In order the code to be consistent, the creation of synthetic events inside the library is reimplemented with these new dynamic events APIs. Signed-off-by: Tzvetomir Stoyanov (VMware) --- src/tracefs-hist.c | 105 +++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 56 deletions(-) diff --git a/src/tracefs-hist.c b/src/tracefs-hist.c index 9009dba..2685dab 100644 --- a/src/tracefs-hist.c +++ b/src/tracefs-hist.c @@ -24,6 +24,8 @@ #define ASCENDING ".ascending" #define DESCENDING ".descending" +#define SYNTHETIC_GROUP "synthetic" + struct tracefs_hist { struct tep_handle *tep; struct tep_event *event; @@ -661,6 +663,7 @@ struct tracefs_synth { struct tep_event *end_event; struct action *actions; struct action **next_action; + struct tracefs_dynevent *dyn_event; char *name; char **synthetic_fields; char **synthetic_args; @@ -719,6 +722,7 @@ void tracefs_synth_free(struct tracefs_synth *synth) synth->actions = action->next; action_free(action); } + tracefs_dynevent_free(synth->dyn_event); free(synth); } @@ -889,6 +893,28 @@ synth_init_from(struct tep_handle *tep, const char *start_system, return synth; } +static int alloc_synthetic_event(struct tracefs_synth *synth) +{ + char *format; + const char *field; + int i; + + format = strdup(""); + if (!format) + return -1; + + for (i = 0; synth->synthetic_fields && synth->synthetic_fields[i]; i++) { + field = synth->synthetic_fields[i]; + format = append_string(format, i ? " " : NULL, field); + } + + synth->dyn_event = dynevent_alloc(TRACEFS_DYNEVENT_SYNTH, SYNTHETIC_GROUP, + synth->name, NULL, format); + free(format); + + return synth->dyn_event ? 0 : -1; +} + /** * tracefs_synth_alloc - create a new tracefs_synth instance * @tep: The tep handle that holds the events to work on @@ -1609,38 +1635,6 @@ int tracefs_synth_save(struct tracefs_synth *synth, return 0; } -static char *create_synthetic_event(struct tracefs_synth *synth) -{ - char *synthetic_event; - const char *field; - int i; - - synthetic_event = strdup(synth->name); - if (!synthetic_event) - return NULL; - - for (i = 0; synth->synthetic_fields && synth->synthetic_fields[i]; i++) { - field = synth->synthetic_fields[i]; - synthetic_event = append_string(synthetic_event, " ", field); - } - - return synthetic_event; -} - -static int remove_synthetic(const char *synthetic) -{ - char *str; - int ret; - - ret = asprintf(&str, "!%s", synthetic); - if (ret < 0) - return -1; - - ret = tracefs_instance_file_append(NULL, "synthetic_events", str); - free(str); - return ret < 0 ? -1 : 0; -} - static int remove_hist(struct tracefs_instance *instance, struct tep_event *event, const char *hist) { @@ -1919,7 +1913,6 @@ tracefs_synth_get_start_hist(struct tracefs_synth *synth) int tracefs_synth_create(struct tracefs_instance *instance, struct tracefs_synth *synth) { - char *synthetic_event; char *start_hist = NULL; char *end_hist = NULL; int ret; @@ -1937,14 +1930,10 @@ int tracefs_synth_create(struct tracefs_instance *instance, if (verify_state(synth) < 0) return -1; - synthetic_event = create_synthetic_event(synth); - if (!synthetic_event) + if (!synth->dyn_event && alloc_synthetic_event(synth)) + return -1; + if (tracefs_dynevent_create(synth->dyn_event)) return -1; - - ret = tracefs_instance_file_append(NULL, "synthetic_events", - synthetic_event); - if (ret < 0) - goto free_synthetic; start_hist = create_hist(synth->start_keys, synth->start_vars); start_hist = append_filter(start_hist, synth->start_filter, @@ -1980,9 +1969,7 @@ int tracefs_synth_create(struct tracefs_instance *instance, remove_synthetic: free(end_hist); free(start_hist); - remove_synthetic(synthetic_event); - free_synthetic: - free(synthetic_event); + tracefs_dynevent_destroy(synth->dyn_event, false); return -1; } @@ -2007,7 +1994,6 @@ int tracefs_synth_create(struct tracefs_instance *instance, int tracefs_synth_destroy(struct tracefs_instance *instance, struct tracefs_synth *synth) { - char *synthetic_event; char *hist; int ret; @@ -2041,11 +2027,7 @@ int tracefs_synth_destroy(struct tracefs_instance *instance, ret = remove_hist(instance, synth->start_event, hist); free(hist); - synthetic_event = create_synthetic_event(synth); - if (!synthetic_event) - return -1; - - ret = remove_synthetic(synthetic_event); + ret = tracefs_dynevent_destroy(synth->dyn_event, true); return ret ? -1 : 0; } @@ -2067,7 +2049,7 @@ int tracefs_synth_show(struct trace_seq *seq, struct tracefs_instance *instance, struct tracefs_synth *synth) { - char *synthetic_event = NULL; + bool new_event = false; char *hist = NULL; char *path; int ret = -1; @@ -2082,16 +2064,19 @@ int tracefs_synth_show(struct trace_seq *seq, return -1; } - synthetic_event = create_synthetic_event(synth); - if (!synthetic_event) - return -1; + if (!synth->dyn_event) { + if (alloc_synthetic_event(synth)) + return -1; + new_event = true; + } path = trace_find_tracing_dir(); if (!path) goto out_free; - trace_seq_printf(seq, "echo '%s' > %s/synthetic_events\n", - synthetic_event, path); + trace_seq_printf(seq, "echo '%s%s %s' > %s/%s\n", + synth->dyn_event->prefix, synth->dyn_event->event, + synth->dyn_event->format, path, synth->dyn_event->trace_file); tracefs_put_tracing_file(path); path = tracefs_instance_get_dir(instance); @@ -2116,10 +2101,18 @@ int tracefs_synth_show(struct trace_seq *seq, hist, path, synth->end_event->system, synth->end_event->name); + if (new_event) { + tracefs_dynevent_free(synth->dyn_event); + synth->dyn_event = NULL; + } + ret = 0; out_free: - free(synthetic_event); free(hist); tracefs_put_tracing_file(path); + if (new_event) { + tracefs_dynevent_free(synth->dyn_event); + synth->dyn_event = NULL; + } return ret; } From patchwork Fri Nov 5 12:16:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 12604567 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6891CC433FE for ; Fri, 5 Nov 2021 12:16:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4C4656125F for ; Fri, 5 Nov 2021 12:16:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231812AbhKEMTS (ORCPT ); Fri, 5 Nov 2021 08:19:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53532 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231849AbhKEMTP (ORCPT ); Fri, 5 Nov 2021 08:19:15 -0400 Received: from mail-wr1-x436.google.com (mail-wr1-x436.google.com [IPv6:2a00:1450:4864:20::436]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EC967C061205 for ; Fri, 5 Nov 2021 05:16:35 -0700 (PDT) Received: by mail-wr1-x436.google.com with SMTP id r8so13371077wra.7 for ; Fri, 05 Nov 2021 05:16:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=f28Hri4UHVTUqfdUfWFtIVGUb3NTfrCa+wAJemj+UaU=; b=Vqd/IA492W79cHdMHKnRHYdiQi1sSEfNwgjMUKzO6Dy5fGEor2KHGqCw0p+2NTjlLN XIGUIBzmwDSUL8jez9VdBqWmfg1zXz7UZs7EBjRVygpT7zm1K52Yq5sjC3PDqkNpXkWn NIiLikN8/VboRpgauLl79w0P0761g+5dWGcYHuC6llydqZUquFUBoLH4dIw4mgE5qozB lvfD2GE5xn7XZcZolvOum0GjcRdY4K5PqDNeF2xxreuqIpx6dsL2zbK6PK58Q9nMdZK3 Yvgoi+Ft1vEHmZWRQ0+UXGtAH6xBe1w1TIANUq0jQLhBpGqV7JbZw8IgfXCbBjuz2xNo 0Hcw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=f28Hri4UHVTUqfdUfWFtIVGUb3NTfrCa+wAJemj+UaU=; b=ahU23C/My/UWNBWd8vCiBdpX7Z3tPUiGKAjDA1xsulEXk487n68+vgPjaEfOZ+RVjh DAxeOFFfLqyWtM7q4tHIDlFNynRJBa0ZNRP67T7jqp2hTiOekvbFlQ0DyE23TTJij1t0 G9fgPOp1Wgem6ZlaftUXYhWxRKihp/GE1fyue5LklCk4Zaf06m61J/lbU4yuWGJ6ZMRz yWCHzsr6K4/oKZF7X+a4Mjgtl1vPKFPyDGmQ0csK8KLjrvQYiI+YwJ2OEXfY+kEKXCo4 apNXkm+S+GfBfenH1xDW8APnl0VPmkKv9nWl9moMNLOk4Aj3tWIu24IXQwZIqBXo/PpS VmiA== X-Gm-Message-State: AOAM531MDpIRVavhDWsWrvpCSUh/JH051kF/+CbwJ8Wdnww6otpMdaNG QxqhurDNBHNiXhq1cAWdA/mVSetErdwg2w== X-Google-Smtp-Source: ABdhPJzGuR8tYUWfE1ptHGkNJnj/FyCUhCfWUj20r82knh4LLN/P1nCtxblAXa7LctSpitB++YJrwg== X-Received: by 2002:adf:f551:: with SMTP id j17mr71466957wrp.392.1636114594638; Fri, 05 Nov 2021 05:16:34 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id x13sm7936531wrr.47.2021.11.05.05.16.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 Nov 2021 05:16:34 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v5 08/12] libtracefs: Add unit test for synthetic events Date: Fri, 5 Nov 2021 14:16:20 +0200 Message-Id: <20211105121624.398717-9-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211105121624.398717-1-tz.stoyanov@gmail.com> References: <20211105121624.398717-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org All tracefs library APIs should be covered in the unit test. There is unit test section for the tracefs_sql* set of APIs, which use synthetic events internally, but no tests for the tracefs_synthetic* APIs. An initial unit test section is added for tracefs_synthetic* APIs. Not all APIs are covered, that section should be extended. Unit tests for basic tracefs_synthetic* APIs are added, to test the changes related to dynamic events code in the library, related to synthetic events. Signed-off-by: Tzvetomir Stoyanov (VMware) --- utest/tracefs-utest.c | 95 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/utest/tracefs-utest.c b/utest/tracefs-utest.c index 5b656d4..6287f31 100644 --- a/utest/tracefs-utest.c +++ b/utest/tracefs-utest.c @@ -403,6 +403,100 @@ static struct tracefs_dynevent **get_dynevents_check(enum tracefs_dynevent_type return devents; } + +struct test_synth { + char *name; + char *start_system; + char *start_event; + char *end_system; + char *end_event; + char *start_match_field; + char *end_match_field; + char *match_name; +}; + +static void test_synth_compare(struct test_synth *synth, struct tracefs_dynevent **devents) +{ + enum tracefs_dynevent_type stype; + char *format; + char *event; + int i; + + for (i = 0; devents && devents[i]; i++) { + stype = tracefs_dynevent_info(devents[i], NULL, + &event, NULL, NULL, &format); + CU_TEST(stype == TRACEFS_DYNEVENT_SYNTH); + CU_TEST(strcmp(event, synth[i].name) == 0); + if (synth[i].match_name) { + CU_TEST(strstr(format, synth[i].match_name) != NULL); + } + } + CU_TEST(devents[i] == NULL); +} + +static void test_instance_syntetic(struct tracefs_instance *instance) +{ + struct test_synth sevents[] = { + {"synth_1", "sched", "sched_waking", "sched", "sched_switch", "pid", "next_pid", "pid_match"}, + {"synth_2", "syscalls", "sys_enter_openat2", "syscalls", "sys_exit_openat2", "__syscall_nr", "__syscall_nr", "nr_match"}, + }; + int sevents_count = sizeof(sevents) / sizeof((sevents)[0]); + struct tracefs_dynevent **devents; + struct tracefs_synth **synth; + struct tep_handle *tep; + int ret; + int i; + + synth = calloc(sevents_count + 1, sizeof(*synth)); + + tep = tracefs_local_events(NULL); + CU_TEST(tep != NULL); + + /* kprobes APIs */ + ret = tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_SYNTH, true); + CU_TEST(ret == 0); + get_dynevents_check(TRACEFS_DYNEVENT_SYNTH, 0); + + for (i = 0; i < sevents_count; i++) { + synth[i] = tracefs_synth_alloc(tep, sevents[i].name, + sevents[i].start_system, sevents[i].start_event, + sevents[i].end_system, sevents[i].end_event, + sevents[i].start_match_field, sevents[i].end_match_field, + sevents[i].match_name); + CU_TEST(synth[i] != NULL); + } + + get_dynevents_check(TRACEFS_DYNEVENT_SYNTH, 0); + + for (i = 0; i < sevents_count; i++) { + ret = tracefs_synth_create(instance, synth[i]); + CU_TEST(ret == 0); + } + + devents = get_dynevents_check(TRACEFS_DYNEVENT_SYNTH, sevents_count); + CU_TEST(devents != NULL); + test_synth_compare(sevents, devents); + tracefs_dynevent_list_free(devents); + + for (i = 0; i < sevents_count; i++) { + ret = tracefs_synth_destroy(instance, synth[i]); + CU_TEST(ret == 0); + } + + get_dynevents_check(TRACEFS_DYNEVENT_SYNTH, 0); + + for (i = 0; i < sevents_count; i++) + tracefs_synth_free(synth[i]); + + tep_free(tep); + free(synth); +} + +static void test_synthetic(void) +{ + test_instance_syntetic(test_instance); +} + static void test_trace_file(void) { const char *tmp = get_rand_str(); @@ -1525,4 +1619,5 @@ void test_tracefs_lib(void) CU_add_test(suite, "ftrace marker", test_ftrace_marker); CU_add_test(suite, "kprobes", test_kprobes); + CU_add_test(suite, "syntetic events", test_synthetic); } From patchwork Fri Nov 5 12:16:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 12604569 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2E7AAC433F5 for ; Fri, 5 Nov 2021 12:16:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0E35E61212 for ; Fri, 5 Nov 2021 12:16:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231849AbhKEMTT (ORCPT ); Fri, 5 Nov 2021 08:19:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53538 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231701AbhKEMTR (ORCPT ); Fri, 5 Nov 2021 08:19:17 -0400 Received: from mail-wr1-x435.google.com (mail-wr1-x435.google.com [IPv6:2a00:1450:4864:20::435]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0FB2FC061208 for ; Fri, 5 Nov 2021 05:16:37 -0700 (PDT) Received: by mail-wr1-x435.google.com with SMTP id d24so13446138wra.0 for ; Fri, 05 Nov 2021 05:16:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=XJvnvRjQV5WIu4vp2/wBSqNpB3fDsNCwh2Y+3NXJ7Ao=; b=a9Jh85cAHTb0DIfuIbqK5bi7K0Ft+CUzK60Fts7qKWjMH8C1CYsAuMUqsQpvFNHOEm h1zs8c7rEFSzB5VxKQtoxoBB42lI0KEdMtxr6lFdhpQwFjfSz3+0CB54tEIO6fhTPf4F kEeS+wbDa55I3ru53Mr/0NvTZqJpxwkhAjbCyHa/lHT4NfJcy+sXcAnc+3rbOcPAqB6p jyokrJW2+zGi9bns7DDqMpgwYQShoNox228uKkarjOrvHfsksU7uiGTk80MK2noczrRL iRKq+whIIjy1yqfKKvL7IqlSQMN4jV8xQWb6FsbDkZg6EVvyDsc3pEYT8vYA5KUMQ/PQ /WGg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=XJvnvRjQV5WIu4vp2/wBSqNpB3fDsNCwh2Y+3NXJ7Ao=; b=yS09HGh2iEy3lH5w6y566fx8GwRxVWRCfQPmMV0CaN6XCzqEYF1xwwD+up3r/IXrMj Lm9kjK440zFAwLLQugs3IFfGctrOxR24XyrPGpygIRPeUsu45zfsg/20+60GlcJKRyol F0SpCHAzpmYxfugLSASt1U9Bw9VI64MmeuwlT+SXaD+DivtvBkUAWjTrxwRk5P8RBsta VbUX7oerfdkChhS6uRoFZYPz9yqnKZ25i6iPHwlkbhZ9oh/ralxnKKBk6qAFi+X1YAvx 92ZoUWJJrJ9Jx7ec3Spy414mkSNp63hMA94grISOicdLY+2cy21LsUXPlQ8qPDhCehaD 80qg== X-Gm-Message-State: AOAM532GHXjsZwrGW8kzXKSfFwsQY65KLHBZbVL2I+U8eIegxycogViX zIcABKzgy68PsGvdkQhWiDg= X-Google-Smtp-Source: ABdhPJyhm+Igyha5Y0PvW5mMJH9rjDgYQdugHaVbhmTTccqtDCs+HspzPDa/uAZzTbHylAZaKps66Q== X-Received: by 2002:adf:e682:: with SMTP id r2mr41732597wrm.281.1636114595545; Fri, 05 Nov 2021 05:16:35 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id x13sm7936531wrr.47.2021.11.05.05.16.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 Nov 2021 05:16:35 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v5 09/12] libtracefs: Update kprobes man pages Date: Fri, 5 Nov 2021 14:16:21 +0200 Message-Id: <20211105121624.398717-10-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211105121624.398717-1-tz.stoyanov@gmail.com> References: <20211105121624.398717-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org As there are a lot of changes in the libtracefs kprobes APIs, the documentation of the library should be updated. Signed-off-by: Tzvetomir Stoyanov (VMware) --- Documentation/libtracefs-kprobes.txt | 94 +++++++++++----------------- Documentation/libtracefs.txt | 6 ++ 2 files changed, 41 insertions(+), 59 deletions(-) diff --git a/Documentation/libtracefs-kprobes.txt b/Documentation/libtracefs-kprobes.txt index c10576e..4a4bf01 100644 --- a/Documentation/libtracefs-kprobes.txt +++ b/Documentation/libtracefs-kprobes.txt @@ -3,7 +3,8 @@ libtracefs(3) NAME ---- -tracefs_kprobe_raw, tracefs_kretprobe_raw, tracefs_get_kprobes, tracefs_kprobe_info, tracefs_kprobe_clear_all, tracefs_kprobe_clear_probe - Create, list, and destroy kprobes +tracefs_kprobe_alloc, tracefs_kretprobe_alloc, tracefs_kprobe_raw, tracefs_kretprobe_raw - +Allocate, get, and create kprobes SYNOPSIS -------- @@ -11,18 +12,30 @@ SYNOPSIS -- *#include * -int tracefs_kprobe_raw(const char pass:[*]system, const char pass:[*]event, const char pass:[*]addr, const char pass:[*]format); -int tracefs_kretprobe_raw(const char pass:[*]system, const char pass:[*]event, const char pass:[*]addr, const char pass:[*]format); -char pass:[*]pass:[*]tracefs_get_kprobes(enum tracefs_kprobe_type type); -enum tracefs_kprobe_type tracefs_kprobe_info(const char pass:[*]group, const char pass:[*]event, - char pass:[*]pass:[*]type, char pass:[*]pass:[*]addr, char pass:[*]pass:[*]format); -enum tracefs_kprobe_type tracefs_kprobe_type(const char pass:[*]group, const char pass:[*]event) -int tracefs_kprobe_clear_all(bool force); -int tracefs_kprobe_clear_probe(const char pass:[*]system, const char pass:[*]event, bool force); +struct tracefs_dynevent pass:[*] +*tracefs_kprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_, + const char pass:[*]_addr_, const char pass:[*]_format_); +struct tracefs_dynevent pass:[*] +*tracefs_kretprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_, + const char pass:[*]_addr_, const char pass:[*]_format_, unsigned int _max_); +int *tracefs_kprobe_raw*(const char pass:[*]_system_, const char pass:[*]_event_, + const char pass:[*]_addr_, const char pass:[*]_format_); +int *tracefs_kretprobe_raw*(const char pass:[*]_system_, const char pass:[*]_event_, + const char pass:[*]_addr_, const char pass:[*]_format_); -- DESCRIPTION ----------- +*tracefs_kprobe_alloc*() allocates a new kprobe context. The kbrobe is not configured in the system. +The new kprobe will be in the _system_ group (or kprobes if _system_ is NULL) and have the name of +_event_ (or _addr_ if _event_ is NULL). The kprobe will be inserted to _addr_ (function name, with +or without offset, or a address), and the _format_ will define the format of the kprobe. See the +Linux documentation file under: Documentation/trace/kprobetrace.rst + +*tracefs_kretprobe_alloc*() is the same as *tracefs_kprobe_alloc*, but allocates context for +kretprobe. It has one additional parameter, which is optional, _max_ - maxactive count. +See description of kretprobes in the Documentation/trace/kprobetrace.rst file. + *tracefs_kprobe_raw*() will create a kprobe event. If _system_ is NULL, then the default "kprobes" is used for the group (event system). Otherwise if _system_ is specified then the kprobe will be created under the group by that name. The @@ -36,55 +49,17 @@ document. creates a kretprobe instead of a kprobe. The difference is also described in the Linux kernel source in the Documentation/trace/kprobetrace.rst file. -*tracefs_get_kprobes*() returns an array of strings (char pass:[*]) that contain -the registered kprobes and kretprobes depending on the given _type_. If _type_ is -TRACEFS_ALL_KPROBES, then all kprobes found are returned. If _type_ is -TRACEFS_KPROBE, then only normal kprobes are returned. If _type_ is -TRACEFS_KRETPROBE, then only kretprobes are returned. -The names are in the "system/event" format. -That is, one string holds both the kprobe's name as well as the group it is -defined under. These strings are allocated and may be modified with the -*strtok*(3) and *strtok_r*(3) functions. The string returned must be freed with -*tracefs_list_free*(3). - -*tracefs_kprobe_info*() returns the type of the given kprobe. If _group_ is -NULL, then the default "kprobes" is used. If _type_ is non NULL, then it will -hold an allocated string that holds the type portion of the kprobe in the -kprobe_events file (the content before the ":"). If _addr_ is non NULL, it will -hold the address or function that the kprobe is attached to. If _format_ is non -NULL, it will hold the format string of the kprobe. Note, that the content in -_type_, _addr_, and _format_ must be freed with free(3) if they are set. Even -in the case of an error, as they may hold information of what caused the error. - -*tracefs_kprobe_clear_all*() will try to remove all kprobes that have been -registered. If the @force flag is set, it will then disable those kprobe events -if they are enabled and then try to clear the kprobes. - -*tracefs_kprobe_clear_probe*() will try to clear specified kprobes. If _system_ -is NULL, then it will only clear the default kprobes under the "kprobes" group. -If _event_ is NULL, it will clear all kprobes under the given _system_. If the -_force_ flag is set, then it will disable the given kprobe events before clearing -them. - RETURN VALUE ------------ -*tracefs_kprobe_raw*(), *tracefs_kretprobe_raw*(), *tracefs_kprobe_clear_all*(), -and *tracefs_kprobe_clear_probe*() return 0 on success, or -1 on error. - -If a parsing error occurs on *tracefs_kprobe_raw*() or *tracefs_kretprobe_raw*() -then *tracefs_error_last*(3) may be used to retrieve the error message explaining -the parsing issue. - -*tracefs_get_kprobes*() returns an allocate string list of allocated strings -on success that must be freed with *tracefs_list_free*(3) and returns -NULL on error. +*tracefs_kprobe_raw*() and *tracefs_kretprobe_raw*() return 0 on success, or -1 on error. +If a parsing error occurs on *tracefs_kprobe_raw*() or *tracefs_kretprobe_raw*() then +*tracefs_error_last*(3) may be used to retrieve the error message explaining the parsing issue. -*tracefs_kprobe_info*() returns the type of the given kprobe. It returns -TRACEFS_KPROBE for normal kprobes, TRACEFS_KRETPROBE for kretprobes, and -on error, or if the kprobe is not found TRACEFS_ALL_KPROBES is returned. -If _type_, _addr_, or _format_ are non NULL, they will contain allocated -strings that must be freed by free(3) even in the case of error. +The *tracefs_kprobe_alloc*() and *tracefs_kretprobe_alloc*() APIs return a pointer to an allocated +tracefs_dynevent structure, describing the probe. This pointer must be freed by +*tracefs_dynevent_free*(3). Note, this only allocates a descriptor representing the kprobe. It does +not modify the running system. ERRORS ------ @@ -96,9 +71,10 @@ The following errors are for all the above calls: *ENOMEM* Memory allocation error. -*tracefs_kprobe_raw*(), *tracefs_kretprobe_raw*() can fail with the following errors: +*tracefs_kprobe_raw*(), *tracefs_kretprobe_raw*(), *tracefs_kprobe_alloc*(), +and *tracefs_kretprobe_alloc*() can fail with the following errors: -*EBADMSG* Either _addr_ or _format_ are NULL. +*EBADMSG* if _addr_ is NULL. *EINVAL* Most likely a parsing error occurred (use *tracefs_error_last*(3) to possibly see what that error was). @@ -217,7 +193,7 @@ int main (int argc, char **argv, char **env) exit(-1); } - tracefs_kprobe_clear_probe(mykprobe, NULL, true); + tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, true); kprobe_create("open", "do_sys_openat2", "file=+0($arg2):ustring flags=+0($arg3):x64 mode=+8($arg3):x64\n"); @@ -247,7 +223,7 @@ int main (int argc, char **argv, char **env) } while (waitpid(pid, NULL, WNOHANG) != pid); /* Will disable the events */ - tracefs_kprobe_clear_probe(mykprobe, NULL, true); + tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, true); tracefs_instance_destroy(instance); tep_free(tep); @@ -293,5 +269,5 @@ https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ COPYING ------- -Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under +Copyright \(C) 2021 VMware, Inc. Free use of this software is granted under the terms of the GNU Public License (GPL). diff --git a/Documentation/libtracefs.txt b/Documentation/libtracefs.txt index 2c9eabd..430d02e 100644 --- a/Documentation/libtracefs.txt +++ b/Documentation/libtracefs.txt @@ -63,6 +63,12 @@ Writing data in the trace buffer: Control library logs: int *tracefs_set_loglevel*(enum tep_loglevel _level_); + +Kprobes and Kretprobes: + struct tracefs_dynevent pass:[*] *tracefs_kprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_, const char pass:[*]_addr_, const char pass:[*]_format_); + struct tracefs_dynevent pass:[*] *tracefs_kretprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_, const char pass:[*]_addr_, const char pass:[*]_format_, unsigned int _max_); + int *tracefs_kprobe_raw*(const char pass:[*]_system_, const char pass:[*]_event_, const char pass:[*]_addr_, const char pass:[*]_format_); + int *tracefs_kretprobe_raw*(const char pass:[*]_system_, const char pass:[*]_event_, const char pass:[*]_addr_, const char pass:[*]_format_); -- DESCRIPTION From patchwork Fri Nov 5 12:16:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 12604571 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C1775C433EF for ; Fri, 5 Nov 2021 12:16:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id ABEA46125F for ; Fri, 5 Nov 2021 12:16:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232957AbhKEMTU (ORCPT ); Fri, 5 Nov 2021 08:19:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53542 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231902AbhKEMTR (ORCPT ); Fri, 5 Nov 2021 08:19:17 -0400 Received: from mail-wr1-x431.google.com (mail-wr1-x431.google.com [IPv6:2a00:1450:4864:20::431]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EB86AC06120A for ; Fri, 5 Nov 2021 05:16:37 -0700 (PDT) Received: by mail-wr1-x431.google.com with SMTP id c4so13389275wrd.9 for ; Fri, 05 Nov 2021 05:16:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=kzOoaeTM2XBUhcvrVBAaoEO/b3p1TXSaKxPwgiFVNaM=; b=X02KE2kZ/DUurNk0KlOq2hPPpf6u9qDJWg8q5GERetxtznqvQG+bcSYny4dxIj8kVx 35dN/2EYh4JirrO4QgT3Ft75ANxDmm74oGqUfoE57ryAaBdG3nufpomGwHv+F6bcl+q9 hq/awh60yD2LnsosBesbfzhQCrh1GlePsXvMpVfwniFZW0WPvC+Y2YedEZv396+blOy7 2rjF4mMDBFsC+UkG3PGuGK1AyeaQyRnVeP3ZSsiajTvqY5Mm0SizEmROAxFoB6s9wq88 7uEUTeEy/HsaZMbOZzVyc2Bl5dVH3THqZjN3YPyAEi9i5JPro4Tx6zat8r6V6Tww0C3h qBUw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=kzOoaeTM2XBUhcvrVBAaoEO/b3p1TXSaKxPwgiFVNaM=; b=0jxVX3Lq8ev1idBQklqxp1tUM9H53xO+0sZzhMs/FrceT8K5p8e8TK27x051b7mDOz ZgLsfQCl8zaAKX3V6Hyf72ecn62Asdzhwx/5jo0T0lRtH5frXXHd4M38QohluQulK0v3 sPcRrNh9/HROb4EwaVVRymBCk+wtLi/l/MJfj9PyRQXeQ1YdZ7+Wx0ijBSD7nXlISXt2 AmJGptXtU2zfr088WUYhcbpVlmsXHyJVmbv3CrntyhROy+RfDpZVEJsTvFwhH3Y27AS0 mcAtYaOYo+aFhIuYqtIfnGxVgu44Yg3Ersb//bdulvGuw5sTaALdhv71LSOPNUuUZ2L7 wwNw== X-Gm-Message-State: AOAM533Gp7V7G0XbFJn2DHtsb77wxcGW5gEXcSv13FC3o2BdW1XPUNAT 6I1t8DvThT27VWsojD6bytbpJ5DDRx1TgQ== X-Google-Smtp-Source: ABdhPJw9AsNgzCaFmO2ycjfh5ROBABFG7QhWHhMJVDNMxEEs2z5QonZ8J55oDFaTk55Of2gQxr1W6A== X-Received: by 2002:adf:ec90:: with SMTP id z16mr47022238wrn.247.1636114596459; Fri, 05 Nov 2021 05:16:36 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id x13sm7936531wrr.47.2021.11.05.05.16.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 Nov 2021 05:16:36 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v5 10/12] libtracefs: Document dynamic events APIs Date: Fri, 5 Nov 2021 14:16:22 +0200 Message-Id: <20211105121624.398717-11-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211105121624.398717-1-tz.stoyanov@gmail.com> References: <20211105121624.398717-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org As a new set of APIs for ftrace dynamic events were added recently, they must be documented. A new man page is added, describing these APIs: tracefs_dynevent_create(); tracefs_dynevent_destroy(); tracefs_dynevent_destroy_all(); tracefs_dynevent_free(); tracefs_dynevent_list_free(); tracefs_dynevent_get_all(); tracefs_dynevent_info(); Signed-off-by: Tzvetomir Stoyanov (VMware) --- Documentation/libtracefs-dynevents.txt | 266 +++++++++++++++++++++++++ Documentation/libtracefs.txt | 11 + 2 files changed, 277 insertions(+) create mode 100644 Documentation/libtracefs-dynevents.txt diff --git a/Documentation/libtracefs-dynevents.txt b/Documentation/libtracefs-dynevents.txt new file mode 100644 index 0000000..95032ef --- /dev/null +++ b/Documentation/libtracefs-dynevents.txt @@ -0,0 +1,266 @@ +libtracefs(3) +============= + +NAME +---- +tracefs_dynevent_create, tracefs_dynevent_destroy, tracefs_dynevent_destroy_all, +tracefs_dynevent_free, tracefs_dynevent_list_free, tracefs_dynevent_get_all, tracefs_dynevent_info - +Create, destroy, free and get dynamic events. + +SYNOPSIS +-------- +[verse] +-- +*#include * + +struct *tracefs_dynevent*; +enum *tracefs_dynevent_type*; +int *tracefs_dynevent_create*(struct tracefs_dynevent pass:[*]_devent_); +int *tracefs_dynevent_destroy*(struct tracefs_dynevent pass:[*]_devent_, bool _force_); +int *tracefs_dynevent_destroy_all*(unsigned int _types_, bool _force_); +void *tracefs_dynevent_free*(struct tracefs_dynevent pass:[*]_devent_); +void *tracefs_dynevent_list_free*(struct tracefs_dynevent pass:[*]pass:[*]_events_); +struct tracefs_dynevent pass:[*]pass:[*]*tracefs_dynevent_get_all*(unsigned int _types_, const char pass:[*]_system_); +enum tracefs_dynevent_type *tracefs_dynevent_info*(struct tracefs_dynevent pass:[*]_dynevent_, char pass:[*]pass:[*]_system_, char pass:[*]pass:[*]_event_, char pass:[*]pass:[*]_prefix_, char pass:[*]pass:[*]_addr_, char pass:[*]pass:[*]_format_); +-- + +DESCRIPTION +----------- + +The *tracefs_dynevent_create*() function creates dynamic event _devent_ in the system. + +The *tracefs_dynevent_destroy*() function removes dynamic event _devent_ from the system. If _force_ +is true, the function will attempt to disable all events in all trace instances, before removing +the dynamic event. The _devent_ context is not freed, use *tracefs_dynevent_free*() to free it. + +The *tracefs_dynevent_destroy_all*() function removes all dynamic events of given types from the +system. The _types_ parameter is a type of specific dynamic event, or a bitmask of dynamic events +types *tracefs_dynevent_type*, that will be removed. If _types_ is 0, dynamic events from all types +will be removed. If _force_ is true, the function will attempt to disable all events in all trace +instances, before removing the dynamic events. + +The *tracefs_dynevent_get_all*() function allocates and returns an array of pointers to dynamic +events of given types that exist in the system. The last element of the array is a NULL pointer. +The array must be freed with *tracefs_dynevent_list_free*(). If there are no events a NULL pointer is +returned. The _types_ parameter is a type of specific dynamic event, or a bitmask of dynamic events +types *tracefs_dynevent_type*, that will be retrieved. If _types_ is 0, dynamic events from all +types will be retrieved. + +The *tracefs_dynevent_free*() function frees a dynamic event context _devent_. + +The *tracefs_dynevent_list_free*() function frees an array of pointers to dynamic event, returned +by *tracefs_dynevent_get_all()* API. + +The *tracefs_dynevent_info*() function returns the type and information of a given dynamic event +_dynevent_. If any of the _system_, _event_, _prefix_, _addr_ or _format_ arguments are not NULL, +then strings are allocated and returned back via these arguments. The _system_ and _event_ holds the +system and the name of the dynamic event. If _prefix_ is non NULL, then it will hold an allocated +string that holds the prefix portion of the dynamic event (the content up to the ":", exluding it). +If _addr_ is non NULL, it will hold the address or function that the dynamic event is attached to, +if relevant for this event type. If _format_ is non NULL, it will hold the format string of the +dynamic event. Note, that the content in _group_, _event_, _prefix_, _addr_, and _format_ must be +freed with free(3) if they are set. + +RETURN VALUE +------------ + +*tracefs_dynevent_create*() returns 0 on success, or -1 on error. If a parsing error occurs then +*tracefs_error_last*(3) may be used to retrieve the error message explaining the parsing issue. + +*tracefs_dynevent_destroy*() and *tracefs_dynevent_destroy_all*() return 0 on success, or -1 on +error. If _force_ is enabled, the functions may fail on disabling the events. + +*tracefs_dynevent_get_all*() function returns allocated array of pointers to dynamic events, or NULL +in case of an error or in case there are no events in the system. That array must be freed by +*tracefs_dynevent_list_free*(). + +*tracefs_dynevent_info*() returns the type of the given dynamic event or TRACEFS_DYNEVENT_UNKNOWN +on error. If _system_, _event_, _prefix_, _addr_, or _format_ are non NULL, they will contain +allocated strings that must be freed by free(3). + +ERRORS +------ +The following errors are for all the above calls: + +*EPERM* Not run as root user + +*ENODEV* dynamic events of requested type are not configured for the running kernel. + +*ENOMEM* Memory allocation error. + +*tracefs_dynevent_create*() can fail with the following errors: + +*EINVAL* Most likely a parsing error occurred (use *tracefs_error_last*(3) to possibly + see what that error was). + +Other errors may also happen caused by internal system calls. + +EXAMPLE +------- +[source,c] +-- +#include +#include +#include + +#include + +static struct tep_event *open_event; +static struct tep_format_field *file_field; + +static struct tep_event *openret_event; +static struct tep_format_field *ret_field; + +static int callback(struct tep_event *event, struct tep_record *record, + int cpu, void *data) +{ + struct trace_seq seq; + + trace_seq_init(&seq); + tep_print_event(event->tep, &seq, record, "%d-%s: ", TEP_PRINT_PID, TEP_PRINT_COMM); + + if (event->id == open_event->id) { + trace_seq_puts(&seq, "open file='"); + tep_print_field(&seq, record->data, file_field); + trace_seq_puts(&seq, "'\n"); + } else if (event->id == openret_event->id) { + unsigned long long ret; + tep_read_number_field(ret_field, record->data, &ret); + trace_seq_printf(&seq, "open ret=%lld\n", ret); + } else { + goto out; + } + + trace_seq_terminate(&seq); + trace_seq_do_printf(&seq); +out: + trace_seq_destroy(&seq); + + return 0; +} + +static pid_t run_exec(char **argv, char **env) +{ + pid_t pid; + + pid = fork(); + if (pid) + return pid; + + execve(argv[0], argv, env); + perror("exec"); + exit(-1); +} + +const char *mykprobe = "my_kprobes"; + +int main (int argc, char **argv, char **env) +{ + struct tracefs_dynevent *kprobe, *kretprobe; + const char *sysnames[] = { mykprobe, NULL }; + struct tracefs_instance *instance; + struct tep_handle *tep; + pid_t pid; + + if (argc < 2) { + printf("usage: %s command\n", argv[0]); + exit(-1); + } + + instance = tracefs_instance_create("exec_open"); + if (!instance) { + perror("creating instance"); + exit(-1); + } + + tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, true); + + kprobe = tracefs_kprobe_alloc(mykprobe, "open", "do_sys_openat2", + "file=+0($arg2):ustring flags=+0($arg3):x64 mode=+8($arg3):x64\n"); + kretprobe = tracefs_kretprobe_alloc(mykprobe, "openret", "do_sys_openat2", "ret=%ax", 0); + if (!kprobe || !kretprobe) { + perror("allocating dynamic events"); + exit(-1); + } + + if (tracefs_dynevent_create(kprobe) || tracefs_dynevent_create(kretprobe)){ + err = tracefs_error_last(NULL); + perror("Failed to create kprobes:"); + if (err && strlen(err)) + fprintf(stderr, "%s\n", err); + exit(-1); + } + + tep = tracefs_local_events_system(NULL, sysnames); + if (!tep) { + perror("reading events"); + exit(-1); + } + open_event = tep_find_event_by_name(tep, mykprobe, "open"); + file_field = tep_find_field(open_event, "file"); + + openret_event = tep_find_event_by_name(tep, mykprobe, "openret"); + ret_field = tep_find_field(openret_event, "ret"); + + tracefs_event_enable(instance, mykprobe, NULL); + pid = run_exec(&argv[1], env); + + /* Let the child start to run */ + sched_yield(); + + do { + tracefs_load_cmdlines(NULL, tep); + tracefs_iterate_raw_events(tep, instance, NULL, 0, callback, NULL); + } while (waitpid(pid, NULL, WNOHANG) != pid); + + /* Will disable the events */ + tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, true); + tracefs_dynevent_free(kprobe); + tracefs_dynevent_free(kretprobe); + tracefs_instance_destroy(instance); + tep_free(tep); + + return 0; +} +-- + +FILES +----- +[verse] +-- +*tracefs.h* + Header file to include in order to have access to the library APIs. +*-ltracefs* + Linker switch to add when building a program that uses the library. +-- + +SEE ALSO +-------- +_libtracefs(3)_, +_libtraceevent(3)_, +_trace-cmd(1)_ + +AUTHOR +------ +[verse] +-- +*Steven Rostedt* +*Tzvetomir Stoyanov* +*Yordan Karadzhov* +-- +REPORTING BUGS +-------------- +Report bugs to + +LICENSE +------- +libtracefs is Free Software licensed under the GNU LGPL 2.1 + +RESOURCES +--------- +https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ + +COPYING +------- +Copyright \(C) 2021 VMware, Inc. Free use of this software is granted under +the terms of the GNU Public License (GPL). diff --git a/Documentation/libtracefs.txt b/Documentation/libtracefs.txt index 430d02e..6850860 100644 --- a/Documentation/libtracefs.txt +++ b/Documentation/libtracefs.txt @@ -64,6 +64,17 @@ Writing data in the trace buffer: Control library logs: int *tracefs_set_loglevel*(enum tep_loglevel _level_); +Dynamic event generic APIs: + struct *tracefs_dynevent*; + enum *tracefs_dynevent_type*; + int *tracefs_dynevent_create*(struct tracefs_dynevent pass:[*]_devent_); + int *tracefs_dynevent_destroy*(struct tracefs_dynevent pass:[*]_devent_, bool _force_); + int *tracefs_dynevent_destroy_all*(unsigned int _types_, bool _force_); + void *tracefs_dynevent_free*(struct tracefs_dynevent pass:[*]_devent_); + void *tracefs_dynevent_list_free*(struct tracefs_dynevent pass:[*]pass:[*]_events_); + struct tracefs_dynevent pass:[*]pass:[*]*tracefs_dynevent_get_all*(unsigned int _types_, const char pass:[*]_system_); + enum tracefs_dynevent_type *tracefs_dynevent_info*(struct tracefs_dynevent pass:[*]_dynevent_, char pass:[*]pass:[*]_system_, char pass:[*]pass:[*]_event_, char pass:[*]pass:[*]_prefix_, char pass:[*]pass:[*]_addr_, char pass:[*]pass:[*]_format_); + Kprobes and Kretprobes: struct tracefs_dynevent pass:[*] *tracefs_kprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_, const char pass:[*]_addr_, const char pass:[*]_format_); struct tracefs_dynevent pass:[*] *tracefs_kretprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_, const char pass:[*]_addr_, const char pass:[*]_format_, unsigned int _max_); From patchwork Fri Nov 5 12:16:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 12604575 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 28F38C433FE for ; Fri, 5 Nov 2021 12:16:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0BE4761252 for ; Fri, 5 Nov 2021 12:16:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231701AbhKEMTV (ORCPT ); Fri, 5 Nov 2021 08:19:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53550 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232948AbhKEMTS (ORCPT ); Fri, 5 Nov 2021 08:19:18 -0400 Received: from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com [IPv6:2a00:1450:4864:20::42c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F327EC061714 for ; Fri, 5 Nov 2021 05:16:38 -0700 (PDT) Received: by mail-wr1-x42c.google.com with SMTP id r8so13371279wra.7 for ; Fri, 05 Nov 2021 05:16:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=u184kF8FzUm0e36PjitDawJ4HoMuTvjibLjz+5jai2A=; b=UfrxWy2JJQALqZ7qVMk6OSP9L1fY/gs/1MNnXEdqyOIz59sdMhFCII4e3s3eppk40q q5cvnY4t6VrlVbI8G/QCNejgmoCWEgfRf3PYJiyPtsqYPPsIby5s7diBLZDKqX4RA+3D PUWNJ2E/qAJiGN3o0Q4rqEUAKG9/QW4Yk3pgpg0uHJeH1HdjPphigbIYwdjjdgr7qk3+ SCR2cj/SvLOCj92EhE7JLeERyavnt6dkeeJBjNCbBHJ+jawf3zBToRJyt17lTVllSnpF eCQ26A3rBAEyeCFwznWkfc1ADjHC4lSJx4vssy44lXcOjP4uwbDn/ihiEZvDeFsz8+7z ghrQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=u184kF8FzUm0e36PjitDawJ4HoMuTvjibLjz+5jai2A=; b=XL0iwFH76fkc81PT25dbIrAlwVR8nbAObhwuHr3tlBfzRdfDiPannrX1Ezk226FmAa noozBbeS1bn78euLx2lcaJMSlWtoQ+7yJCMvluPy3/w0kRmwCB0R1367431buhHZ7bB9 bKEfNJat/UqjrzkDcwqG1vG3vdkumuHckggqt7s6xbfi5fjybTAmKWrjm24f0An6I34/ 0fnZwLks4OsNlnSbM4nIx1lesw27m/IRxX0D5BlZeeDE38Am/pbmmyrBIvIyR/yEW2Uc UrzjJlNmBxhHs+p0FUnhDLilWiEeTNuxps2nXrhw3JUSqS+fE2PGi/k2AKUoBNBtJjCH PRWQ== X-Gm-Message-State: AOAM5328p5FmV6jmGONLSE2W3+dyuFcMXgtjiArmkgbrmXuSiR2WDqfx g/nuUh4HiJfWaiOIYzPgjAB6Ry89Y7DHpg== X-Google-Smtp-Source: ABdhPJzFiUNw9Fvqs6UTFwgCu7gmUeuJ13mwvfsmS8iuK58CX0WCuOGBZiNpg7zpBVemadWKvKF0OQ== X-Received: by 2002:a5d:58f9:: with SMTP id f25mr67845178wrd.206.1636114597454; Fri, 05 Nov 2021 05:16:37 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id x13sm7936531wrr.47.2021.11.05.05.16.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 Nov 2021 05:16:36 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v5 11/12] libtracefs: Remove man page compile artifact Date: Fri, 5 Nov 2021 14:16:23 +0200 Message-Id: <20211105121624.398717-12-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211105121624.398717-1-tz.stoyanov@gmail.com> References: <20211105121624.398717-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The libtracefs-sqlhist.txt.1 file is generated during the tracefs library man pages compilation, it should not be part of the sources. Signed-off-by: Tzvetomir Stoyanov (VMware) --- Documentation/libtracefs-sqlhist.txt.1 | 351 ------------------------- 1 file changed, 351 deletions(-) delete mode 100644 Documentation/libtracefs-sqlhist.txt.1 diff --git a/Documentation/libtracefs-sqlhist.txt.1 b/Documentation/libtracefs-sqlhist.txt.1 deleted file mode 100644 index 1e94ea4..0000000 --- a/Documentation/libtracefs-sqlhist.txt.1 +++ /dev/null @@ -1,351 +0,0 @@ -SQLHIST(1) -========== - -NAME ----- -sqlhist - Tool that uses SQL language to create / show creation of tracefs histograms and synthetic events. - -SYNOPSIS --------- -*sqlhist* ['OPTIONS'] ['SQL-select-command'] - -DESCRIPTION ------------ -The sqlhist(1) will take an SQL like statement to create tracefs histograms and -synthetic events that can perform various actions for various handling of the -data. - -The tracefs file system interfaces with the Linux tracing infrastructure that -has various dynamic and static events through out the kernel. Each of these -events can have a "histogram" attached to it, where the fields of the event -will define the buckets of the histogram. - -A synthetic event is a way to attach two separate events and use the fields -and time stamps of those events to create a new dynamic event. This new -dynamic event is call a synthetic event. The fields of each event can have -simple calculations done on them where, for example, the delta between -a field of one event to a field of the other event can be taken. This also -works for the time stamps of the events where the time delta between the -two events can also be extracted and placed into the synthetic event. - -Other actions can be done from the fields of the events. A snapshot can -be taken of the kernel ring buffer a variable used in the synthetic -event creating hits a max, or simply changes. - -The commands to create histograms and synthetic events are complex and -not easy to remember. *sqlhist* is used to convert SQL syntax into the -commands needed to create the histogram or synthetic event. - -The *SQL-select-command* is a SQL string defined by *tracefs_sql*(3). - -Note, this must be run as root (or sudo) as interacting with the tracefs -directory requires root privilege, unless the *-t* option is given with -a copy of the _tracefs_ directory and its events. - -The *sqlhist* is a simple program where its code actual exists in the -*tracefs_sql*(3) man page. - -OPTIONS -------- -*-n* 'name':: - The name of the synthetic event to create. This event can then be - used like any other event, and enabled via *trace-cmd*(1). - -*-t* 'tracefs-dir':: - In order to test this out as non root user, a copy of the tracefs directory - can be used, and passing that directory with this option will allow - the program to work. Obviously, *-e* will not work as non-root because - it will not be able to execute. - - # mkdir /tmp/tracing - # cp -r /sys/kernel/tracing/events /tmp/tracing - # exit - $ ./sqlhist -t /tmp/tracing ... - -*-e*:: - Not only display the commands to create the histogram, but also execute them. - This requires root privilege. - -*-f* 'file':: - Instead of reading the SQL commands from the command line, read them from - _file_. If _file_ is '-' then read from standard input. - -*-m* 'var':: - Do the given action when the variable _var_ hits a new maximum. This can - not be used with *-c*. - -*-c* 'var':: - Do the given action when the variable _var_ changes its value. This can - not be used with *-m*. - -*-s*:: - Perform a snapshot instead of calling the synthetic event. - -*-T*:: - Perform both a snapshot and trace the synthetic event. - -*-S* 'fields[,fields]':: - Save the given fields. The fields must be fields of the "end" event given - in the *SQL-select-command* - - -EXAMPLES --------- - -Create the sqlhist executable: - -[source, c] --- - man tracefs_sql | sed -ne '/^EXAMPLE/,/FILES/ { /EXAMPLE/d ; /FILES/d ; p}' > sqlhist.c - gcc -o sqlhist sqlhist.c `pkg-config --cflags --libs libtracefs` --- - -As described above, for testing purposes, make a copy of the event directory: -[source, c] --- - $ mkdir /tmp/tracing - $ sudo cp -r /sys/kernel/tracing/events /tmp/tracing/ - $ sudo chmod -R 0644 /tmp/tracing/ --- - -For an example of simple histogram output using the copy of the tracefs directory. -[source, c] --- - $ ./sqlhist -t /tmp/tracing/ 'SELECT CAST(call_site as SYM-OFFSET), bytes_req, CAST(bytes_alloc AS _COUNTER_) FROM kmalloc' --- - -Produces the output: -[source, c] --- - echo 'hist:keys=call_site.sym-offset,bytes_req:vals=bytes_alloc' > /sys/kernel/tracing/events/kmem/kmalloc/trigger --- - -Which could be used by root: -[source, c] --- - # echo 'hist:keys=call_site.sym-offset,bytes_req:vals=bytes_alloc' > /sys/kernel/tracing/events/kmem/kmalloc/trigger - # cat /sys/kernel/tracing/events/kmem/kmalloc/hist -# event histogram -# -# trigger info: hist:keys=call_site.sym-offset,bytes_req:vals=hitcount,bytes_alloc:sort=hitcount:size=2048 [active] -# - -{ call_site: [ffffffff813f8d8a] load_elf_phdrs+0x4a/0xb0 , bytes_req: 728 } hitcount: 1 bytes_alloc: 1024 -{ call_site: [ffffffffc0c69e74] nf_ct_ext_add+0xd4/0x1d0 [nf_conntrack] , bytes_req: 128 } hitcount: 1 bytes_alloc: 128 -{ call_site: [ffffffff818355e6] dma_resv_get_fences+0xf6/0x440 , bytes_req: 8 } hitcount: 1 bytes_alloc: 8 -{ call_site: [ffffffffc06dc73f] intel_gt_get_buffer_pool+0x15f/0x290 [i915] , bytes_req: 424 } hitcount: 1 bytes_alloc: 512 -{ call_site: [ffffffff813f8d8a] load_elf_phdrs+0x4a/0xb0 , bytes_req: 616 } hitcount: 1 bytes_alloc: 1024 -{ call_site: [ffffffff8161a44c] __sg_alloc_table+0x11c/0x180 , bytes_req: 32 } hitcount: 1 bytes_alloc: 32 -{ call_site: [ffffffffc070749d] shmem_get_pages+0xad/0x5d0 [i915] , bytes_req: 16 } hitcount: 1 bytes_alloc: 16 -{ call_site: [ffffffffc07507f5] intel_framebuffer_create+0x25/0x60 [i915] , bytes_req: 408 } hitcount: 1 bytes_alloc: 512 -{ call_site: [ffffffffc06fc20f] eb_parse+0x34f/0x910 [i915] , bytes_req: 408 } hitcount: 1 bytes_alloc: 512 -{ call_site: [ffffffffc0700ebd] i915_gem_object_get_pages_internal+0x5d/0x270 [i915] , bytes_req: 16 } hitcount: 1 bytes_alloc: 16 -{ call_site: [ffffffffc0771188] intel_frontbuffer_get+0x38/0x220 [i915] , bytes_req: 400 } hitcount: 1 bytes_alloc: 512 -{ call_site: [ffffffff8161a44c] __sg_alloc_table+0x11c/0x180 , bytes_req: 128 } hitcount: 1 bytes_alloc: 128 -{ call_site: [ffffffff813f8f45] load_elf_binary+0x155/0x1680 , bytes_req: 28 } hitcount: 1 bytes_alloc: 32 -{ call_site: [ffffffffc07038c8] __assign_mmap_offset+0x208/0x3d0 [i915] , bytes_req: 288 } hitcount: 1 bytes_alloc: 512 -{ call_site: [ffffffff813737b2] alloc_bprm+0x32/0x2f0 , bytes_req: 416 } hitcount: 1 bytes_alloc: 512 -{ call_site: [ffffffff813f9027] load_elf_binary+0x237/0x1680 , bytes_req: 64 } hitcount: 1 bytes_alloc: 64 -{ call_site: [ffffffff8161a44c] __sg_alloc_table+0x11c/0x180 , bytes_req: 64 } hitcount: 1 bytes_alloc: 64 -{ call_site: [ffffffffc040ffe7] drm_vma_node_allow+0x27/0xe0 [drm] , bytes_req: 40 } hitcount: 2 bytes_alloc: 128 -{ call_site: [ffffffff813cda98] __do_sys_timerfd_create+0x58/0x1c0 , bytes_req: 336 } hitcount: 2 bytes_alloc: 1024 -{ call_site: [ffffffff818355e6] dma_resv_get_fences+0xf6/0x440 , bytes_req: 40 } hitcount: 2 bytes_alloc: 128 -{ call_site: [ffffffff8139b75a] single_open+0x2a/0xa0 , bytes_req: 32 } hitcount: 2 bytes_alloc: 64 -{ call_site: [ffffffff815df715] bio_kmalloc+0x25/0x80 , bytes_req: 136 } hitcount: 2 bytes_alloc: 384 -{ call_site: [ffffffffc071e5cd] i915_vma_work+0x1d/0x50 [i915] , bytes_req: 416 } hitcount: 3 bytes_alloc: 1536 -{ call_site: [ffffffff81390d0d] alloc_fdtable+0x4d/0x100 , bytes_req: 56 } hitcount: 3 bytes_alloc: 192 -{ call_site: [ffffffffc06ff65f] i915_gem_do_execbuffer+0x158f/0x2440 [i915] , bytes_req: 16 } hitcount: 4 bytes_alloc: 64 -{ call_site: [ffffffff8137713c] alloc_pipe_info+0x5c/0x230 , bytes_req: 384 } hitcount: 5 bytes_alloc: 2560 -{ call_site: [ffffffff813771b4] alloc_pipe_info+0xd4/0x230 , bytes_req: 640 } hitcount: 5 bytes_alloc: 5120 -{ call_site: [ffffffff81834cdb] dma_resv_list_alloc+0x1b/0x40 , bytes_req: 40 } hitcount: 6 bytes_alloc: 384 -{ call_site: [ffffffff81834cdb] dma_resv_list_alloc+0x1b/0x40 , bytes_req: 56 } hitcount: 9 bytes_alloc: 576 -{ call_site: [ffffffff8120086e] tracing_map_sort_entries+0x9e/0x3e0 , bytes_req: 24 } hitcount: 60 bytes_alloc: 1920 - -Totals: - Hits: 122 - Entries: 30 - Dropped: 0 --- - -Note, although the examples use uppercase for the SQL keywords, they do not have -to be. 'SELECT' could also be 'select' or even 'sElEcT'. - -By using the full SQL language, synthetic events can be made and processed. -For example, using *sqlhist* along with *trace-cmd*(1), wake up latency can -be recorded by creating a synthetic event by attaching the _sched_waking_ -and the _sched_switch_ events. - -[source, c] --- - # sqlhist -n wakeup_lat -e -T -m lat 'SELECT end.next_comm AS comm, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) AS lat FROM ' \ - 'sched_waking AS start JOIN sched_switch AS end ON start.pid = end.next_pid WHERE end.next_prio < 100 && end.next_comm == "cyclictest"' - # trace-cmd start -e all -e wakeup_lat -R stacktrace - # cyclictest -l 1000 -p80 -i250 -a -t -q -m -d 0 -b 1000 --tracemark - # trace-cmd show -s | tail -30 - -0 [002] dNh4 23454.902246: sched_wakeup: comm=cyclictest pid=12272 prio=120 target_cpu=002 - -0 [005] ...1 23454.902246: cpu_idle: state=4294967295 cpu_id=5 - -0 [007] d..1 23454.902246: cpu_idle: state=0 cpu_id=7 - -0 [002] dNh1 23454.902247: hrtimer_expire_exit: hrtimer=0000000037956dc2 - -0 [005] d..1 23454.902248: cpu_idle: state=0 cpu_id=5 - -0 [002] dNh1 23454.902248: write_msr: 6e0, value 4866ce957272 - -0 [006] ...1 23454.902248: cpu_idle: state=4294967295 cpu_id=6 - -0 [002] dNh1 23454.902249: local_timer_exit: vector=236 - -0 [006] d..1 23454.902250: cpu_idle: state=0 cpu_id=6 - -0 [002] .N.1 23454.902250: cpu_idle: state=4294967295 cpu_id=2 - -0 [002] dN.1 23454.902251: rcu_utilization: Start context switch - -0 [002] dN.1 23454.902252: rcu_utilization: End context switch - -0 [001] ...1 23454.902252: cpu_idle: state=4294967295 cpu_id=1 - -0 [002] dN.3 23454.902253: prandom_u32: ret=3692516021 - -0 [001] d..1 23454.902254: cpu_idle: state=0 cpu_id=1 - -0 [002] d..2 23454.902254: sched_switch: prev_comm=swapper/2 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=cyclictest next_pid=12275 next_prio=19 - -0 [002] d..4 23454.902256: wakeup_lat: next_comm=cyclictest lat=17 - -0 [002] d..5 23454.902258: - => trace_event_raw_event_synth - => action_trace - => event_hist_trigger - => event_triggers_call - => trace_event_buffer_commit - => trace_event_raw_event_sched_switch - => __traceiter_sched_switch - => __schedule - => schedule_idle - => do_idle - => cpu_startup_entry - => secondary_startup_64_no_verify --- - -Here's the options for *sqlhist* explained: - - *-n wakeup_lat* :: - Name the synthetic event to use *wakeup_lat*. - - *-e*:: - Execute the commands that are printed. - - *-T*:: - Perform both a trace action and then a snapshot action (swap the buffer into the static 'snapshot' buffer). - - *-m lat*:: - Trigger the actions whenever 'lat' hits a new maximum value. - -Now a breakdown of the SQL statement: -[source, c] --- - 'SELECT end.next_comm AS comm, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) AS lat FROM ' \ - 'sched_waking AS start JOIN sched_switch AS end ON start.pid = end.next_pid WHERE end.next_prio < 100 && end.next_comm == "cyclictest"' --- - *end.next_comm AS comm*:: - Save the 'sched_switch' field *next_comm* and place it into the *comm* field of the 'wakeup_lat' synthetic event. - - *(end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) AS lat*:: - Take the delta of the time stamps from the 'sched_switch' event and the 'sched_waking' event. - As time stamps are usually recorded in nanoseconds, *TIMESTAMP* would give the full nanosecond time stamp, - but here, the *TIMESTAMP_USECS* will truncate it into microseconds. The value is saved in the - variable *lat*, which will also be recorded in the synthetic event. - - *FROM 'sched_waking' AS start JOIN sched_switch AS end ON start.pid = end.next_pid*:: - Create the synthetic event by joining _sched_waking_ to _sched_switch_, matching - the _sched_waking_ 'pid' field with the _sched_switch_ 'next_pid' field. - Also make *start* an alias for _sched_waking_ and *end* an alias for _sched_switch_ - which then an use *start* and *end* as a subsitute for _sched_waking_ and _sched_switch_ - respectively through out the rest of the SQL statement. - - *WHERE end.next_prio < 100 && end.next_comm == "cyclictest"*:: - Filter the logic where it executes only if _sched_waking_ 'next_prio' field - is less than 100. (Note, in the Kernel, priorities are inverse, and the real-time - priorities are represented from 0-100 where 0 is the highest priority). - Also only trace when the 'next_comm' (the task scheduling in) of the _sched_switch_ - event has the name "cyclictest". - -For the *trace-cmd*(3) command: -[source, c] --- - trace-cmd start -e all -e wakeup_lat -R stacktrace --- - - *trace-cmd start*:: - Enables tracing (does not record to a file). - - *-e all*:: - Enable all events - - *-e wakeup_lat -R stacktrace*:: - have the "wakeup_lat" event (our synthetic event) enable the *stacktrace* trigger, were - for every instance of the "wakeup_lat" event, a kernel stack trace will be recorded - in the ring buffer. - -After calling *cyclictest* (a real-time tool to measure wakeup latency), read the snapshot -buffer. - - *trace-cmd show -s*:: - *trace-cmd show* reads the kernel ring buffer, and the *-s* option will read the *snapshot* - buffer instead of the normal one. - -[source, c] --- - -0 [002] d..4 23454.902256: wakeup_lat: next_comm=cyclictest lat=17 --- - We see on the "wakeup_lat" event happened on CPU 2, with a wake up latency 17 microseconds. - -This can be extracted into a *trace.dat* file that *trace-cmd*(3) can read and do further -analysis, as well as *kernelshark*. - -[source, c] --- - # trace-cmd extract -s - # trace-cmd report --cpu 2 | tail -30 - -0 [002] 23454.902238: prandom_u32: ret=1633425088 - -0 [002] 23454.902239: sched_wakeup: cyclictest:12275 [19] CPU:002 - -0 [002] 23454.902241: hrtimer_expire_exit: hrtimer=0xffffbbd68286fe60 - -0 [002] 23454.902241: hrtimer_cancel: hrtimer=0xffffbbd6826efe70 - -0 [002] 23454.902242: hrtimer_expire_entry: hrtimer=0xffffbbd6826efe70 now=23455294430750 function=hrtimer_wakeup/0x0 - -0 [002] 23454.902243: sched_waking: comm=cyclictest pid=12272 prio=120 target_cpu=002 - -0 [002] 23454.902244: prandom_u32: ret=1102749734 - -0 [002] 23454.902246: sched_wakeup: cyclictest:12272 [120] CPU:002 - -0 [002] 23454.902247: hrtimer_expire_exit: hrtimer=0xffffbbd6826efe70 - -0 [002] 23454.902248: write_msr: 6e0, value 4866ce957272 - -0 [002] 23454.902249: local_timer_exit: vector=236 - -0 [002] 23454.902250: cpu_idle: state=4294967295 cpu_id=2 - -0 [002] 23454.902251: rcu_utilization: Start context switch - -0 [002] 23454.902252: rcu_utilization: End context switch - -0 [002] 23454.902253: prandom_u32: ret=3692516021 - -0 [002] 23454.902254: sched_switch: swapper/2:0 [120] R ==> cyclictest:12275 [19] - -0 [002] 23454.902256: wakeup_lat: next_comm=cyclictest lat=17 - -0 [002] 23454.902258: kernel_stack: -=> trace_event_raw_event_synth (ffffffff8121a0db) -=> action_trace (ffffffff8121e9fb) -=> event_hist_trigger (ffffffff8121ca8d) -=> event_triggers_call (ffffffff81216c72) -=> trace_event_buffer_commit (ffffffff811f7618) -=> trace_event_raw_event_sched_switch (ffffffff8110fda4) -=> __traceiter_sched_switch (ffffffff8110d449) -=> __schedule (ffffffff81c02002) -=> schedule_idle (ffffffff81c02c86) -=> do_idle (ffffffff8111e898) -=> cpu_startup_entry (ffffffff8111eba9) -=> secondary_startup_64_no_verify (ffffffff81000107) --- - -BUGS ----- - -As *sqlhist* is just example code from a man page, it is guaranteed to contain -lots of bugs. For one thing, not all error paths are covered properly. - -SEE ALSO --------- -trace-cmd(1), tracefs_sql(3) - -AUTHOR ------- -Written by Steven Rostedt, - -RESOURCES ---------- -https://git.kernel.org/pub/scm/utils/trace-cmd/trace-cmd.git/ - -COPYING -------- -Copyright \(C) 2021 , Inc. Free use of this software is granted under -the terms of the GNU Public License (GPL). - From patchwork Fri Nov 5 12:16:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 12604573 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 68E77C4332F for ; Fri, 5 Nov 2021 12:16:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 537AE6127A for ; Fri, 5 Nov 2021 12:16:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231902AbhKEMTW (ORCPT ); Fri, 5 Nov 2021 08:19:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53554 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232954AbhKEMTT (ORCPT ); Fri, 5 Nov 2021 08:19:19 -0400 Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com [IPv6:2a00:1450:4864:20::32c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B90A2C061205 for ; Fri, 5 Nov 2021 05:16:39 -0700 (PDT) Received: by mail-wm1-x32c.google.com with SMTP id 71so6859551wma.4 for ; Fri, 05 Nov 2021 05:16:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=kjW3Ft0o1QbRPEMydzIPROuQg3tDieB+hGug3dKaESk=; b=Q/hQ6htTu4N8/v9DiyCe74+gAyzuP7hc6Svgs6rzhjgg8tPfg/dj0eiq5M/uCG59rP xunLjROixdWnIFWHLwnBZL4CuIuz6/Fq8miDlKVRM4IoyO2R7Qa+si0sCxqR3D7uKud7 WcvEBWywueGAITOnA4h7ip9hDU3V9Fq8lrZNcXaNN2RtIBjclHwrHc5CqqpDd5m0cNg2 0aU9vM9A/0T2g9zaiafkhRP4e8gaGgTmlmfoH7EyV86GEDY5vY6p99F27xxnobZ9zcp8 eL6g8/UYzCnROnmRJJmq0y09ZxxNZnTbjuIxC7cIkrPN8kIqmDsILYE1lV6mF/FUZLSU GVDg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=kjW3Ft0o1QbRPEMydzIPROuQg3tDieB+hGug3dKaESk=; b=LHKDYBBchI9leq6eTUwTblnaEpzei8G16in5qriFSaC3fdX+Z1QLqJ+os8I5mfNHdI 8+kIPiMQe+SUKUUPOlJD1pSl7CGuhFqTZebN5rdFkwhwTBxUp5FuYGpRuAv8P+G0RED0 tTwAxqUeHa7g+y6J7T9tXagdL7CHj25NXVvwKZk+Vq/klWN1sqHcwgtsOO2W+LUts5C2 JVGfjnN4m9zgnFEuzo0/T5eHU/RsAatR2d5lGm5u4k1zCOMd5O2JJITlTYjhi1fMg2wf f8UNhXvcTx2K5mJ9aQ8kSqCHQ+i0bD1nGAVvk30v4w4BwCY1UZUdejNtIr6nK3JE8Bzq GCvw== X-Gm-Message-State: AOAM531v+WERDtJubYwNqZ4Na74IicnUIM0s9wzdub7VPmoKx/QSzd7E phq9Gg07668OrZR4WHQlpEAigsUeCNhQ5Q== X-Google-Smtp-Source: ABdhPJzlIO053SLhqhCKkPH1lovILq7V2GO+KxG4tQI4FLoEsPCshe6rsHDJcPQQGRRrHh/OcmQoMA== X-Received: by 2002:a05:600c:202:: with SMTP id 2mr30226657wmi.134.1636114598364; Fri, 05 Nov 2021 05:16:38 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id x13sm7936531wrr.47.2021.11.05.05.16.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 Nov 2021 05:16:37 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v5 12/12] libtracefs: Fix duplication in synthetic events man page Date: Fri, 5 Nov 2021 14:16:24 +0200 Message-Id: <20211105121624.398717-13-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211105121624.398717-1-tz.stoyanov@gmail.com> References: <20211105121624.398717-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org There is a duplication in the tracefs_synth_create() man page description. Signed-off-by: Tzvetomir Stoyanov (VMware) --- Documentation/libtracefs-synth2.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/libtracefs-synth2.txt b/Documentation/libtracefs-synth2.txt index f734b44..5338351 100644 --- a/Documentation/libtracefs-synth2.txt +++ b/Documentation/libtracefs-synth2.txt @@ -49,8 +49,8 @@ as a field for both events to calculate the delta in nanoseconds, or use *TRACEFS_TIMESTAMP_USECS" as the compare fields for both events to calculate the delta in microseconds. This is used as the example below. -*tracefs_synth_create*() creates the synthetic event in the system in the system -in the _instance_ provided. Note, synthetic events apply across all instances, +*tracefs_synth_create*() creates the synthetic event in the system in the +_instance_ provided. Note, synthetic events apply across all instances, but some creation requires histograms to be established, which are local to instances.