From patchwork Mon Nov 15 10:45:42 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: 12619281 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 CA027C433EF for ; Mon, 15 Nov 2021 10:46:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AE363630EF for ; Mon, 15 Nov 2021 10:46:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231184AbhKOKtN (ORCPT ); Mon, 15 Nov 2021 05:49:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60748 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237552AbhKOKs5 (ORCPT ); Mon, 15 Nov 2021 05:48:57 -0500 Received: from mail-ed1-x534.google.com (mail-ed1-x534.google.com [IPv6:2a00:1450:4864:20::534]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 38610C061767 for ; Mon, 15 Nov 2021 02:46:01 -0800 (PST) Received: by mail-ed1-x534.google.com with SMTP id m14so70079303edd.0 for ; Mon, 15 Nov 2021 02:46:01 -0800 (PST) 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=hHZSvWEMZvBGFSSKfwugmOq0OTi4IzuSUBBm/nGt270=; b=DJ95xjGWXC+/HFVN0W5/I/EmVp8wDCxNlC3EEn+2LZLFtVLQCC61cQUEaK4Hw4r1dR 9/v7c28SvKWSv6bzMbR6/zPVGdizj5SdmUjLrcPm4/MISxGWmouMLOZbUyo6kBJxkWqt lpD6+M3tESjfLRPcoivUBo4TqlJVM6cmmuY+sSanOtqSNHiMK8TFkNwY1dOVkR5V9HSq P5hVInfTTBhM8a86Iy8bLkqliPfFRszTAtQcQRnBmCE28wTWQW5K84H3Sj6zSEA46pYR MpYjdDm84CLrP7PhA/tCIUbDVsn7okHFM4/LY0yIN2IVsfff+B2z1Rkx2ADM4aos6azi KoCA== 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=hHZSvWEMZvBGFSSKfwugmOq0OTi4IzuSUBBm/nGt270=; b=aLatcGBe78dtzd9tjRfXLuVEqI/Zo6emZLQ/snNGWJxmlJ6wRWY9AExbhB5H+XAVGJ sJv5VL7YNhIsvoqkDYTfZ8ReyxYb+zlwyceCJlKcRb23Mdys+PD9bopN2QKcNT3qpX8o 1XVecikyUnHZWOy5k26yJ/1pjZfJcztyQDMFdOC+qRaCApAnGaxGKU7UgCC43+/DGZ9H 3MU9TpouvTmjGldZrfb76BMOhtD+FhEtRgmUB6xhMQpc/OZ31CIABBQKzQgBXekGjpZz EVLD+4oiTs54rhgsTUPxnSgBVdPqCDp3YSzoLxp9/sPB2CdbJqfUkNjJygARR92GPRcG fUYA== X-Gm-Message-State: AOAM5301lOvCgPeRWwy2DpdoYpEv35eB7zvdnzGNEVsB0Q+4AK1WEB9x v3uzjEylFZzJHw8IP5gRCpA= X-Google-Smtp-Source: ABdhPJyM05RgKga5+QvgcMBbMVxd+8OQh2o/9BGowMuEj5/JHpgnHrykV5sJwUjbbXw1KAIpz2lhCQ== X-Received: by 2002:a50:cd87:: with SMTP id p7mr54140658edi.205.1636973159635; Mon, 15 Nov 2021 02:45:59 -0800 (PST) Received: from oberon.zico.biz.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id e12sm6315509ejs.86.2021.11.15.02.45.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Nov 2021 02:45:59 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v7 01/15] libtracefs: New APIs for dynamic events Date: Mon, 15 Nov 2021 12:45:42 +0200 Message-Id: <20211115104556.121359-2-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211115104556.121359-1-tz.stoyanov@gmail.com> References: <20211115104556.121359-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 | 709 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 751 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..0f7cccd --- /dev/null +++ b/src/tracefs-dynevents.c @@ -0,0 +1,709 @@ +// 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" + +#define EVENT_INDEX(B) (ffs(B) - 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, KPROBE_EVENTS, "p", dyn_generic_del, dyn_generic_parse}, + {TRACEFS_DYNEVENT_KRETPROBE, KPROBE_EVENTS, "r", dyn_generic_del, dyn_generic_parse}, + {TRACEFS_DYNEVENT_UPROBE, UPROBE_EVENTS, "p", dyn_generic_del, dyn_generic_parse}, + {TRACEFS_DYNEVENT_URETPROBE, UPROBE_EVENTS, "r", dyn_generic_del, dyn_generic_parse}, + {TRACEFS_DYNEVENT_EPROBE, "", "e", dyn_generic_del, dyn_generic_parse}, + {TRACEFS_DYNEVENT_SYNTH, SYNTH_EVENTS, "", 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) != EVENT_INDEX(TRACEFS_DYNEVENT_MAX)); + + if (!tracefs_file_exists(NULL, DYNEVENTS_EVENTS)) + return; + + /* Use ftrace dynamic_events, if available */ + for (i = 0; i < EVENT_INDEX(TRACEFS_DYNEVENT_MAX); i++) + dynevents[i].file = DYNEVENTS_EVENTS; + + dynevents[EVENT_INDEX(TRACEFS_DYNEVENT_SYNTH)].prefix = "s"; +} + +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[EVENT_INDEX(type)]; +} + +/** + * 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 Mon Nov 15 10:45:43 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: 12619283 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 92459C433FE for ; Mon, 15 Nov 2021 10:46:20 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7511661AAD for ; Mon, 15 Nov 2021 10:46:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231142AbhKOKtN (ORCPT ); Mon, 15 Nov 2021 05:49:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60754 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231286AbhKOKs6 (ORCPT ); Mon, 15 Nov 2021 05:48:58 -0500 Received: from mail-ed1-x535.google.com (mail-ed1-x535.google.com [IPv6:2a00:1450:4864:20::535]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3D88BC0613B9 for ; Mon, 15 Nov 2021 02:46:02 -0800 (PST) Received: by mail-ed1-x535.google.com with SMTP id g14so6179696edb.8 for ; Mon, 15 Nov 2021 02:46:02 -0800 (PST) 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=8PbFluYxM42X1L+Slvpt4jNgCEqCaKXabQBVgjBPpDU=; b=d0pVijQHldYGRxG9hqYkySih25+/VHKZtCg59nGs5ZZcPtIKpg0U/3wuYLltzknH56 skuILuwMmRTJj1SLtSXIxia2Bffcr2EEhsDmVQLPNtDzGDpi+UTgkHIGjM5ZoWAUftN8 Lol3ld6vTdG0LmEVQfVh9/szGnFZv2u7uTpJYp1Ex84cu/Dh59sVNIw9dROUipvMEO9D 9hQH83DANMDDNiCh6pZjHqaDFsNdMw1v1hm9nSw1vqMemMko7Dffy2zXSkK/vD6LNCeB vKffEzdarAcOzndWmjXYfsdSKQ7WeAjXtn+1MxSSOECSF1rNj5GJ9cWQmZh2X+MWxC8T GG9A== 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=8PbFluYxM42X1L+Slvpt4jNgCEqCaKXabQBVgjBPpDU=; b=Mh2wWRVqEBt/RWQ1KRAw7avcIhBAjonYvTro2V57H6CVSbY4XDPzwbDJaOEOdQVGBh W7+7ZAfyxjs80qXFmx3LVHWbkqYy8dAoCuzkCpcQXvNbgSlSg7cwPfQ2g3ZFvhvOrKHt hEidTznW+P/4zxOlRdHFiwlABwS6qvimWDAPoLmwfO6s2mbZX/dW/ZuQ80Vdj2DJe4tU wehIE6yr8c00M+D1iChrtoTGJfic8FQYBacHLQgYmSHmh9USEWaCSUgpUsMwG+Raw2DB Pk52bM3MJ5a+Shd6+YC1A5eUX+/F8Di1ZUHekGtgOAoAZWKN852l7OXO+mSmzgJoFnyI p8pA== X-Gm-Message-State: AOAM531Bjfhd5lbxqx/ghViEtanCG3CNlEatWJQGLSqNWuXzntDYTcrl PCS4A7A12WuDjVJ7vjIuQFo= X-Google-Smtp-Source: ABdhPJxhacALg+lavbINp4j8h5ych3yIWkCmCU3ZUgHaiNgmBahIJJ84eVS0mu554TAJ/en2zxQFjg== X-Received: by 2002:a17:907:6e26:: with SMTP id sd38mr49134077ejc.90.1636973160832; Mon, 15 Nov 2021 02:46:00 -0800 (PST) Received: from oberon.zico.biz.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id e12sm6315509ejs.86.2021.11.15.02.45.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Nov 2021 02:46:00 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v7 02/15] libtracefs: New APIs for kprobe allocation Date: Mon, 15 Nov 2021 12:45:43 +0200 Message-Id: <20211115104556.121359-3-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211115104556.121359-1-tz.stoyanov@gmail.com> References: <20211115104556.121359-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 Mon Nov 15 10:45:44 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: 12619287 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 0472BC433F5 for ; Mon, 15 Nov 2021 10:46:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E0CB26320D for ; Mon, 15 Nov 2021 10:46:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231140AbhKOKtP (ORCPT ); Mon, 15 Nov 2021 05:49:15 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60764 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237604AbhKOKtA (ORCPT ); Mon, 15 Nov 2021 05:49:00 -0500 Received: from mail-ed1-x529.google.com (mail-ed1-x529.google.com [IPv6:2a00:1450:4864:20::529]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 21282C061746 for ; Mon, 15 Nov 2021 02:46:04 -0800 (PST) Received: by mail-ed1-x529.google.com with SMTP id b15so69553017edd.7 for ; Mon, 15 Nov 2021 02:46:04 -0800 (PST) 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=J9iEgdzNzMxl43ZEx3AmCPex4l5vYz7WmIKnc62EFzA=; b=kTXmLZHy+TMmVI43axKEyXxJq8nJkaAbC1esyBwBXVC2v8o+wvJNsROqSUe3wRIGiD pSXJniyGSxtUvbYN5vyevypwfj/QEOoaBPAcEGu5yyzdT/hX7Jsd9j685u/gnMjgPBnQ Hr2P/vZ/+ibMemyYU+wXSvy3r4hje4Iyjre5cstgunkacBi0Zun4sdVlP0SLlUABkHry JlwarNqZMRzzWRQp9wy8VjqbAH04bJjI4CqPImhsj5gpUFjM/AghTezkvCWIEEmlskG7 9e+5+aLj9dgCIiwVjY6zTCUbWK0YLbFxgU8nEB/nrSz7HhkedwHgIlhboB/lT8JvKHCc 3egA== 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=J9iEgdzNzMxl43ZEx3AmCPex4l5vYz7WmIKnc62EFzA=; b=rpvMx0hFTHRzXbnbqg8dpkD8fb45v7pmaS+ycAMbYtvGPZzEZle7FGJEOGcGq1WLzO kaQEj9lGurzFzWAxw986+kxEvwocVJBo8z0HAgJl62WBqMLbrIb2u1HI9Y7AkSJzCkLm RoXB62X7D7BCYtcM+bWVy5lVRAmnStB7rXfTEVJxtKb6GzD+Gvdeb/aG1wzWkK7c7KD4 RDf/GYGZa4imLHjpaD2d0G6M3+dkdgW3ZcElQ3IWb1pnI+s1Q4k+bP8ZRHW4/OAD1w5A zwDANRA/8qD46XY/z/u6++3TVNKnNb7TahQiTQh7RWnbrTdJSnC1NhAbNBshrwpy3V90 1a6A== X-Gm-Message-State: AOAM5313/RiBFBWmocdbrNFe8Rt6C94QOr5D277lfPecfhtJIutnS9GQ ybO7W30Hwd8+ur33TYEo4gLGVEK8NeOUvw== X-Google-Smtp-Source: ABdhPJyLqcdkYdQispOW+1WntzG0Iml/P7cZpU3+zn0LITJFuw577xfZKhChkSevh3UcAoA8gPDraA== X-Received: by 2002:a05:6402:51c6:: with SMTP id r6mr924267edd.365.1636973162617; Mon, 15 Nov 2021 02:46:02 -0800 (PST) Received: from oberon.zico.biz.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id e12sm6315509ejs.86.2021.11.15.02.46.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Nov 2021 02:46:01 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v7 03/15] libtracefs: Remove redundant kprobes APIs Date: Mon, 15 Nov 2021 12:45:44 +0200 Message-Id: <20211115104556.121359-4-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211115104556.121359-1-tz.stoyanov@gmail.com> References: <20211115104556.121359-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 Mon Nov 15 10:45:45 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: 12619279 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 40ECDC433F5 for ; Mon, 15 Nov 2021 10:46:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2A1A3630EF for ; Mon, 15 Nov 2021 10:46:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231135AbhKOKtK (ORCPT ); Mon, 15 Nov 2021 05:49:10 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60770 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237636AbhKOKtB (ORCPT ); Mon, 15 Nov 2021 05:49:01 -0500 Received: from mail-ed1-x531.google.com (mail-ed1-x531.google.com [IPv6:2a00:1450:4864:20::531]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AF735C061766 for ; Mon, 15 Nov 2021 02:46:05 -0800 (PST) Received: by mail-ed1-x531.google.com with SMTP id g14so6180641edb.8 for ; Mon, 15 Nov 2021 02:46:05 -0800 (PST) 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=7BUnNNvtelfSsEsX0fj2R1XkVZDYthUXP5AbVuNiHE0=; b=K6QRzcDSeJ2+aQWlTFXBC8cNSDoZ8AA1M3NsXT1749x07GCKHKH5WGiKtqp+BmLa8/ usgNg9uQFb/RTkKOiv1CaUCPDaG6ocSCzfWMQOyj4UKp/I5vcy+STYfitdaAyEfSZgoZ 5ft3sXgd9Sk4pITRv8RT02RfrSAHTdNRY9JKyjinQQHaVLZ348szHOd9Bb9F6dApUwIC kDjoUHQes2BMBtDno6Caq8gqztj5IHvma4LOYyFUdVII4IgMffGDaItJRkqxCXWNHKCR /ny/hztnQpho4KWVovo7cl/anwfbXAsy8GzxTZXtTX5xW5Jser1Ay3WiuC6+zemMbC+1 WNrQ== 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=7BUnNNvtelfSsEsX0fj2R1XkVZDYthUXP5AbVuNiHE0=; b=2M9Gb2SF2eFrGEig2jjuOl3uCxKRIR/n8qleMzNiG5hp0d2b3ItL20E7ZUjbPjmuRe LGmCteXEQiaJlfhxLAMUfPVwrnYFg8mi1Nf3n1t2RbFLKwOkQY8TMfTCZsILyb7gCspe lDOh+OOJDUbFZnsiM2oGBoCRxn9iB7TPyXbXAcoDtdB0tad9tskEPWc6LNZj69GQiztc YZG4m4UkfB9t09PuCqUVI4bIyGq87Y+c/jIblTJdzKcsl9TWst76hUK2buUUH2izEG7r KfU2MvrsFswLQVtBoBckAR0XDt/tujdGf3bBj/QITqjhq1bAlO8KM/uYuimAulQ0AKt+ UHuQ== X-Gm-Message-State: AOAM533oqqpM/vYqgOjuxaOjzNtnfDrG4YNA3GOlVL/RWM/z5LWIyAR6 M3PM7pFK2LOo4/c0/CEK8XWnp31hvLEUhw== X-Google-Smtp-Source: ABdhPJzu9P9I05GmpgEM6iLtwDAClal4cxv02t2CpC4tKYvJ1o+iKaypAw5qpxXfFPqw8vl7kJYoYQ== X-Received: by 2002:a05:6402:278e:: with SMTP id b14mr54187340ede.362.1636973164344; Mon, 15 Nov 2021 02:46:04 -0800 (PST) Received: from oberon.zico.biz.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id e12sm6315509ejs.86.2021.11.15.02.46.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Nov 2021 02:46:03 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v7 04/15] libtracefs: Reimplement kprobe raw APIs Date: Mon, 15 Nov 2021 12:45:45 +0200 Message-Id: <20211115104556.121359-5-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211115104556.121359-1-tz.stoyanov@gmail.com> References: <20211115104556.121359-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 Mon Nov 15 10:45:46 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: 12619285 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 3B271C433F5 for ; Mon, 15 Nov 2021 10:46:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1F18E6320D for ; Mon, 15 Nov 2021 10:46:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230507AbhKOKtN (ORCPT ); Mon, 15 Nov 2021 05:49:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60754 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237639AbhKOKtD (ORCPT ); Mon, 15 Nov 2021 05:49:03 -0500 Received: from mail-ed1-x535.google.com (mail-ed1-x535.google.com [IPv6:2a00:1450:4864:20::535]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4230EC061767 for ; Mon, 15 Nov 2021 02:46:07 -0800 (PST) Received: by mail-ed1-x535.google.com with SMTP id y12so13274654eda.12 for ; Mon, 15 Nov 2021 02:46:07 -0800 (PST) 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=DDADqVqis1ytUbii4KTR8QPw2lYzPpTz2PMbQRzcpcM=; b=bmgfYIu7gukpmcRBsVA2Z+Zgvw4ZEMIkxNeCu92TWsXZlx5HTo/mWF0E+lrJf36U5s SOd7HEgTo96T2q8n//aIC/MAmtF9bT0KSBaCjrNVPnAJmjpbjZ9OXshw341fh62sray9 JllaaA/IPHzxXrYfdtaYFig0pyesqpzP3b302XpQ416T+yzn0ehDRPJkzjBM0hKs77gs V/2JJ5U+o3DiSGX4+e5t8rscLxzSmP16QwVNcI1Ti4Dto52YxzCvyE3nyTBlWJgRB1GQ NcgashNO0fmKW9vZgYd/Qh1jOJHO3lGmP9SArqLOPjvOK2nJiwgtw97+R3cNBNQCtPVq oiUw== 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=DDADqVqis1ytUbii4KTR8QPw2lYzPpTz2PMbQRzcpcM=; b=BZsPaUtnfh4ZkAqX/JVmIkntGYZyqPAFbpoqCQO23kaKRGtmAnevv+OCbpgIRDlxZG MMAW2BPohg34eh+6eVPiyONNEh0XKUb2l5nF1qoErnOKSZcaZPAWnBBgg/BrHdySLGqu 8LMXrlEfsatgMKn6Zp1ZtGyZdJnJlfBDDEUAKslDjsZ6cTsjWUcE7+UYfJ2Ki9CIPmID PsR/FtazjrK9fEGu42ZKFmi7REErwnAbXNtZTHVbFweOmmfOixohZUkdHFbT1Aa91Jfz /9KU7nlvvlI+uBYoeYorGTcfqE92vGgP7mKm1OBGA+RYxrHbQuAIEn3wZctyyb1WUkyt 6Hcw== X-Gm-Message-State: AOAM53349jvsBSfRb8zAnUhgHZUssUemxQTcq2lMCw4HmRNz8KLYGwyM WsbYIV8hi4r8ULOuDZI6xM56jo06eXebTg== X-Google-Smtp-Source: ABdhPJyryMYZ4zSCtdMX0vyX+Xynwn+eqbZXBYF8R+mUYx/CNqqfO0ys29QBfBOLoqyRfBgWYSRQWg== X-Received: by 2002:a17:907:d94:: with SMTP id go20mr48319502ejc.78.1636973165839; Mon, 15 Nov 2021 02:46:05 -0800 (PST) Received: from oberon.zico.biz.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id e12sm6315509ejs.86.2021.11.15.02.46.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Nov 2021 02:46:04 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v7 05/15] libtracefs: Extend kprobes unit test Date: Mon, 15 Nov 2021 12:45:46 +0200 Message-Id: <20211115104556.121359-6-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211115104556.121359-1-tz.stoyanov@gmail.com> References: <20211115104556.121359-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 | 419 +++++++++++++++++++++++++----------------- 1 file changed, 249 insertions(+), 170 deletions(-) diff --git a/utest/tracefs-utest.c b/utest/tracefs-utest.c index 09bb8f2..18cd37f 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,248 @@ static void test_instance_file_read(struct tracefs_instance *inst, const char *f free(file); } +struct probe_test { + enum tracefs_dynevent_type type; + char *prefix; + char *system; + char *event; + char *address; + char *format; +}; + +static bool check_probes(struct probe_test *probes, int count, + struct tracefs_dynevent **devents, bool in_system, + struct tracefs_instance *instance) +{ + enum tracefs_dynevent_type type; + char *ename; + char *address; + char *event; + char *system; + char *format; + char *prefix; + int found = 0; + int ret; + int i, j; + + for (i = 0; devents && devents[i]; i++) { + type = tracefs_dynevent_info(devents[i], &system, + &event, &prefix, &address, &format); + for (j = 0; j < count; j++) { + if (type != probes[j].type) + continue; + if (probes[j].event) + ename = probes[j].event; + else + ename = probes[j].address; + if (strcmp(ename, event)) + continue; + if (probes[j].system) { + CU_TEST(strcmp(probes[j].system, system) == 0); + } + CU_TEST(strcmp(probes[j].address, address) == 0); + if (probes[j].format) { + CU_TEST(strcmp(probes[j].format, format) == 0); + } + if (probes[j].prefix) { + CU_TEST(strcmp(probes[j].prefix, prefix) == 0); + } + ret = tracefs_event_enable(instance, system, event); + if (in_system) { + CU_TEST(ret == 0); + } else { + CU_TEST(ret != 0); + } + ret = tracefs_event_disable(instance, system, event); + if (in_system) { + CU_TEST(ret == 0); + } else { + CU_TEST(ret != 0); + } + + found++; + break; + } + free(system); + free(event); + free(prefix); + free(address); + free(format); + } + + CU_TEST(found == count); + if (found != count) + return false; + + return true; +} + +static void test_kprobes_instance(struct tracefs_instance *instance) +{ + struct probe_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 probe_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_probes(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_probes(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_probes(ktests, kprobe_count, devents, true, instance)); + CU_TEST(check_probes(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_probes(ktests, kprobe_count, devents, true, instance)); + CU_TEST(check_probes(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_probes(ktests, kprobe_count, devents, true, instance)); + CU_TEST(check_probes(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_probes(ktests, kprobe_count, dkprobe, false, instance)); + CU_TEST(check_probes(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_probes(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_probes(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_probes(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_probes(ktests, kprobe_count, devents, true, instance)); + CU_TEST(check_probes(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 +766,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 +1520,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 Mon Nov 15 10:45:47 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: 12619291 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 C70DFC433EF for ; Mon, 15 Nov 2021 10:46:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AF0A36320D for ; Mon, 15 Nov 2021 10:46:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231168AbhKOKtT (ORCPT ); Mon, 15 Nov 2021 05:49:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60782 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237640AbhKOKtE (ORCPT ); Mon, 15 Nov 2021 05:49:04 -0500 Received: from mail-ed1-x529.google.com (mail-ed1-x529.google.com [IPv6:2a00:1450:4864:20::529]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 51811C061746 for ; Mon, 15 Nov 2021 02:46:08 -0800 (PST) Received: by mail-ed1-x529.google.com with SMTP id x15so69849669edv.1 for ; Mon, 15 Nov 2021 02:46:08 -0800 (PST) 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=05BHPdPiDOtHQRIv4zIUU8jReMNW4bXw0flnarRNdek=; b=fDVYKND+FEh0QlUGs3KRaMjLxbHK/k2ItYFJDqox2KhuOQTrNDjmB6VpnRfxq/ZbqH Yciuz23hsRvaVNGZrOjYZVhT6x+OykR2FQ6qK4sNpqmSgwHdrVLWhqr2iyACFdKNpFUP 0Bx+8MeoWzoXcYTIWCV4Ji4yocv4f+OP+SncFggHrghxYhUpTEVvNgKqHOPkRjQdTaAh 1O8mIN4fy78C0z16sNPErPeKrdXMV++CQ6vcscD2Fqi3BWIF2CzyZYoyHFj8ME7W3ZpB YqtOczgvQ/usw+Q96lCp7+6BUCjsaxqAmmS2UZ53PVibF7+iVbgWWJyyPdlJbcrVecl5 x50A== 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=05BHPdPiDOtHQRIv4zIUU8jReMNW4bXw0flnarRNdek=; b=vzUvUk+Q7RQsBKJbW2UXXmHXPbV55tcxUpncUmS6UgcXffcD6Q/LBXPG3L2+Lv8IBG pJn/bmyRQOy3o2HCAXUFe/g2fv459Jsr9oPv41cUP2n8wX/kJ6+LzQ1pKr7bJVs8kMhZ SJqv+LYxKyj6j4Bk9rG8lqzopRSTUjZb36vSQlmyBH4tpByZnJrRyenRF8EDiq96LCep cegvEpqVV1vxHn5agx4es2GTwe9OGCmIgUhuuJOQNIXs3wyPv2KRQGOu+noG3mGV+tl/ qSzBU2hpT/tE74uywqGWJtyu0eRIB6SOoqwciCqvsCiljFOU3LclcwHVmo23sTnhZEct veTg== X-Gm-Message-State: AOAM53330W8eee0n0zoyiVrz/vUwtSnj6RjyxuSfXWMiaa8897SqEvM5 IEyOo7/IN4Lwj5Yl5WaFUl8= X-Google-Smtp-Source: ABdhPJxNksaHGEcBvOTskOoK8GgyCmfZseIWQlSxTHFyDtPg5Tfpwdd+65g4tBpwHejuNeHIvv2lIg== X-Received: by 2002:a50:9b07:: with SMTP id o7mr52543561edi.104.1636973166867; Mon, 15 Nov 2021 02:46:06 -0800 (PST) Received: from oberon.zico.biz.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id e12sm6315509ejs.86.2021.11.15.02.46.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Nov 2021 02:46:06 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v7 06/15] libtracefs: Rename tracefs_synth_init API Date: Mon, 15 Nov 2021 12:45:47 +0200 Message-Id: <20211115104556.121359-7-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211115104556.121359-1-tz.stoyanov@gmail.com> References: <20211115104556.121359-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 Mon Nov 15 10:45:48 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: 12619289 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 82F50C433EF for ; Mon, 15 Nov 2021 10:46:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6814661AAD for ; Mon, 15 Nov 2021 10:46:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231199AbhKOKtR (ORCPT ); Mon, 15 Nov 2021 05:49:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60788 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237647AbhKOKtF (ORCPT ); Mon, 15 Nov 2021 05:49:05 -0500 Received: from mail-ed1-x52c.google.com (mail-ed1-x52c.google.com [IPv6:2a00:1450:4864:20::52c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5695CC061766 for ; Mon, 15 Nov 2021 02:46:09 -0800 (PST) Received: by mail-ed1-x52c.google.com with SMTP id z10so43322801edc.11 for ; Mon, 15 Nov 2021 02:46:09 -0800 (PST) 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=G1vQ5g3GiREtd+cPcgSIqOvzt/C/6PyJE0cLz6AY9RQ=; b=ahcWQBIiqhktZW0c2EWaWwdCE8yPtSDXHQ3md3tKH5JVXagcOlvHzAELL8AfKMelhs eh51wZQdypBK6LMiZ7/MBUzZvKfVLZjZ1Vok1/HpqH8+/KL2QojH1CESTypUvz5Z5jfM uxqOpePpv7rBjzYcCnAXm1K1BAaBNrC/J5TDce+ruFrN7700j2UfCjCzATE5HvBUUS48 3HSw69HhZN082t9ESGTJt98hVPzJLlp1fEmwl57ITQdGkYWvry3vqJ5RrHmT4GaJKd2m jADpySkAFN8aupU6KxFWFlczBD/YZt0GLg6gjJ7x2DLwoCazMJww/tTjGQ8gpRqm1b/V TVOQ== 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=G1vQ5g3GiREtd+cPcgSIqOvzt/C/6PyJE0cLz6AY9RQ=; b=MXDqCfK1XbHaQckiUXbagPjtzBEhZyHBoHSRw99prJwdMRhSpro/dnWzuKlMrVkmYc A3aJko219rrE1K/p+Of5XNAmc3AeKuBdoID8boABl/LM1WjZ4seqGnbE8i5WAFAAk2HP 7tQNMGXk87BTP6aD4PCcoOCEcVpsseSg55asUojTTC2vivegcN/VB7Ux6dKS2up6Kamv LtsS2hxtovRSNgA7ZCoT8UB/CVbhombzIMU0HZoSiug3mHZt/Ypjg+5CDmPuVssyb8CK NLVQysRs4y5ZZzCVWBm0tCIb15qzeCjI6lxiCtbz3aybm055f4oy8Ml58YtxW1zMWq9+ ZdMw== X-Gm-Message-State: AOAM5310IdVGYDTevUzrFTzaisrEZaEZr6nWxrpOtjVSLgIKfm12RYjx H1PwX2EUeLhU3andruJ3vTE= X-Google-Smtp-Source: ABdhPJzFEPV1YJFf8bP6RzvNhwVj0r1EsxXkGY8Jeb8ctSNniTH8xQnF7FGQ8NaitEoLiCiDTB28NQ== X-Received: by 2002:a50:d74e:: with SMTP id i14mr32133609edj.243.1636973167965; Mon, 15 Nov 2021 02:46:07 -0800 (PST) Received: from oberon.zico.biz.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id e12sm6315509ejs.86.2021.11.15.02.46.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Nov 2021 02:46:07 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v7 07/15] libtracefs: Use the internal dynamic events API when creating synthetic events Date: Mon, 15 Nov 2021 12:45:48 +0200 Message-Id: <20211115104556.121359-8-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211115104556.121359-1-tz.stoyanov@gmail.com> References: <20211115104556.121359-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 Mon Nov 15 10:45:49 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: 12619293 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 94D54C433F5 for ; Mon, 15 Nov 2021 10:46:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7B20E6320D for ; Mon, 15 Nov 2021 10:46:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231213AbhKOKtU (ORCPT ); Mon, 15 Nov 2021 05:49:20 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60794 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237650AbhKOKtG (ORCPT ); Mon, 15 Nov 2021 05:49:06 -0500 Received: from mail-ed1-x52a.google.com (mail-ed1-x52a.google.com [IPv6:2a00:1450:4864:20::52a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 852D4C061746 for ; Mon, 15 Nov 2021 02:46:10 -0800 (PST) Received: by mail-ed1-x52a.google.com with SMTP id m20so23947429edc.5 for ; Mon, 15 Nov 2021 02:46:10 -0800 (PST) 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=hixuXk64CHv8JKcKgwUy56uV5n1XBc9iiy2yPhiSsik=; b=PSo3CIYFgugQPEmv9qJY2wirMHAQKA5fi7Uq+NwDjX70szikEAz7giktSXXbHY64DE 7jn2etEqqBacq60u1jBd76uwQVTR2Eogv/V9W4n8clQWPW+WDGneuS6jQPwdM7xxeGdA HrV9Q+/0uaO/OBvf2g+/h6P1BbRlvOrN/oPsk6iK7gwkAOCHTdp7VT0w8NkmgAgAsMVM qVZnIMqgYb3GM/JJe2BPuLvj5yxFN+5Q7ZqMNsKzkDQvsihtclE7sb7g6Bdx1aC/ETom 96wRHaf1k5sTew1BsWToOxnAsME8lLVw2se1x8DsVqSpXmVTQV9IOy0pjReOqFKIem/u T2VQ== 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=hixuXk64CHv8JKcKgwUy56uV5n1XBc9iiy2yPhiSsik=; b=VsPm8QbHD1dpRxbF7IqW+Q/YqiMJACrPIzvis7J2ZkBtebulhXxhlRJXp/f56UBdgk SUan9Ee9141YBvN2+RsIZ/DnF5blKMiypnApsDjSD+V6Stgs7vI4kQAqKyCy0n9CjGmo mol/d9jRSyx/TQQ8bj+lSS2Q/6mYvB4ZpkMV3C8waxpt/CK/B88veaYQ5FzFRJ4k7WrU llvRKUEqmpQ27IGLdSbrhCZnmIwVx1/BMEUFuSCfdBuVBWe9hOFtwVEgbVZGO70j0TP7 ytv/ozmhOGJ2MLt5lZRpYiPc9suYQ1kQeU5gPPKUt6TQElP15otGsNC0EHyH4S52v9CP ih9Q== X-Gm-Message-State: AOAM533+MwzDVl//Qw+klsxDlZg9l9Bt6P4dElyGPJnMRxQF0xKGekOy 4b9qakVOYf6hNBKcW10fpvg= X-Google-Smtp-Source: ABdhPJwTlqe+W7N1PwDdT66yOFkfJ3wsYfvx8KjjSR2rRArjEVV/49kg9hzV2cLGNLceodZVJ97lEQ== X-Received: by 2002:a17:907:9847:: with SMTP id jj7mr47896235ejc.508.1636973169077; Mon, 15 Nov 2021 02:46:09 -0800 (PST) Received: from oberon.zico.biz.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id e12sm6315509ejs.86.2021.11.15.02.46.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Nov 2021 02:46:08 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v7 08/15] libtracefs: Remove instance parameter from synthetic events APIs Date: Mon, 15 Nov 2021 12:45:49 +0200 Message-Id: <20211115104556.121359-9-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211115104556.121359-1-tz.stoyanov@gmail.com> References: <20211115104556.121359-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The synthetic events apply across all instances, but some histograms configuration is performed in specific instance. That configuration is implementation detail of the synthetic event and should not be part of the API. These APIs are affected by the change: tracefs_synth_create() tracefs_synth_destroy() tracefs_synth_show() Now, the top trace instance is used by default. If there is a use case for a custom instance, a new API could be proposed in the future: tracefs_synth_add_instance() that will associate the synthetic event with a custom instance, before calling the create API. Suggested-by: Steven Rostedt (VMware) Suggested-by: Yordan Karadzhov (VMware) Signed-off-by: Tzvetomir Stoyanov (VMware) --- Documentation/libtracefs-sql.txt | 4 ++-- Documentation/libtracefs-synth.txt | 6 ++--- Documentation/libtracefs-synth2.txt | 30 ++++++++++-------------- include/tracefs.h | 9 +++----- src/tracefs-hist.c | 36 ++++++++++++----------------- utest/tracefs-utest.c | 10 ++++---- 6 files changed, 40 insertions(+), 55 deletions(-) diff --git a/Documentation/libtracefs-sql.txt b/Documentation/libtracefs-sql.txt index e762eae..73984ae 100644 --- a/Documentation/libtracefs-sql.txt +++ b/Documentation/libtracefs-sql.txt @@ -405,9 +405,9 @@ static int do_sql(const char *buffer, const char *name, const char *var, } } } - tracefs_synth_show(&seq, NULL, synth); + tracefs_synth_show(&seq, synth); if (execute) - tracefs_synth_create(NULL, synth); + tracefs_synth_create(synth); } else { struct tracefs_hist *hist; hist = tracefs_synth_get_start_hist(synth); diff --git a/Documentation/libtracefs-synth.txt b/Documentation/libtracefs-synth.txt index 2fd9019..e238f46 100644 --- a/Documentation/libtracefs-synth.txt +++ b/Documentation/libtracefs-synth.txt @@ -268,7 +268,7 @@ static void show_event(void) trace_seq_init(&s); - tracefs_synth_show(&s, NULL, synth); + tracefs_synth_show(&s, synth); trace_seq_terminate(&s); trace_seq_do_printf(&s); trace_seq_destroy(&s); @@ -281,10 +281,10 @@ int main (int argc, char **argv) if (argc > 1) { if (!strcmp(argv[1], "create")) { /* Create the synthetic event */ - tracefs_synth_create(NULL, synth); + tracefs_synth_create(synth); } else if (!strcmp(argv[1], "delete")) { /* Delete the synthetic event */ - tracefs_synth_destroy(NULL, synth); + tracefs_synth_destroy(synth); } else { printf("usage: %s [create|delete]\n", argv[0]); exit(-1); diff --git a/Documentation/libtracefs-synth2.txt b/Documentation/libtracefs-synth2.txt index f734b44..95f3092 100644 --- a/Documentation/libtracefs-synth2.txt +++ b/Documentation/libtracefs-synth2.txt @@ -12,12 +12,9 @@ SYNOPSIS -- *#include * -int tracefs_synth_create(struct tracefs_instance pass:[*]instance, - struct tracefs_synth pass:[*]synth); -int tracefs_synth_destroy(struct tracefs_instance pass:[*]instance, - struct tracefs_synth pass:[*]synth); -int tracefs_synth_show(struct trace_seq pass:[*]seq, struct tracefs_instance pass:[*]instance, - struct tracefs_synth pass:[*]synth); +int tracefs_synth_create(struct tracefs_synth pass:[*]synth); +int tracefs_synth_destroy(struct tracefs_synth pass:[*]synth); +int tracefs_synth_show(struct trace_seq pass:[*]seq, struct tracefs_synth pass:[*]synth); bool tracefs_synth_complete(struct tracefs_synth pass:[*]synth); struct tracefs_hist pass:[*]tracefs_synth_get_start_hist(struct tracefs_synth pass:[*]synth); @@ -49,18 +46,15 @@ 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, -but some creation requires histograms to be established, which are local to -instances. +*tracefs_synth_create*() creates the synthetic event in the system. The synthetic events apply +across all instances. -*tracefs_synth_destroy*() destroys the synthetic event. It will attempt to stop -the running of it in the given _instance_, but if its running in another instance -this may fail as busy. +*tracefs_synth_destroy*() destroys the synthetic event. It will attempt to stop the running of it in +its instance (top by default), but if its running in another instance this may fail as busy. *tracefs_synth_show*() acts like *tracefs_synth_create*(), but instead of creating -the synthetic event in the given _instance_, it will write the echo commands to -manually create it in the _seq_ given. +the synthetic event in the system, it will write the echo commands to manually create +it in the _seq_ given. *tracefs_synth_complete*() returns true if the synthetic event _synth_ has both a starting and ending event. @@ -201,7 +195,7 @@ static void show_event(void) trace_seq_init(&s); - tracefs_synth_show(&s, NULL, synth); + tracefs_synth_show(&s, synth); trace_seq_terminate(&s); trace_seq_do_printf(&s); trace_seq_destroy(&s); @@ -214,10 +208,10 @@ int main (int argc, char **argv) if (argc > 1) { if (!strcmp(argv[1], "create")) { /* Create the synthetic event */ - tracefs_synth_create(NULL, synth); + tracefs_synth_create(synth); } else if (!strcmp(argv[1], "delete")) { /* Delete the synthetic event */ - tracefs_synth_destroy(NULL, synth); + tracefs_synth_destroy(synth); } else { printf("usage: %s [create|delete]\n", argv[0]); exit(-1); diff --git a/include/tracefs.h b/include/tracefs.h index 1092609..7b3f92b 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -522,13 +522,10 @@ int tracefs_synth_save(struct tracefs_synth *synth, char **save_fields); bool tracefs_synth_complete(struct tracefs_synth *synth); struct tracefs_hist *tracefs_synth_get_start_hist(struct tracefs_synth *synth); -int tracefs_synth_create(struct tracefs_instance *instance, - struct tracefs_synth *synth); -int tracefs_synth_destroy(struct tracefs_instance *instance, - struct tracefs_synth *synth); +int tracefs_synth_create(struct tracefs_synth *synth); +int tracefs_synth_destroy(struct tracefs_synth *synth); void tracefs_synth_free(struct tracefs_synth *synth); -int tracefs_synth_show(struct trace_seq *seq, struct tracefs_instance *instance, - struct tracefs_synth *synth); +int tracefs_synth_show(struct trace_seq *seq, struct tracefs_synth *synth); struct tracefs_synth *tracefs_sql(struct tep_handle *tep, const char *name, const char *sql_buffer, char **err); diff --git a/src/tracefs-hist.c b/src/tracefs-hist.c index 2685dab..005fa8f 100644 --- a/src/tracefs-hist.c +++ b/src/tracefs-hist.c @@ -658,6 +658,7 @@ struct action { * @end_parens: Current parenthesis level for end event */ struct tracefs_synth { + struct tracefs_instance *instance; struct tep_handle *tep; struct tep_event *start_event; struct tep_event *end_event; @@ -1898,11 +1899,9 @@ tracefs_synth_get_start_hist(struct tracefs_synth *synth) /** * tracefs_synth_create - creates the synthetic event on the system - * @instance: The instance to modify the start and end events * @synth: The tracefs_synth descriptor * - * This creates the synthetic events. The @instance is used for writing - * the triggers into the start and end events. + * This creates the synthetic events. * * Returns 0 on succes and -1 on error. * On error, errno is set to: @@ -1910,8 +1909,7 @@ tracefs_synth_get_start_hist(struct tracefs_synth *synth) * ENIVAL - a parameter is passed as NULL that should not be or a problem * writing into the system. */ -int tracefs_synth_create(struct tracefs_instance *instance, - struct tracefs_synth *synth) +int tracefs_synth_create(struct tracefs_synth *synth) { char *start_hist = NULL; char *end_hist = NULL; @@ -1947,13 +1945,13 @@ int tracefs_synth_create(struct tracefs_instance *instance, if (!end_hist) goto remove_synthetic; - ret = tracefs_event_file_append(instance, synth->start_event->system, + ret = tracefs_event_file_append(synth->instance, synth->start_event->system, synth->start_event->name, "trigger", start_hist); if (ret < 0) goto remove_synthetic; - ret = tracefs_event_file_append(instance, synth->end_event->system, + ret = tracefs_event_file_append(synth->instance, synth->end_event->system, synth->end_event->name, "trigger", end_hist); if (ret < 0) @@ -1965,7 +1963,7 @@ int tracefs_synth_create(struct tracefs_instance *instance, return 0; remove_start_hist: - remove_hist(instance, synth->start_event, start_hist); + remove_hist(synth->instance, synth->start_event, start_hist); remove_synthetic: free(end_hist); free(start_hist); @@ -1975,15 +1973,14 @@ int tracefs_synth_create(struct tracefs_instance *instance, /** * tracefs_synth_destroy - delete the synthetic event from the system - * @instance: The instance to modify the start and end events * @synth: The tracefs_synth descriptor * * This will destroy a synthetic event created by tracefs_synth_create() - * with the same @instance and @synth. + * with the same @synth. * - * It will attempt to disable the synthetic event, but if other instances - * have it active, it is likely to fail, which will likely fail on - * all other parts of tearing down the synthetic event. + * It will attempt to disable the synthetic event in its instance (top by default), + * but if other instances have it active, it is likely to fail, which will likely + * fail on all other parts of tearing down the synthetic event. * * Returns 0 on succes and -1 on error. * On error, errno is set to: @@ -1991,8 +1988,7 @@ int tracefs_synth_create(struct tracefs_instance *instance, * ENIVAL - a parameter is passed as NULL that should not be or a problem * writing into the system. */ -int tracefs_synth_destroy(struct tracefs_instance *instance, - struct tracefs_synth *synth) +int tracefs_synth_destroy(struct tracefs_synth *synth) { char *hist; int ret; @@ -2008,14 +2004,14 @@ int tracefs_synth_destroy(struct tracefs_instance *instance, } /* Try to disable the event if possible */ - tracefs_event_disable(instance, "synthetic", synth->name); + tracefs_event_disable(synth->instance, "synthetic", synth->name); hist = create_end_hist(synth); hist = append_filter(hist, synth->end_filter, synth->end_parens); if (!hist) return -1; - ret = remove_hist(instance, synth->end_event, hist); + ret = remove_hist(synth->instance, synth->end_event, hist); free(hist); hist = create_hist(synth->start_keys, synth->start_vars); @@ -2024,7 +2020,7 @@ int tracefs_synth_destroy(struct tracefs_instance *instance, if (!hist) return -1; - ret = remove_hist(instance, synth->start_event, hist); + ret = remove_hist(synth->instance, synth->start_event, hist); free(hist); ret = tracefs_dynevent_destroy(synth->dyn_event, true); @@ -2035,7 +2031,6 @@ int tracefs_synth_destroy(struct tracefs_instance *instance, /** * tracefs_synth_show - show the command lines to create the synthetic event * @seq: The trace_seq to store the command lines in - * @instance: The instance to modify the start and end events * @synth: The tracefs_synth descriptor * * This will list the "echo" commands that are equivalent to what would @@ -2046,7 +2041,6 @@ int tracefs_synth_destroy(struct tracefs_instance *instance, * ENOMEM - memory allocation failure. */ int tracefs_synth_show(struct trace_seq *seq, - struct tracefs_instance *instance, struct tracefs_synth *synth) { bool new_event = false; @@ -2079,7 +2073,7 @@ int tracefs_synth_show(struct trace_seq *seq, synth->dyn_event->format, path, synth->dyn_event->trace_file); tracefs_put_tracing_file(path); - path = tracefs_instance_get_dir(instance); + path = tracefs_instance_get_dir(synth->instance); hist = create_hist(synth->start_keys, synth->start_vars); hist = append_filter(hist, synth->start_filter, diff --git a/utest/tracefs-utest.c b/utest/tracefs-utest.c index 18cd37f..dbb0d26 100644 --- a/utest/tracefs-utest.c +++ b/utest/tracefs-utest.c @@ -337,28 +337,28 @@ static void test_instance_trace_sql(struct tracefs_instance *instance) synth = tracefs_sql(tep, SQL_1_EVENT, SQL_1_SQL, NULL); CU_TEST(synth != NULL); - ret = tracefs_synth_show(&seq, instance, synth); + ret = tracefs_synth_show(&seq, synth); CU_TEST(ret == 0); tracefs_synth_free(synth); trace_seq_reset(&seq); synth = tracefs_sql(tep, SQL_2_EVENT, SQL_2_SQL, NULL); CU_TEST(synth != NULL); - ret = tracefs_synth_show(&seq, instance, synth); + ret = tracefs_synth_show(&seq, synth); CU_TEST(ret == 0); tracefs_synth_free(synth); trace_seq_reset(&seq); synth = tracefs_sql(tep, SQL_3_EVENT, SQL_3_SQL, NULL); CU_TEST(synth != NULL); - ret = tracefs_synth_show(&seq, instance, synth); + ret = tracefs_synth_show(&seq, synth); CU_TEST(ret == 0); tracefs_synth_free(synth); trace_seq_reset(&seq); synth = tracefs_sql(tep, SQL_4_EVENT, SQL_4_SQL, NULL); CU_TEST(synth != NULL); - ret = tracefs_synth_show(&seq, instance, synth); + ret = tracefs_synth_show(&seq, synth); CU_TEST(ret == 0); tracefs_synth_free(synth); trace_seq_reset(&seq); @@ -367,7 +367,7 @@ static void test_instance_trace_sql(struct tracefs_instance *instance) if (event) { synth = tracefs_sql(tep, SQL_5_EVENT, SQL_5_SQL, NULL); CU_TEST(synth != NULL); - ret = tracefs_synth_show(&seq, instance, synth); + ret = tracefs_synth_show(&seq, synth); CU_TEST(ret == 0); tracefs_synth_free(synth); trace_seq_reset(&seq); From patchwork Mon Nov 15 10:45:50 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: 12619295 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 94FD8C433EF for ; Mon, 15 Nov 2021 10:46:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7DB4D63210 for ; Mon, 15 Nov 2021 10:46:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231217AbhKOKtW (ORCPT ); Mon, 15 Nov 2021 05:49:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60798 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237653AbhKOKtH (ORCPT ); Mon, 15 Nov 2021 05:49:07 -0500 Received: from mail-ed1-x52d.google.com (mail-ed1-x52d.google.com [IPv6:2a00:1450:4864:20::52d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 48C5EC061766 for ; Mon, 15 Nov 2021 02:46:11 -0800 (PST) Received: by mail-ed1-x52d.google.com with SMTP id g14so6181832edb.8 for ; Mon, 15 Nov 2021 02:46:11 -0800 (PST) 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=5wrs7L2YT+2ElOEXCQbxcUq6Ky9y3xFO6bJvpEM+XDQ=; b=i6wseAwOnv32cw9QvxF2uOS5qVCWruwzmlw34nz7qCZJaQq8rFAqFgQsiYlkwpR3sz c9SGKIBoAxMwN5BOcfK3hU3KyGWSxU7HPvCgok/M00354NUz0WbLpdwMgMo26qiU+npP lvOCE2RVuPHgLGMT75b4UxfoBW7j8hjQyggUVAhIUmO6gCRChFbrvLoln/pKFEYtSdjv EiehHSpgN8/Npe4++T3VGo5ox2xdn7WObbVxdEmVqGXnFH3uE360TtPhOwl8FdPXQCnf n9wXAU2pUI8Kg/nVRzwp3YtzYbWpevxpcgjDNbWdxuve11xKexNzKUYOUUJfuzGmaTnn EDrQ== 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=5wrs7L2YT+2ElOEXCQbxcUq6Ky9y3xFO6bJvpEM+XDQ=; b=NUWcyrRK2fCJ947+8qLN7xD51Tm/0hlnqWcv9MyYE9pNA6Lwm9w6yi2am5Dpe9kapu dwfymwS1kbJc8l1wmU4b2RETCTQf7KnQUKDStGI1/0Lqt3Nicee8riJyLeVEeuymo+cm KvtgPEIaPI/jQa+WCeQn+z/wjmD7muguSXDF7gZNYNE/BKyrvS/qhBP5GF8+brsWSWpB UtJV/bA6ZPSZ4kiktGzyssJE1hFNk1LTGFkLd6xrynCQpuSDawT02kn7GoCyTVQPGmAl ZCeu6uV7nu8+F6daCEKEoLkLE4Yu13ybrs0tn4K/6FBgPYDN7FxBoi/KL40i72tSKcUT Tevg== X-Gm-Message-State: AOAM532vuK/2IRND2fOkPxeTTQrJFviUugKdHOOOgeVqcMg/W0HCTrE/ Szh7q+93RAXHgYj9JgIjUNSN2rA7kwogEg== X-Google-Smtp-Source: ABdhPJzR90ccvZRIjrkDz+WfWftv46PmGV7yJ7sEDv8gW2zVCV9969GpuHy0xSx7nl2nTIn1kklHng== X-Received: by 2002:a05:6402:1d56:: with SMTP id dz22mr54923727edb.44.1636973169961; Mon, 15 Nov 2021 02:46:09 -0800 (PST) Received: from oberon.zico.biz.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id e12sm6315509ejs.86.2021.11.15.02.46.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Nov 2021 02:46:09 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v7 09/15] libtracefs: Add unit test for synthetic events Date: Mon, 15 Nov 2021 12:45:50 +0200 Message-Id: <20211115104556.121359-10-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211115104556.121359-1-tz.stoyanov@gmail.com> References: <20211115104556.121359-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 dbb0d26..2e4084d 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(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(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(); @@ -1521,4 +1615,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 Mon Nov 15 10:45:51 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: 12619297 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 8D6DFC433F5 for ; Mon, 15 Nov 2021 10:46:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 768BD61AAD for ; Mon, 15 Nov 2021 10:46:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231233AbhKOKtZ (ORCPT ); Mon, 15 Nov 2021 05:49:25 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60808 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237574AbhKOKtJ (ORCPT ); Mon, 15 Nov 2021 05:49:09 -0500 Received: from mail-ed1-x535.google.com (mail-ed1-x535.google.com [IPv6:2a00:1450:4864:20::535]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1F495C061746 for ; Mon, 15 Nov 2021 02:46:13 -0800 (PST) Received: by mail-ed1-x535.google.com with SMTP id z10so43323516edc.11 for ; Mon, 15 Nov 2021 02:46:13 -0800 (PST) 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=Nph0DVqAcFCkOXebNW88CnwB7ri3CU1NY+XAp8ha9X0=; b=TWTGSBVGQgkwaf2Fh7fVT652MbXK60vK+SxIQr0ZSFL9x5yTn8pvWPIfmPa/qUA1fo FjTQLs2FrCSkpOb20NSoyFqv3OUUd2z8cb+HNnQyPAU1mqib6UtlXRNR2mBSsbamZe8B 7tMvlFH1jM5zhVOkqauxphfFav1JwxkGU4iSYIekn5OYdQnkDDvFcsFxIpzDSmk+BvPB fj7a7IBSzAuIMFd37gbt7dgGStvk+V+rUTklC0onF+UbiOvzaP55G7wOugw5FNiEkOJv nHzcwPzcp1QUHRONGHVSQsZ6kkqZ/QwsZ6CSl41mywZfP/Q8CXEE1OAFEVEMSIuzpg6E En+g== 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=Nph0DVqAcFCkOXebNW88CnwB7ri3CU1NY+XAp8ha9X0=; b=zfXQchsyj5iDQEFWod4wbS3x51uLe9MWPO1scXiMZ4odEVZv2TbRCBqKLKXoLH9zx9 PqBHxptA2/WZYy1gYw9CS+nWHJGZVvHw1pn9A2XTv8ccZCrDf57ek8QbsGm7Bgj9ojg5 OXNC/g3lzaoW5yAxz8YSsKeZ9rdnO0L6LYNdidCL4tIz38vXoKOhDz0hhvCu2SldOI/D huLT7YS/9jkjBh2tyCzFpjFbhlBh6p3PEuSibFATNrwMiJz6DYtLvhuE8we0BBCThTjy wNG1jiVfzzqo4vnWX/xvi+UMAG3oO51ERd6WAKb2tH1zAS4QcfdZ7/nnnKwOtO6zb+M2 TH8w== X-Gm-Message-State: AOAM533eEzLEnpVCwvtZYEZ+805GmRKP2MRoJNL/xGUlb/KG9imnW+Yb awqgDOdh2gwgAetJXcKv/MJURgySz60IHw== X-Google-Smtp-Source: ABdhPJwH3YpV8UEHrvWBHoCCMYpmJC5bQK2IEJEuWbuXCgELIJPIxmhASeWq3dBv7X832WPiDLafHQ== X-Received: by 2002:a05:6402:254d:: with SMTP id l13mr53440605edb.165.1636973171596; Mon, 15 Nov 2021 02:46:11 -0800 (PST) Received: from oberon.zico.biz.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id e12sm6315509ejs.86.2021.11.15.02.46.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Nov 2021 02:46:10 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v7 10/15] libtracefs: Update kprobes man pages Date: Mon, 15 Nov 2021 12:45:51 +0200 Message-Id: <20211115104556.121359-11-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211115104556.121359-1-tz.stoyanov@gmail.com> References: <20211115104556.121359-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 Mon Nov 15 10:45:52 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: 12619303 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 27558C433FE for ; Mon, 15 Nov 2021 10:46:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0A4BA63221 for ; Mon, 15 Nov 2021 10:46:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230456AbhKOKte (ORCPT ); Mon, 15 Nov 2021 05:49:34 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60816 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237613AbhKOKtK (ORCPT ); Mon, 15 Nov 2021 05:49:10 -0500 Received: from mail-ed1-x52f.google.com (mail-ed1-x52f.google.com [IPv6:2a00:1450:4864:20::52f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3257FC061766 for ; Mon, 15 Nov 2021 02:46:14 -0800 (PST) Received: by mail-ed1-x52f.google.com with SMTP id z5so9896369edd.3 for ; Mon, 15 Nov 2021 02:46:14 -0800 (PST) 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=ob06WUv+izI4Jezu4mHKXc4ZrigJqrvIZBxSR1gu7c8=; b=WtRuY8UeboJt0d7kWMrcVxUB3T28shmzYB0E26sHDA5sgbJ3C8BcAGtrst/68JGnWl HjY38AJHY7OQjft/BgtsG60IuUcwduKoQqWLdAHfMZiQDGOB8Dh+oGo9Ux3jJPvhJwV7 YturP6F9PUer8Ie7fK3DMh89r8eJZhcK/Ga2vkNJFXjjJ4uojEQm6Nj1hGnAHt/hgnFy rsapmMAhciV/8mmmCQQPL1xO+n985w2UdjdhIEXo2sgxZQM/pPDHjjTqZkoQsUO9tnnY 6Gxi6lvlfhco9nkNT2pHP/Suk4IC5ZIX2kaz7H2s32HXfyBjUAHBC8CI7T3TUII+ymBm XLGw== 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=ob06WUv+izI4Jezu4mHKXc4ZrigJqrvIZBxSR1gu7c8=; b=7mk20P9eMYlQMKZ3yZmY7+qcvzGUGbt7CLIikyHqBwM65WKnrfvkotttUL5zLZTVc+ XXwRESFzTaRZDCBeB+wrtYMjaxVl7wd9ZuPJhHO/raokSTb3hnIbF4BwZ9j1bjFKHDFb /Fo9qYUgX6zM+ES2vHv2apNwn38+ipmcsAybZ/oCVtBaeQ6suiL9JLQMf5p8bpCxVaEJ hd4GY74XG0SciiHvE3RUnkYpQtNqCNPHoNJtcXoZHtPS1dFx36ZF/0zkX324QN8O/nUu fMbzB3c2VmVqy+iINoLiJrG64aEjMYOhhLs99OLWRgnN1LAeZuUcBLvU7oYX3Mka5IIi 0Wsg== X-Gm-Message-State: AOAM532Hb6S6YdxqT1VHWv83zLY+b+zGHXLAROOk32DBbbu/8cI3oxPu brLOu6ozk/gu3K0lEoyo+Fw= X-Google-Smtp-Source: ABdhPJyZT12KL+iplXOMJany3X049xRHMG3MIoS6qj9qmOlnyaqJstQiYT3DDyfcLcdbEujRwU5gMA== X-Received: by 2002:a50:da06:: with SMTP id z6mr53600642edj.355.1636973172669; Mon, 15 Nov 2021 02:46:12 -0800 (PST) Received: from oberon.zico.biz.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id e12sm6315509ejs.86.2021.11.15.02.46.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Nov 2021 02:46:12 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v7 11/15] libtracefs: Document dynamic events APIs Date: Mon, 15 Nov 2021 12:45:52 +0200 Message-Id: <20211115104556.121359-12-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211115104556.121359-1-tz.stoyanov@gmail.com> References: <20211115104556.121359-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 | 264 +++++++++++++++++++++++++ Documentation/libtracefs.txt | 11 ++ 2 files changed, 275 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..25172c3 --- /dev/null +++ b/Documentation/libtracefs-dynevents.txt @@ -0,0 +1,264 @@ +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: + +*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 Mon Nov 15 10:45:53 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: 12619299 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 0A20AC433EF for ; Mon, 15 Nov 2021 10:46:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E1179630EF for ; Mon, 15 Nov 2021 10:46:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231237AbhKOKtb (ORCPT ); Mon, 15 Nov 2021 05:49:31 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60818 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237593AbhKOKtK (ORCPT ); Mon, 15 Nov 2021 05:49:10 -0500 Received: from mail-ed1-x534.google.com (mail-ed1-x534.google.com [IPv6:2a00:1450:4864:20::534]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EDF6FC061767 for ; Mon, 15 Nov 2021 02:46:14 -0800 (PST) Received: by mail-ed1-x534.google.com with SMTP id e3so33401846edu.4 for ; Mon, 15 Nov 2021 02:46:14 -0800 (PST) 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=epkCq6AT/wz6cMxL6AMlkBwN3glIlU5bcaUvAqf1PeE=; b=XGB5f4tQYL3Bdy/IsEQ5Xl6Tuo6SQ54YKKs/MSl4/wMq44o+vTNyfwvbZ1yrWRiTWF 0bNSnmkDoFPw55cdTKFaTVL092P2uYyRk3o8Bujp8TxZiC+VVXPNWCZqaIFWVAZr73TI x5U7W9UC1BKB+clY16iKzvHoNHDhR2v8duAO20ccMTS8TcH8iA9PWWqa2eYI4gem8XXO gNh6tVUH9Tf6Md/OwnkruP4RgEwR+IQ/zYpTOpMw5iVAfBNa9KjjqSIhL9uWDJSELTIi 7TrfYkyfySoSIRMKSaDGdv9tw/nlhbjGrFdYeTOT6qXFMJxmSMQa4f/O6E6riWngxaPF prXg== 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=epkCq6AT/wz6cMxL6AMlkBwN3glIlU5bcaUvAqf1PeE=; b=SEj9SA/M0ajK+Y17W3AqkMJk23X2GhlZ/5RFxuSlGcPQmE3NxQnWcaf16BJTXsEX+P 4VvwQztmv943fbShE28H1MPu8AooATw0BST1Tz0hBU5pxn77WDz3VvIihXrm3ENBb0EN Ro6yO5QoSt97LbD0gMANGfnXqONoKJNCYAD7e8MDkMyaYZ+qlh89VTB7NKHFlrhCXhFv /mJv68KXoLzWHvR+gS+gVC6DZWhcZRabZ8w1wJ1oFwqRz3fNB0SWDvH6i6kC+cEn6DI5 VYP4I19qf4NCgTDHG6MDhuQYJJMnGq4+/eEtu6bfJahCFdlYbwuWbrO4ZAAingS4X5Xo nFdg== X-Gm-Message-State: AOAM533Cw7A4VLGifWSepWpvbUDU1YL/e/SbKHfxPjnlGUYJKPkqswqy 1h2pAOaAIFdslBSKG1pfyPDVbHsdzzgP1w== X-Google-Smtp-Source: ABdhPJzb5E07mSJTg7cDKQj6/omO+FR5sp9empLblaQVPd4vE+z8NEtjkSN65Df+Weu5TIBUNRvGUQ== X-Received: by 2002:a50:d6d9:: with SMTP id l25mr44398561edj.41.1636973173648; Mon, 15 Nov 2021 02:46:13 -0800 (PST) Received: from oberon.zico.biz.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id e12sm6315509ejs.86.2021.11.15.02.46.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Nov 2021 02:46:13 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v7 12/15] libtracefs: Do not clean sqlhist man page source Date: Mon, 15 Nov 2021 12:45:53 +0200 Message-Id: <20211115104556.121359-13-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211115104556.121359-1-tz.stoyanov@gmail.com> References: <20211115104556.121359-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The "make doc_clean" command assumes that all *.1 files are being generated with "make doc" command and removes all of them. This assumption is wrong, as the sources of man pages from section one have prefix "*.txt.1" and must not be removed. A more precise filtering is added, so only files generated during "make doc" are removed. Signed-off-by: Tzvetomir Stoyanov (VMware) --- Documentation/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/Makefile b/Documentation/Makefile index 0c00505..92a67aa 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -197,7 +197,8 @@ endif CLEAN_FILES = \ $(MAN_XML) $(addsuffix +,$(MAN_XML)) \ $(MAN_HTML) $(addsuffix +,$(MAN_HTML)) \ - $(DOC_MAN3) *.3 *.1 *.m + $(filter-out $(MAN1_TEXT),$(wildcard *.1)) \ + $(DOC_MAN3) *.3 *.m clean: $(Q) $(RM) $(CLEAN_FILES) From patchwork Mon Nov 15 10:45:54 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: 12619301 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 B9E55C433F5 for ; Mon, 15 Nov 2021 10:46:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A0FC663218 for ; Mon, 15 Nov 2021 10:46:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231252AbhKOKtq (ORCPT ); Mon, 15 Nov 2021 05:49:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60824 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237490AbhKOKtM (ORCPT ); Mon, 15 Nov 2021 05:49:12 -0500 Received: from mail-ed1-x52c.google.com (mail-ed1-x52c.google.com [IPv6:2a00:1450:4864:20::52c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 304D8C061746 for ; Mon, 15 Nov 2021 02:46:16 -0800 (PST) Received: by mail-ed1-x52c.google.com with SMTP id z10so43324128edc.11 for ; Mon, 15 Nov 2021 02:46:16 -0800 (PST) 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=h78QeBEEovORBF/16T7O3ZByWmCzMq5HwgKLnG/R2k4=; b=OSmSNSXtjnhARUcroPhjqt3uynSVpU3V132WntnN1qFxjFVpKmpOYsW1fPPAnRuxZh amnLZwKGhM2R3dbIVsLs+qecVj6cH4Zum9bQblWGNinArjw8pJC7d4tKmOMkROZXiNfY WHnzzJt9xtET0O/YVqkJlgqjB4kBqGQAiw6B4LZtDsUoS63sHyO1ikjCc3/LLM1xjxyX 6+jhXl9OqiKiklaZwcPnKdxJnqqMeLeIiCmwIqUbz7CjYj5CQ/wsugK88vCKL3sClKCw 85EcR5PwBZxbBq5PyB8PhX5bfORotIV6K2LgrWpl0L54VnuSyg0XMH6osMXoU3bNJDpA 5aMw== 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=h78QeBEEovORBF/16T7O3ZByWmCzMq5HwgKLnG/R2k4=; b=kuFK2tmHhdCPk5oaZlR/+gJDGW03Cwk864C5qRaRLDEG1wcPYCxIIrOr4GS0mVz4Id rC8UKzM85l67M/RG1cT8zKYDJwz5Xbh79C6HzqXuzzhRgyss7vwVQjqIJDotf3dseyH6 IgekqtUw1yx5fgZGUdfBWQGNmA8hhL333SW8mPQT3yGTDx8JV4B8aX6ZkPcXipu+S0/K Q220zIXGvJsdI69OkTX15egGCB7j0BskPvNKunB4p22DHIWIHw+Hh/E1RoqoVsBmM16A eJcBh0gBniXGWIZIouPZMrbQa42f2UxXsySlXcquL/3eLaIF4O15rZJLx+MpTrw1NCC1 MpVw== X-Gm-Message-State: AOAM532iYLk7iqi6nK+/Vn5hG9cZldStEDQYe+M+BHU1GWG4RmoahSso BT2WpDl1a0vyUPKHQhWJjXs= X-Google-Smtp-Source: ABdhPJwAvmR9nkKj9GQJrj+NIrSte+1ouCvX9DrCzkhnEHqcdoBQ2xHYZKSM269HwJG4v2Dbo4ZHlw== X-Received: by 2002:a17:906:478e:: with SMTP id cw14mr47272266ejc.46.1636973174771; Mon, 15 Nov 2021 02:46:14 -0800 (PST) Received: from oberon.zico.biz.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id e12sm6315509ejs.86.2021.11.15.02.46.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Nov 2021 02:46:14 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v7 13/15] libtracefs: Introduce eprobe API Date: Mon, 15 Nov 2021 12:45:54 +0200 Message-Id: <20211115104556.121359-14-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211115104556.121359-1-tz.stoyanov@gmail.com> References: <20211115104556.121359-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org Recently a new type of dynamic trace events was added in the Linux kernel - event probes. Tracefs library should have APIs to work with that event. As this is a dynamic event, all tracefs_dynevent_* APIs can be used to control event probes. Only one new API is proposed: tracefs_eprobe_alloc() Signed-off-by: Tzvetomir Stoyanov (VMware) --- include/tracefs.h | 4 ++++ src/Makefile | 1 + src/tracefs-eprobes.c | 56 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 src/tracefs-eprobes.c diff --git a/include/tracefs.h b/include/tracefs.h index 7b3f92b..4431ec7 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -261,6 +261,10 @@ enum tracefs_dynevent_type tracefs_dynevent_info(struct tracefs_dynevent *dynevent, char **system, char **event, char **prefix, char **addr, char **format); +struct tracefs_dynevent * +tracefs_eprobe_alloc(const char *system, const char *event, + const char *target_system, const char *target_event, const char *fetchargs); + struct tracefs_dynevent * tracefs_kprobe_alloc(const char *system, const char *event, const char *addr, const char *format); struct tracefs_dynevent * diff --git a/src/Makefile b/src/Makefile index 99cd7da..cda0a0c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -12,6 +12,7 @@ OBJS += tracefs-kprobes.o OBJS += tracefs-hist.o OBJS += tracefs-filter.o OBJS += tracefs-dynevents.o +OBJS += tracefs-eprobes.o # Order matters for the the three below OBJS += sqlhist-lex.o diff --git a/src/tracefs-eprobes.c b/src/tracefs-eprobes.c new file mode 100644 index 0000000..cc25f8e --- /dev/null +++ b/src/tracefs-eprobes.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * Copyright (C) 2021, VMware, Tzvetomir Stoyanov + * + */ +#include +#include + +#include "tracefs.h" +#include "tracefs-local.h" + +#define EPROBE_DEFAULT_GROUP "eprobes" + +/** + * tracefs_eprobe_alloc - Allocate new eprobe + * @system: The system name (NULL for the default eprobes) + * @event: The name of the event to create + * @target_system: The system of the target event + * @target_event: The name of the target event + * @fetchargs: String with arguments, that will be fetched from @target_event + * + * Allocate an eprobe context that will be in the @system group (or eprobes if + * @system is NULL). Have the name of @event. The new eprobe will be attached to + * given @target_event which is in the given @target_system. The arguments + * described in @fetchargs will fetched from the @target_event. + * + * The eprobe is not created in the system. + * + * Return a pointer to a eprobe context on success, or NULL on error. + * The returned pointer must be freed with tracefs_dynevent_free() + * + */ +struct tracefs_dynevent * +tracefs_eprobe_alloc(const char *system, const char *event, + const char *target_system, const char *target_event, const char *fetchargs) +{ + struct tracefs_dynevent *kp; + char *target; + + if (!event || !target_system || !target_event) { + errno = EINVAL; + return NULL; + } + + if (!system) + system = EPROBE_DEFAULT_GROUP; + + if (asprintf(&target, "%s.%s", target_system, target_event) < 0) + return NULL; + + kp = dynevent_alloc(TRACEFS_DYNEVENT_EPROBE, system, event, target, fetchargs); + free(target); + + return kp; +} + From patchwork Mon Nov 15 10:45:55 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: 12619305 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 14627C4332F for ; Mon, 15 Nov 2021 10:46:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F228E63218 for ; Mon, 15 Nov 2021 10:46:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230432AbhKOKtr (ORCPT ); Mon, 15 Nov 2021 05:49:47 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60830 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231153AbhKOKtN (ORCPT ); Mon, 15 Nov 2021 05:49:13 -0500 Received: from mail-ed1-x530.google.com (mail-ed1-x530.google.com [IPv6:2a00:1450:4864:20::530]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 350BBC0613B9 for ; Mon, 15 Nov 2021 02:46:17 -0800 (PST) Received: by mail-ed1-x530.google.com with SMTP id m14so70082705edd.0 for ; Mon, 15 Nov 2021 02:46:17 -0800 (PST) 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=2vIoVHLstu25xuIXqAcJFEhZJRRGdjPstyMmOwVR1K4=; b=f9qc/qYNdo3C+VJRV64heXUFu1x99fMk37ADztY3smHbmg/peolXDOTMiNN9qmKctR HKEjyFLNFQqYNNar7BKKl6dPI1vRJViOyeAKbICmtgOZfVL7CDlkmL3+oOtkceiTrEwR +0VmyR801sdsoplCBChWNB9w8p6nf61ERbfGVc65As9YtxmVoZIUwMajVyikcLwwYH06 c1zWOcWXB7xE2ek1Kmw1KvQPCRpj5D+1qHOTqhB7+sqPVKpu6xmhto3F7+yNz+H4+XNS jwSuEO8mCBXA5DEygoo2BWAMhonySrBB6mVgzUu+ZXmQmyd1p6h6HkHNV3hPHPHO8GvI 3Tuw== 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=2vIoVHLstu25xuIXqAcJFEhZJRRGdjPstyMmOwVR1K4=; b=m7GSS+gFXKYOfLxsISsrdmYsDYieRlsqvln0ud63HDs8oMNtQczNuxwx0LlEXRQKTN zB2vK7EZ/KTpi7mkrKScCisWpX4wJFSRvLS1FfhYWHjFm1Wjpno1CfyqEuc8W3ITXdSw ySJec5hj/8fbpaWSQpiw9QhGS4nAUpAgc8rblq8uUyGacQqXfI6WLMUlMyomNYj4KuGg /oMv2Aihqi62dvyc+LbWrLS2w9jPxh+grpPC7FoS5zicySGAEMTTd/cI/0R7VW/V+NJa Yp2e48U8e2Cmmwmi12md0Uh2RdHD5TEmyx0LHfZ8ICXUeMcRUsIDC/Khb3arjHERyAtx 55yQ== X-Gm-Message-State: AOAM533r/NUHSwEsW0ast6ug9cR4xxlO4wcLqbf8UPLpjd4WQBNMNs6v fqZrlh82FRmwu7eP239kw/E= X-Google-Smtp-Source: ABdhPJxIpSldL4UaovF+QFsWIXWvLSN4XN2vEIP2SwB0SwcTJRW/aZJTDEN1Sh+bJzsFs4YiG7UDoA== X-Received: by 2002:a05:6402:3513:: with SMTP id b19mr54487313edd.351.1636973175815; Mon, 15 Nov 2021 02:46:15 -0800 (PST) Received: from oberon.zico.biz.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id e12sm6315509ejs.86.2021.11.15.02.46.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Nov 2021 02:46:15 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v7 14/15] libtracefs: Add utest for event probes Date: Mon, 15 Nov 2021 12:45:55 +0200 Message-Id: <20211115104556.121359-15-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211115104556.121359-1-tz.stoyanov@gmail.com> References: <20211115104556.121359-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org All library APIs should be covered by the library unit test, that's why it is extended with new eeven probes tests. Signed-off-by: Tzvetomir Stoyanov (VMware) --- utest/tracefs-utest.c | 68 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/utest/tracefs-utest.c b/utest/tracefs-utest.c index 2e4084d..96b2baf 100644 --- a/utest/tracefs-utest.c +++ b/utest/tracefs-utest.c @@ -782,6 +782,73 @@ static void test_kprobes(void) test_kprobes_instance(test_instance); } +static void test_eprobes_instance(struct tracefs_instance *instance) +{ + struct probe_test etests[] = { + { TRACEFS_DYNEVENT_EPROBE, "e", NULL, "sopen_in", "syscalls.sys_enter_openat", + "file=+0($filename):ustring" }, + { TRACEFS_DYNEVENT_EPROBE, "e", "etest", "sopen_out", "syscalls.sys_exit_openat", + "res=$ret:u64" }, + }; + int count = sizeof(etests) / sizeof((etests)[0]); + struct tracefs_dynevent **deprobes; + struct tracefs_dynevent **devents; + char *tsys, *tevent; + char *tmp, *sav; + int ret; + int i; + + deprobes = calloc(count + 1, sizeof(*deprobes)); + + /* Invalid parameters */ + CU_TEST(tracefs_eprobe_alloc("test", NULL, "test", "test", "test") == NULL); + CU_TEST(tracefs_eprobe_alloc("test", "test", NULL, "test", "test") == NULL); + CU_TEST(tracefs_eprobe_alloc("test", "test", "test", NULL, "test") == NULL); + + ret = tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_EPROBE, true); + CU_TEST(ret == 0); + get_dynevents_check(TRACEFS_DYNEVENT_EPROBE, 0); + + for (i = 0; i < count; i++) { + tmp = strdup(etests[i].address); + tsys = strtok_r(tmp, "./", &sav); + tevent = strtok_r(NULL, "", &sav); + deprobes[i] = tracefs_eprobe_alloc(etests[i].system, etests[i].event, + tsys, tevent, etests[i].format); + free(tmp); + CU_TEST(deprobes[i] != NULL); + } + deprobes[i] = NULL; + + get_dynevents_check(TRACEFS_DYNEVENT_EPROBE, 0); + CU_TEST(check_probes(etests, count, deprobes, false, instance)); + + for (i = 0; i < count; i++) { + CU_TEST(tracefs_dynevent_create(deprobes[i]) == 0); + } + + devents = get_dynevents_check(TRACEFS_DYNEVENT_EPROBE, count); + CU_TEST(check_probes(etests, count, devents, true, instance)); + tracefs_dynevent_list_free(devents); + devents = NULL; + + for (i = 0; i < count; i++) { + CU_TEST(tracefs_dynevent_destroy(deprobes[i], false) == 0); + } + get_dynevents_check(TRACEFS_DYNEVENT_EPROBE, 0); + CU_TEST(check_probes(etests, count, deprobes, false, instance)); + + for (i = 0; i < count; i++) + tracefs_dynevent_free(deprobes[i]); + + free(deprobes); +} + +static void test_eprobes(void) +{ + test_eprobes_instance(test_instance); +} + static void test_instance_file(void) { struct tracefs_instance *instance = NULL; @@ -1616,4 +1683,5 @@ void test_tracefs_lib(void) test_ftrace_marker); CU_add_test(suite, "kprobes", test_kprobes); CU_add_test(suite, "syntetic events", test_synthetic); + CU_add_test(suite, "eprobes", test_eprobes); } From patchwork Mon Nov 15 10:45:56 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: 12619307 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 97B3DC43217 for ; Mon, 15 Nov 2021 10:46:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 839C8630EF for ; Mon, 15 Nov 2021 10:46:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231153AbhKOKtr (ORCPT ); Mon, 15 Nov 2021 05:49:47 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60836 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231161AbhKOKtN (ORCPT ); Mon, 15 Nov 2021 05:49:13 -0500 Received: from mail-ed1-x52e.google.com (mail-ed1-x52e.google.com [IPv6:2a00:1450:4864:20::52e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2D02FC061746 for ; Mon, 15 Nov 2021 02:46:18 -0800 (PST) Received: by mail-ed1-x52e.google.com with SMTP id z5so9897295edd.3 for ; Mon, 15 Nov 2021 02:46:18 -0800 (PST) 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=ah69xG5P4nVicL7GuHLsqd5IvrMQ6gBCU1n2d4zFeYg=; b=Du4pjyqG1zr/inhqjTGyomBxTIO4CUziuY9pfZpHzT1OxV913N4wMvf/GNddPLmM5q TbQxiGMXEK8ZZeb2PrxwvDhUrqmgfGcu1wNv74eAgh3HqUHLP2RQ3UQ18oqZoeDyKUTK Ph7dT/CU6uZA42ORhrN7PcZ/hhCaJus3qDzdvJehe+J83AgYfUIRhvygTAOaN6P0EXoA XH9KqhlYg8RXCtNhHFDj42D4N6bg5dtHVw7Wm4F0W+jDUr58B9cai8yf3AZNktSbbJvF NmguN9oJMyFuD8sw5w56DwucoC/uuOWLKqsSzz5mwV8HmQfJwA85et7c0QTicwZg6xvd kl5g== 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=ah69xG5P4nVicL7GuHLsqd5IvrMQ6gBCU1n2d4zFeYg=; b=424kl1pDlLIcCl9myqKAlySCB0M3KciPHTiQcaABUEnlYECxobQ7t1U7C9L9hW8m+8 B6m9KvjM6DX9eGksSa6BniFWurgLGS2wqpsPnEJ8TGWDwcLdbVhy5zET973Y8DYlbf75 UsnNT+gsp54jwkG/7Cz8I6M2ySOJmQ04VrjsTKZ8C2bAKhIzaaiD2MUIpg/F5Zaft90k 18IerRwa5jqJsnu3mFbFO/VAIn19kscNM0KRusbt1y5l9jBfx0jF9aLE/j/FG4yMBGar N8FTSMx/9gPOtSGdJeUsFu1z1rYyqqZ2m9+toLCg7U6JkXyy78dHc1jGLGSlOlttyVJR Au7g== X-Gm-Message-State: AOAM533cO4uO2vc9PVotACNDIkpafcSnj9/C4Vos/2ACG9cLg8MuDxMC Pws1BGsGi0heBEJiuZgZnk/nXt+VlcFIrQ== X-Google-Smtp-Source: ABdhPJytrDo5qDOSYJzqQyAc87zFlE544kuk6hKuDlsmwX9bZ2MgeIhsdJnSzHsqp7Bc43ddefAXMQ== X-Received: by 2002:aa7:c406:: with SMTP id j6mr34052352edq.76.1636973176820; Mon, 15 Nov 2021 02:46:16 -0800 (PST) Received: from oberon.zico.biz.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id e12sm6315509ejs.86.2021.11.15.02.46.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Nov 2021 02:46:16 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v7 15/15] libtracefs: Document eprobe API Date: Mon, 15 Nov 2021 12:45:56 +0200 Message-Id: <20211115104556.121359-16-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211115104556.121359-1-tz.stoyanov@gmail.com> References: <20211115104556.121359-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 API for ftrace event probes wasadded recently, it must be documented. A new man page is added, describing the API: tracefs_eprobe_alloc() Signed-off-by: Tzvetomir Stoyanov (VMware) --- Documentation/libtracefs-eprobes.txt | 189 +++++++++++++++++++++++++++ Documentation/libtracefs.txt | 3 + 2 files changed, 192 insertions(+) create mode 100644 Documentation/libtracefs-eprobes.txt diff --git a/Documentation/libtracefs-eprobes.txt b/Documentation/libtracefs-eprobes.txt new file mode 100644 index 0000000..3baaea3 --- /dev/null +++ b/Documentation/libtracefs-eprobes.txt @@ -0,0 +1,189 @@ +libtracefs(3) +============= + +NAME +---- +tracefs_eprobe_alloc - Allocate new event probe (eprobe) + +SYNOPSIS +-------- +[verse] +-- +*#include * + +struct tracefs_dynevent pass:[*] +*tracefs_eprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_, + const char pass:[*]_target_system_, const char pass:[*]_target_event_, + const char pass:[*]_fetchargs_); +-- + +DESCRIPTION +----------- +*tracefs_eprobe_alloc*() allocates a new eprobe context. The ebrobe is not configured in the system. +The new eprobe will be in the _system_ group (or eprobes if _system_ is NULL) and have the name of +_event_. The eprobe will be attached to _target_event_, located in _target_system_. The list of +arguments, described in _fetchargs_, will be fetched from _target_event_. The returned pointer to +the event probe must be freed with *tracefs_dynevent_free*(). + + +RETURN VALUE +------------ +The *tracefs_eprobe_alloc*() API returns a pointer to an allocated tracefs_dynevent structure, +describing the event probe. This pointer must be freed by *tracefs_dynevent_free*(3). Note, this +only allocates a descriptor representing the eprobe. It does not modify the running system. On error +NULL is returned. + +EXAMPLE +------- +[source,c] +-- +#include +#include +#include + +#include + +static struct tep_event *open_event; +static struct tep_format_field *file_field; + +static int callback(struct tep_event *event, struct tep_record *record, + int cpu, void *data) +{ + struct trace_seq seq; + + trace_seq_init(&seq); + tep_print_event(event->tep, &seq, record, "%d-%s: ", TEP_PRINT_PID, TEP_PRINT_COMM); + + if (event->id == open_event->id) { + trace_seq_puts(&seq, "open file='"); + tep_print_field(&seq, record->data, file_field); + trace_seq_puts(&seq, "'\n"); + } + + trace_seq_terminate(&seq); + trace_seq_do_printf(&seq); + +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 *myprobe = "my_eprobes"; + +int main (int argc, char **argv, char **env) +{ + struct tracefs_dynevent *eprobe; + struct tracefs_instance *instance; + struct tep_handle *tep; + const char *sysnames[] = { mykprobe, NULL }; + pid_t pid; + + if (argc < 2) { + printf("usage: %s command\n", argv[0]); + exit(-1); + } + + instance = tracefs_instance_create("exec_open"); + if (!instance) { + perror("creating instance"); + exit(-1); + } + + tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_EPROBE, true); + + eprobe = tracefs_eprobe_alloc(myprobe, "sopen", "syscalls", "sys_enter_openat2", + "file=+0($filename):ustring"); + if (!eprobe) { + perror("allocating event probe"); + exit(-1); + } + + if (tracefs_dynevent_create(eprobe)) { + perror("creating event probe"); + exit(-1); + } + + tep = tracefs_local_events_system(NULL, sysnames); + if (!tep) { + perror("reading events"); + exit(-1); + } + + open_event = tep_find_event_by_name(tep, myprobe, "sopen"); + file_field = tep_find_field(open_event, "file"); + + tracefs_event_enable(instance, myprobe, "sopen"); + pid = run_exec(&argv[1], env); + + /* Let the child start to run */ + sched_yield(); + + do { + tracefs_load_cmdlines(NULL, tep); + tracefs_iterate_raw_events(tep, instance, NULL, 0, callback, NULL); + } while (waitpid(pid, NULL, WNOHANG) != pid); + + /* Will disable the events */ + tracefs_dynevent_destroy(eprobe, true); + tracefs_dynevent_free(eprobe); + tracefs_instance_destroy(instance); + tep_free(tep); + + return 0; +} +-- + +FILES +----- +[verse] +-- +*tracefs.h* + Header file to include in order to have access to the library APIs. +*-ltracefs* + Linker switch to add when building a program that uses the library. +-- + +SEE ALSO +-------- +_libtracefs(3)_, +_libtraceevent(3)_, +_trace-cmd(1)_ + +AUTHOR +------ +[verse] +-- +*Steven Rostedt* +*Tzvetomir Stoyanov* +-- + +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 6850860..39cf027 100644 --- a/Documentation/libtracefs.txt +++ b/Documentation/libtracefs.txt @@ -75,6 +75,9 @@ Dynamic event generic APIs: 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_); +Even probes (eprobes): + struct tracefs_dynevent pass:[*] *tracefs_eprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_, const char pass:[*]_target_system_, const char pass:[*]_target_event_, const char pass:[*]_fetchargs_); + 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_);