From patchwork Wed Nov 3 15:44:07 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: 12601037 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 4B171C433F5 for ; Wed, 3 Nov 2021 15:44:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2508661076 for ; Wed, 3 Nov 2021 15:44:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231872AbhKCPrA (ORCPT ); Wed, 3 Nov 2021 11:47:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47110 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231814AbhKCPq7 (ORCPT ); Wed, 3 Nov 2021 11:46:59 -0400 Received: from mail-wm1-x330.google.com (mail-wm1-x330.google.com [IPv6:2a00:1450:4864:20::330]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 50E19C061208 for ; Wed, 3 Nov 2021 08:44:22 -0700 (PDT) Received: by mail-wm1-x330.google.com with SMTP id a20-20020a1c7f14000000b003231d13ee3cso4958873wmd.3 for ; Wed, 03 Nov 2021 08:44:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=mk8UsDEs/9HhhdOD6MZP+6P70WQWCZJP4h3Hu/8AwAg=; b=PVKH7tgrVgcxJinDuzl25FZynSYJvglbODOcdJ2QeFAiNxIORSn4WHhgiV/5nqGZdV uWrZFB4TfRJzNeS6shgbOGon8Lr1LWOiVZTj78UxlBeSFJjDn96BhdbB3bGJFukTcYIo JEkJ8PI7h14aWs5LoLzwIWp0xG9Q6oIKiHwPSd6vlpwyZ+hIBdHqguDiS/YqUewRLJEi 0fAEmBamI+d+UMfwRwfKXbe1Zu1mFQcbkbf63IENxTyYPQm8IZw53gt0VnrfG99vCMeE ge6yDJ+LGfgCZ/uaK1LQKbro57PHUVKJDsLmXBOyRUX3aQJg1dHUouxZBZXwxRkudbbE 9ZbA== 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=mk8UsDEs/9HhhdOD6MZP+6P70WQWCZJP4h3Hu/8AwAg=; b=I9aFDxNouGqiwhpXW/2sgpvNd2EGbmRiAMa9Q4GjykPN4mzTLVlj/eZBSXwckOUSiF EsLBn1gRuwcUFBaUJEd5A9W6Y5UMhiFYboNYRksCMrUfvt31dY2MEahSAdNcPwj2vb2A 6yz1dpNsimxfNpscEUeLTPT4jhOQeXCwPS1HjtTi/121dKRAE1ofC4g1cTMc4MOmH6BP 8Sxc2MWhoPpHOZM4qgV0PL9GzfNBftpy4MPS6fl3L2/RtClHc6JV2gaHyxuhTLD6zRmE l8oRvp5f76C4bjya9vGoo9OaUkcdnKG9ef2kA0lNjZU0qQY0+uE8j7KThrF8TZCiKaeJ YkUA== X-Gm-Message-State: AOAM530Vuy3zZR1Mh9SnDJHPQFwlZnAzF1Wr0SCHt9/WK/MthYqzjqUz mm5ap451VuMcBDpRiRJAa1jZ7GGfg5DNFg== X-Google-Smtp-Source: ABdhPJygdVKr7jTuIRXHs2KKcRUwcxyRgTbDV97ELOIZdcNeYcqqlkm0LVzakrMpsL9h5G9CdtlO9Q== X-Received: by 2002:a1c:2781:: with SMTP id n123mr16335372wmn.132.1635954260861; Wed, 03 Nov 2021 08:44:20 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id p12sm2767866wrr.10.2021.11.03.08.44.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 03 Nov 2021 08:44:20 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v3 01/11] libtracefs: Add new public macros for bits manipulations Date: Wed, 3 Nov 2021 17:44:07 +0200 Message-Id: <20211103154417.246999-2-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211103154417.246999-1-tz.stoyanov@gmail.com> References: <20211103154417.246999-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org Some of the tracefs library APIs may have bit mask parameters. To simplify the usage of such APIs, generic bit manipulations macros are added to the library API: TRACEFS_BIT_SET TRACEFS_BIT_TEST TRACEFS_BIT_CLEAR Signed-off-by: Tzvetomir Stoyanov (VMware) --- include/tracefs.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/tracefs.h b/include/tracefs.h index a2cda30..fa7f316 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -10,6 +10,10 @@ #include #include +#define TRACEFS_BIT_SET(M, B) do { (M) |= (1ULL << (B)); } while (0) +#define TRACEFS_BIT_TEST(M, B) ((M) & (1ULL<<(B))) +#define TRACEFS_BIT_CLEAR(M, B) do { (M) &= ~(1ULL << (B)); } while (0) + char *tracefs_get_tracing_file(const char *name); void tracefs_put_tracing_file(char *name); From patchwork Wed Nov 3 15:44:08 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: 12601041 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 5C823C4332F for ; Wed, 3 Nov 2021 15:44:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 45D916109F for ; Wed, 3 Nov 2021 15:44:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231867AbhKCPrB (ORCPT ); Wed, 3 Nov 2021 11:47:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47120 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231843AbhKCPrA (ORCPT ); Wed, 3 Nov 2021 11:47:00 -0400 Received: from mail-wr1-x431.google.com (mail-wr1-x431.google.com [IPv6:2a00:1450:4864:20::431]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 88CBBC061714 for ; Wed, 3 Nov 2021 08:44:23 -0700 (PDT) Received: by mail-wr1-x431.google.com with SMTP id d27so4243282wrb.6 for ; Wed, 03 Nov 2021 08:44:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=6h1vJDYTBvV2ieEmEn+9t7HgisiwS1MOI2iEPcBsu0w=; b=LNnGfS9tfAZxKF3OHEf8oR3IFcBK0HdP3AuvOnhTMogE+truL9ll3kgEGRxu4iOb2s Bw0CEA68Rh6Dd8SBEntgVKTMEq91cJc5G6FdIb0HTCf+iaYcUx9aamh27QPq9TkYU5vR S3YVzLs6FWanWKCpbTLu95n5uS8zPnzhEJFbE098Y25l2Kyr2zHxma6Yc3ksj6uCf8Sf ucac0GA2a0gu4W9eOlPAZsR5klr66MGMYBScXVMmalQRxlnDk1sPbJOlTwOKawH/x/1e z+0+U75OjMueWgojgw1CwAmZxaKF711phxyYV1thHPd8nbaTXapuFBz1eXiVI55n+dl5 rbkA== 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=6h1vJDYTBvV2ieEmEn+9t7HgisiwS1MOI2iEPcBsu0w=; b=YbJoc35XLnehvVHQ3vqP8pnZ23lHEiFU/4BDnyyINRA7qeVBUo8a2bHKqlyMZooUaZ V0C/giI/+TH76FgaP/RVJr+47x87W9tB8tnXkI7fwJptMgh5FOVwGZHhDleg0K5KXEkp jnXI4N9dXepLbIbY5lerFShW0mHBxcqhFCulpeQDzCZEtN6qIhOhzshvTu73ntQda5qw oCLvTQRCW+meS4UeRstK4uvPWjBO1VJTHTOOkz0ll2mK41p1ikCpGWd1UczRlrzex13r oCYifXZN85gXlJ5GuKpskl5BJNjwOnVAfsvP10YbvS37pBge6kL7O4bu3PYa7zBrKIJY lTrw== X-Gm-Message-State: AOAM5309jSVuxZTEIPK9IZA7zDRTChVanrqTQIolK4a1BDsOTvSKC7JS kVSrdcQOmN3tNyEJMX9TC8g= X-Google-Smtp-Source: ABdhPJxkj3QGNEDLxNtjv59i7QW/MSNjuTtz1x806Ow61CPuMDAsL2PC4eg4KtxBoY5DkUZ1V3gYcQ== X-Received: by 2002:a05:6000:1a88:: with SMTP id f8mr5870764wry.54.1635954262019; Wed, 03 Nov 2021 08:44:22 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id p12sm2767866wrr.10.2021.11.03.08.44.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 03 Nov 2021 08:44:21 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v3 02/11] libtracefs: New APIs for dynamic events Date: Wed, 3 Nov 2021 17:44:08 +0200 Message-Id: <20211103154417.246999-3-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211103154417.246999-1-tz.stoyanov@gmail.com> References: <20211103154417.246999-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 | 19 ++ src/Makefile | 1 + src/tracefs-dynevents.c | 601 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 639 insertions(+) create mode 100644 src/tracefs-dynevents.c diff --git a/include/tracefs-local.h b/include/tracefs-local.h index 684eccf..4d64ad4 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 long type_mask, const char *system); + #endif /* _TRACE_FS_LOCAL_H */ diff --git a/include/tracefs.h b/include/tracefs.h index fa7f316..470234d 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -242,6 +242,25 @@ 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_KPROBE = 0, + TRACEFS_DYNEVENT_KRETPROBE, + TRACEFS_DYNEVENT_UPROBE, + TRACEFS_DYNEVENT_URETPROBE, + TRACEFS_DYNEVENT_EPROBE, + TRACEFS_DYNEVENT_SYNTH, + TRACEFS_DYNEVENT_MAX, +}; +int tracefs_dynevent_create(struct tracefs_dynevent *devent); +int tracefs_dynevent_destroy(struct tracefs_dynevent *devent, bool force); +int tracefs_dynevent_destroy_all(unsigned long type_mask, 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 long type_mask, const char *system); + 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..be2a7a0 --- /dev/null +++ b/src/tracefs-dynevents.c @@ -0,0 +1,601 @@ +// 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" + +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 (*dyn_events_del)(struct dyn_events_desc *desc, struct tracefs_dynevent *dyn); + int (*dyn_events_parse)(struct dyn_events_desc *desc, const char *group, + char *line, struct tracefs_dynevent **ret_dyn); +} dynevents[] = { + {TRACEFS_DYNEVENT_KPROBE, NULL, "p", dyn_generic_del, dyn_generic_parse}, + {TRACEFS_DYNEVENT_KRETPROBE, NULL, "r", dyn_generic_del, dyn_generic_parse}, + {TRACEFS_DYNEVENT_UPROBE, NULL, "p", dyn_generic_del, dyn_generic_parse}, + {TRACEFS_DYNEVENT_URETPROBE, NULL, "r", dyn_generic_del, dyn_generic_parse}, + {TRACEFS_DYNEVENT_EPROBE, NULL, "e", dyn_generic_del, dyn_generic_parse}, + {TRACEFS_DYNEVENT_SYNTH, NULL, "s", dyn_synth_del, dyn_synth_parse}, +}; + +static int dyn_generic_del(struct dyn_events_desc *desc, struct tracefs_dynevent *dyn) +{ + char *str; + int ret; + + if (dyn->system) + ret = asprintf(&str, "-:%s/%s", dyn->system, dyn->event); + else + ret = asprintf(&str, "-:%s", dyn->event); + + if (ret < 0) + return -1; + + ret = tracefs_instance_file_append(NULL, desc->file, str); + free(str); + + return ret < 0 ? ret : 0; +} + +/** + * tracefs_dynevent_free - Free a dynamic event context + * @devent: Pointer to a dynamic event context + * + * The dynamic event, described by this context, is not + * removed from the system by this API. It only frees the memory. + */ +void tracefs_dynevent_free(struct tracefs_dynevent *devent) +{ + if (!devent) + return; + free(devent->system); + free(devent->event); + free(devent->address); + free(devent->format); + free(devent->prefix); + free(devent->trace_file); + free(devent); +} + +static int dyn_generic_parse(struct dyn_events_desc *desc, const char *group, + char *line, struct tracefs_dynevent **ret_dyn) +{ + struct tracefs_dynevent *dyn; + char *format = NULL; + char *address; + char *system; + char *prefix; + char *event; + char *sav; + + if (strncmp(line, desc->prefix, strlen(desc->prefix))) + return -1; + + prefix = strtok_r(line, ":", &sav); + if (!prefix) + return -1; + system = strtok_r(NULL, "/", &sav); + if (!system) + return -1; + event = strtok_r(NULL, " ", &sav); + if (!event) + return -1; + address = strtok_r(NULL, " ", &sav); + if (!address) + address = event + strlen(event) + 1; + else + format = address + strlen(address) + 1; + + /* KPROBEs and UPROBEs share the same prefix, check the format */ + if (desc->type == TRACEFS_DYNEVENT_UPROBE || desc->type == TRACEFS_DYNEVENT_URETPROBE) { + if (!strchr(address, '/')) + return -1; + } + if (group && 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->system = strdup(system); + if (!dyn->system) + goto error; + /* Prefix of KRETPROBE can contain MAXACTIVE integer */ + dyn->prefix = strdup(prefix); + if (!dyn->prefix) + goto error; + dyn->event = strdup(event); + if (!dyn->event) + goto error; + if (desc->type == TRACEFS_DYNEVENT_SYNTH) { + /* Synthetic events have no address */ + dyn->format = strdup(address); + if (!dyn->format) + goto error; + } else { + dyn->address = strdup(address); + if (!dyn->address) + goto error; + if (*format != '\0') { + 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; +} + +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, " ", &sav); + if (!event) + return -1; + + format = event + strlen(event) + 1; + if (*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) != TRACEFS_DYNEVENT_MAX); + + /* Use ftrace dynamic_events, if available */ + if (tracefs_file_exists(NULL, DYNEVENTS_EVENTS)) { + for (i = 0; i < TRACEFS_DYNEVENT_MAX; i++) + dynevents[i].file = DYNEVENTS_EVENTS; + return; + } + + if (tracefs_file_exists(NULL, KPROBE_EVENTS)) { + dynevents[TRACEFS_DYNEVENT_KPROBE].file = KPROBE_EVENTS; + dynevents[TRACEFS_DYNEVENT_KRETPROBE].file = KPROBE_EVENTS; + } + if (tracefs_file_exists(NULL, UPROBE_EVENTS)) { + dynevents[TRACEFS_DYNEVENT_UPROBE].file = UPROBE_EVENTS; + dynevents[TRACEFS_DYNEVENT_URETPROBE].file = UPROBE_EVENTS; + } + if (tracefs_file_exists(NULL, SYNTH_EVENTS)) { + dynevents[TRACEFS_DYNEVENT_SYNTH].file = SYNTH_EVENTS; + dynevents[TRACEFS_DYNEVENT_SYNTH].prefix = ""; + } + +} + +static struct dyn_events_desc *get_devent_desc(enum tracefs_dynevent_type type) +{ + static bool init; + + if (!init) { + init_devent_desc(); + init = true; + } + + return &dynevents[type]; +} + +__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) > 0 ? ":" : "", + 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) > 0 ? ":" : "", + 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->dyn_events_del(desc, devent); +} + +static int get_all_type(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->dyn_events_parse(desc, system, line, ret_all ? &devent : NULL); + if (!ret) { + if (ret_all) { + tmp = realloc(all, (count+1)*sizeof(struct tracefs_dynevent *)); + 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 = 0; + + if (!events) + return; + + while (events[i]) + tracefs_dynevent_free(events[i++]); + + free(events); +} + +/** + * tracefs_dynevent_get_all - return an array of pointers to dynamic events of given types + * @type_mask: Bitmask of tracefs_dynevent_type values. The TRACEFS_BIT_SET macro can be used + * to set the bits of the desired types in the mask. If mask is 0, events from all + * types will be returned. + * @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 long type_mask, const char *system) +{ + struct tracefs_dynevent **events, **tmp, **all_events = NULL; + int count, all = 0; + int i; + + for (i = 0; i < TRACEFS_DYNEVENT_MAX; i++) { + if (type_mask && !TRACEFS_BIT_TEST(type_mask, i)) + continue; + count = get_all_type(i, system, &events); + if (count > 0) { + tmp = realloc(all_events, + (all + count)*sizeof(struct tracefs_dynevent *)); + if (!tmp) + goto error; + all_events = tmp; + memcpy(all_events + all, events, + count*sizeof(struct tracefs_dynevent *)); + all += count; + } + + } + + /* Add a NULL pointer at the end */ + if (all > 0) { + tmp = realloc(all_events, + (all + 1)*sizeof(struct tracefs_dynevent *)); + if (!tmp) + goto error; + + all_events = tmp; + 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 + * @type_mask: Bitmask of tracefs_dynevent_type values. The TRACEFS_BIT_SET macro can be used + * to set the bits of the desired types in the mask. If mask is 0, events from all + * types will be destroyed. + * @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 long type_mask, bool force) +{ + struct tracefs_dynevent **all; + int i = 0; + int ret = 0; + + all = tracefs_dynevent_get_all(type_mask, NULL); + if (!all) + return 0; + while (all[i]) { + if (tracefs_dynevent_destroy(all[i], force)) + ret = -1; + i++; + } + tracefs_dynevent_list_free(all); + + return ret; +} + +__hidden int dynevent_get_count(unsigned long type_mask, const char *system) +{ + int count, all = 0; + int i; + + for (i = 0; i < TRACEFS_DYNEVENT_MAX; i++) { + if (!TRACEFS_BIT_TEST(type_mask, i)) + continue; + count = get_all_type(i, system, NULL); + if (count > 0) + all += count; + } + + return all; +} From patchwork Wed Nov 3 15:44:09 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: 12601039 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 B0D88C433EF for ; Wed, 3 Nov 2021 15:44:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9A3B56109F for ; Wed, 3 Nov 2021 15:44:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229928AbhKCPrB (ORCPT ); Wed, 3 Nov 2021 11:47:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47110 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231814AbhKCPrB (ORCPT ); Wed, 3 Nov 2021 11:47:01 -0400 Received: from mail-wr1-x436.google.com (mail-wr1-x436.google.com [IPv6:2a00:1450:4864:20::436]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 63773C061203 for ; Wed, 3 Nov 2021 08:44:24 -0700 (PDT) Received: by mail-wr1-x436.google.com with SMTP id b12so4260019wrh.4 for ; Wed, 03 Nov 2021 08:44:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=m/FCV/p7IsZ3hsCfrBJPr62lpyUDQdCydkAOXxPmsjI=; b=lSlWPn95Ol4Qg6HcfJfqaHfXWxkKOSvCjr2ZEc+x8aLpjqhgjbRqcrwG2keY2IO2Qb T2k6WtYeecnbaXFc5JYCc39yam9yYmB2qAlS7sgLHqkfhgJcJJOovYPIxgYF7dRvcy1T ozkBKkY7yO5kCimKlaLX90q490jgbVmCP9awnVbJ4p09OawquhF0sXL92qR3ltKfKlWg v/CcOSyrJr1+QIa/zarcBuFmUL6j62rKL1GsesiFRG9YTg0Fb5SReV17OrKhc8vS1BnD q+FErOuzjQVq0K51SuhWvdiM9jCiV6raaazGOAXp+Zs0sezc8gIw+ecR8gj1A94V/odp ZwBw== 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=m/FCV/p7IsZ3hsCfrBJPr62lpyUDQdCydkAOXxPmsjI=; b=yk+5JqewBjPkoDbX4fM4QztoBkrPnWN08vU1IBy3R9Mkp9EMrvUIpodMy8U6ZRlvUh xZ/BORy8hSEpx3loysxTCGJ+qO2PqFfInWbuA+sOM1VRv8bJ5dNS9A6PMdCMgFqSfGU8 oB44wXTK13Kx9olQC3ESBufLkj94W9wQYXYKP4ABpW586jixIwQXKy6khQR/mhuo9vKs syZ4ec4Jkc8FDueaVAGxLrNigNpKn+Y5zL0F4YE5SsjCx3uXCI4VW9zn2o4eH6Vmqb1O 0t0/NBNDIE+QTsmhej1EiXvoaQStLp9pRSMcSnyMpKj9Im5ebUCufLUg2pdUAcUWtkjg Fnsg== X-Gm-Message-State: AOAM533kSvfW10onenvNP/Z3M58PTmVv3DaW6zjSgQ8YHlSIXcXMgd3e QH+AAjok3h5CGbQoP7+iXX4= X-Google-Smtp-Source: ABdhPJyJAKC3ucZDyMF9C52n6AvgKgvirIfJc09jgimbvjIlOpE69hc+RHyeaUvOAva3FWwXEHfsQQ== X-Received: by 2002:a5d:4e52:: with SMTP id r18mr30852054wrt.224.1635954262879; Wed, 03 Nov 2021 08:44:22 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id p12sm2767866wrr.10.2021.11.03.08.44.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 03 Nov 2021 08:44:22 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v3 03/11] libtracefs: New APIs for kprobe allocation Date: Wed, 3 Nov 2021 17:44:09 +0200 Message-Id: <20211103154417.246999-4-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211103154417.246999-1-tz.stoyanov@gmail.com> References: <20211103154417.246999-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 | 105 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/include/tracefs.h b/include/tracefs.h index 470234d..b8f7c09 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, 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..d1279ff 100644 --- a/src/tracefs-kprobes.c +++ b/src/tracefs-kprobes.c @@ -20,6 +20,111 @@ #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, int max) +{ + struct tracefs_dynevent *kp; + int ret; + + kp = kprobe_alloc(TRACEFS_DYNEVENT_KRETPROBE, system, event, addr, format); + if (!kp) + return NULL; + if (max) { + 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 Wed Nov 3 15:44:10 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: 12601043 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 09131C433F5 for ; Wed, 3 Nov 2021 15:44:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E167D61076 for ; Wed, 3 Nov 2021 15:44:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231843AbhKCPrC (ORCPT ); Wed, 3 Nov 2021 11:47:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47130 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231814AbhKCPrC (ORCPT ); Wed, 3 Nov 2021 11:47:02 -0400 Received: from mail-wr1-x433.google.com (mail-wr1-x433.google.com [IPv6:2a00:1450:4864:20::433]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6EDF3C061714 for ; Wed, 3 Nov 2021 08:44:25 -0700 (PDT) Received: by mail-wr1-x433.google.com with SMTP id s13so4274239wrb.3 for ; Wed, 03 Nov 2021 08:44:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=lnVE59onQOLIl9fFs9ZtirZV6E+WBa281mt3cuvQw8g=; b=LbcmLIwBMOoQ3okcnP4YSjQ8ov92N7WHrzsgNe+TzwxARm9gO/ygx+XcCP/tQRphEC brURkc7LykDB/bn7SZrBXhSHpbMpi8UFzu2koMM/nhEPpKt+++tjKNufvz7nb7Zyet1U U30GN5ukt67wIBPqZGETtQSTJiBaxlQx7vQIxPBK//kOkPafcvCgi4v4o6pQT5ZNIRbw 6Bdl9+XbFOWt7cBbRkSKqjqdUZzr7s7chLbTJjBk7OW/EAASWD3syAfizweBc238kGyW 4ZKAHLwBr/toNTwOruo3uA+Zm5orrwVuU+hq4VrfLlzfslW8MM1Q0sATInLZThB86xSG GNxg== 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=lnVE59onQOLIl9fFs9ZtirZV6E+WBa281mt3cuvQw8g=; b=e/1Bv+QRnYM0e+Mr1vh0ibRfE0uoa5J0G5+1rQvSl0ehbNh0w+AmiDkM1SB3eK4Q7j Gye46My89Txk1luWR1WlFqocQY8eP5/CyfRjK1Snx8xqv8sML0QoFKDSnEkaF5O+kMRD xWEmPvm+0LkvOfQf3eHfZrOoQ8bu8IggjfBNLe9RmDh/rCnOZIY+W7hCJ8YCb7J5Az7w YVWEuV6FnNxKWJEMQqKwgtloUWtqzieOa1BqU+NrZ6+cGYeMaY4WHhF+ZVEGPeiyf00P FwrV0K3AESn9jktIl8XNDHKNrq5KyKPU26LoJzQfPQKI9AExK072kAecjtE+KhTgpnBW gPxQ== X-Gm-Message-State: AOAM532DuFj4T4cDATpV3uuY2PQyM2n/Fouh03U0djYXAEhnF4VAeGVS opNtlmBjozx8M3ZPYRmgW2k= X-Google-Smtp-Source: ABdhPJz39L5DF1moKRIusu0b4yNcV8Y5P8axLsmWrBfRh77li1GYDyL5Smf29+u3O6eECj6iojsaZQ== X-Received: by 2002:a5d:4582:: with SMTP id p2mr28356862wrq.364.1635954263973; Wed, 03 Nov 2021 08:44:23 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id p12sm2767866wrr.10.2021.11.03.08.44.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 03 Nov 2021 08:44:23 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v3 04/11] libtracefs: Remove redundant kprobes APIs Date: Wed, 3 Nov 2021 17:44:10 +0200 Message-Id: <20211103154417.246999-5-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211103154417.246999-1-tz.stoyanov@gmail.com> References: <20211103154417.246999-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() 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 | 3 - src/tracefs-kprobes.c | 247 ------------------------------------------ 2 files changed, 250 deletions(-) diff --git a/include/tracefs.h b/include/tracefs.h index b8f7c09..6bf45c3 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -276,11 +276,8 @@ 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 d1279ff..72a4a35 100644 --- a/src/tracefs-kprobes.c +++ b/src/tracefs-kprobes.c @@ -262,80 +262,6 @@ static int parse_kprobe(char *content, char **saveptr, 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") @@ -406,176 +332,3 @@ enum tracefs_kprobe_type tracefs_kprobe_info(const char *group, const char *even 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 Wed Nov 3 15:44:11 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: 12601045 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 CBF7AC433FE for ; Wed, 3 Nov 2021 15:44:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B471B610EA for ; Wed, 3 Nov 2021 15:44:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231874AbhKCPrD (ORCPT ); Wed, 3 Nov 2021 11:47:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47136 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231856AbhKCPrD (ORCPT ); Wed, 3 Nov 2021 11:47:03 -0400 Received: from mail-wm1-x332.google.com (mail-wm1-x332.google.com [IPv6:2a00:1450:4864:20::332]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6FA20C061714 for ; Wed, 3 Nov 2021 08:44:26 -0700 (PDT) Received: by mail-wm1-x332.google.com with SMTP id c71-20020a1c9a4a000000b0032cdcc8cbafso2173145wme.3 for ; Wed, 03 Nov 2021 08:44:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Ip4dlo5AYQ4QHnMXw18iYgumz2fdqoA8+XnbhNcOLUw=; b=dQikdMelrDU1B2XA/JCYNB9kAPsKq04wrtbApVkU5ZlvuiQjPaOpckvXYYvU61S58c WjcLKiZuoexOpaldnUBJbOaLt+3frWvaTg8CyhxQEjguBL+dqodhZeX2b89+2KE0asTI V0zeIum3S4RsNywyNeMA5OEn+5q6N9eB0xa3gnTiMIe5lMjkBAxl8Wk9plXGaELygMC6 SF2/hvtnGkNBoymGbeunewW7UlROsZ99mGieH4pGRs7REwwVa2p+Y9K10z/TP0oIGm49 +q9RgesLLBtIAqBkikJ55tSu4mCm8tbow3NXCvhlwyq1Z5DPWrpeL5gmiAl5TOzzbIaO FrAg== 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=Ip4dlo5AYQ4QHnMXw18iYgumz2fdqoA8+XnbhNcOLUw=; b=uVY+UNxmARMoHicI2sTz0gMaQH4fowxXzDVmg/ZZpVtPCR8BVhsukhGZMsOHeN29pT e+N67lq5PnDYFGLB6j7cpqlZBqnAs+P8krHy5g/nYUTQenA54L9em5tS4KIV2gonGJXm EFJtua6K0HPnZU6quyD1xcGDMpMo8GC8vDDUlzRmE9bSEzzEZAcLnCbcFe+2v/jGs6P7 tYcWXyAmFKNYuLnU2oEu8ZAEj4oYdi7ME5kx+hiq9je6BXCMczt+1oYcbIoJOdVpNRfX 32u57QyDMp6ed189maSIW9zKy/cTvfvuui58cEBqID9LQqxbwF0ToX/RaB87nMMc1CJV DIIw== X-Gm-Message-State: AOAM533MRockvD5Uv8Jf/r9gt7il4D/NYTOgobiS1pHPko0w+6PtynKn bP5oCkhutg+cpveoYXRC1YK3p5W+l2hilg== X-Google-Smtp-Source: ABdhPJxRhQo9NQ3RKnuoBB5TWHarvYAi1RRM5gav+2gVP2MeZx1EGWK1garQHBM1Hdk8YPq9M00chQ== X-Received: by 2002:a1c:1d42:: with SMTP id d63mr15869501wmd.184.1635954264932; Wed, 03 Nov 2021 08:44:24 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id p12sm2767866wrr.10.2021.11.03.08.44.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 03 Nov 2021 08:44:24 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v3 05/11] libtracefs: Change tracefs_kprobe_info API Date: Wed, 3 Nov 2021 17:44:11 +0200 Message-Id: <20211103154417.246999-6-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211103154417.246999-1-tz.stoyanov@gmail.com> References: <20211103154417.246999-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 make kprobe APIs consistent with the other libtracefs APIs, the tracefs_kprobe_info() API is reimplemented and changed to work with the library dynamic event structure. Signed-off-by: Tzvetomir Stoyanov (VMware) --- include/tracefs.h | 11 +-- src/tracefs-kprobes.c | 172 ++++++++++++++++-------------------------- 2 files changed, 66 insertions(+), 117 deletions(-) diff --git a/include/tracefs.h b/include/tracefs.h index 6bf45c3..8ff9d12 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -261,12 +261,6 @@ void tracefs_dynevent_list_free(struct tracefs_dynevent **events); struct tracefs_dynevent ** tracefs_dynevent_get_all(unsigned long type_mask, const char *system); -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,8 +270,9 @@ 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); -enum tracefs_kprobe_type tracefs_kprobe_info(const char *group, const char *event, - char **type, char **addr, char **format); +enum tracefs_dynevent_type tracefs_kprobe_info(struct tracefs_dynevent *kprobe, + char **system, char **event, + char **prefix, char **addr, char **format); enum tracefs_hist_key_type { TRACEFS_HIST_KEY_NORMAL = 0, diff --git a/src/tracefs-kprobes.c b/src/tracefs-kprobes.c index 72a4a35..eb71df3 100644 --- a/src/tracefs-kprobes.c +++ b/src/tracefs-kprobes.c @@ -210,125 +210,79 @@ 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_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. + * tracefs_kprobe_info - return details of a kprobe + * @kprobe: A kprobe context, describing given kprobe. + * @group: return, group in which the kprobe is configured + * @event: return, name of the kprobe event + * @prefix: return, prefix string of the kprobe + * for kretprobes, the maxactive count is encoded in the prefix + * @addr: return, the function and offset (or address) of the kprobe + * @format: return, the format string of the kprobe * - * 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. + * Returns the type of the kprobe, or TRACEFS_DYNEVENT_MAX 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_kprobe_type tracefs_kprobe_info(const char *group, const char *event, - char **type, char **addr, char **format) +enum tracefs_dynevent_type tracefs_kprobe_info(struct tracefs_dynevent *kprobe, + char **system, char **event, + char **prefix, 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 (system) + *system = NULL; + if (event) + *event = NULL; + if (prefix) + *prefix = 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); + if (!kprobe) + return TRACEFS_DYNEVENT_MAX; - switch (*ktype) { - case 'p': rtype = TRACEFS_KPROBE; break; - case 'r': rtype = TRACEFS_KRETPROBE; break; - } - break; + if (system) { + if (kprobe->system) { + *system = strdup(kprobe->system); + if (!(*system)) + goto error; } - ret = parse_kprobe(NULL, &saveptr, &ktype, &system, &probe, - &kaddr, &kfmt); } - free(content); - return rtype; + if (event) { + *event = strdup(kprobe->event); + if (!(*event)) + goto error; + } + if (prefix) { + *prefix = strdup(kprobe->prefix); + if (!(*prefix)) + goto error; + } + if (addr && kprobe->address) { + *addr = strdup(kprobe->address); + if (!(*addr)) + goto error; + } + if (format && kprobe->format) { + *format = strdup(kprobe->format); + if (!(*format)) + goto error; + } + + return kprobe->type; + +error: + if (system) + free(*system); + if (event) + free(*event); + if (prefix) + free(*prefix); + if (addr) + free(*addr); + if (format) + free(*format); + return TRACEFS_DYNEVENT_MAX; } From patchwork Wed Nov 3 15:44:12 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: 12601047 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 79C40C433EF for ; Wed, 3 Nov 2021 15:44:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 67A196109F for ; Wed, 3 Nov 2021 15:44:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231860AbhKCPrF (ORCPT ); Wed, 3 Nov 2021 11:47:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47146 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231814AbhKCPrE (ORCPT ); Wed, 3 Nov 2021 11:47:04 -0400 Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com [IPv6:2a00:1450:4864:20::32d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9A45CC061714 for ; Wed, 3 Nov 2021 08:44:27 -0700 (PDT) Received: by mail-wm1-x32d.google.com with SMTP id f7-20020a1c1f07000000b0032ee11917ceso2211804wmf.0 for ; Wed, 03 Nov 2021 08:44:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=sSMAJ01LS/y7mukHCTMxlvD1U2S16GHAhL8uRiol210=; b=CCbjLkAG7mlq2RXc+iGZUcKDEb78z5M2mo8pz9enVvWN8hCx20ic6c6pccBiAHMArB uQXZvcbFmR77WtwwbLpZtTbdW2H+cK32dW4rkICeelIfkOzLGd+Im6DE/9xi2PkYfzlh KJPX2RFYDZMI3QSReTYh4q9xWemr0eXgfXyfGaZJXqQ1md/+uj2IHgIXS7m8thx9nB4P Tgr6m5rQOpj0jyyoh7QAyytr2uC5O7g2uS0BxeOf0jSU/JRHjrbRaGG32pUKwh/TDZ8G pr4mOeNPqZ6qMsB2TknZGArvqrK4Qx1BsvgCspCtUldu/5d4JMOQIKcIZNs7Y8RQOgWP GmMA== 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=sSMAJ01LS/y7mukHCTMxlvD1U2S16GHAhL8uRiol210=; b=AqBh9aQC6h/dJ327MbFuZ4+0CJZW5iHgKoCPFXASS+ivlkxi1ZMSJ3ty3bGMT/xUg7 D716OR+F9i0y8KvH8BD0t6PJA6Vs5He7Et/rnV8qnPQAjz+JrHOXj3RKgz5Cr1HBwAwF sDCUMHwPi0ZWF0L4m4lH0qy0gcbQeYyoe30JyIePw18BYxnXluLMZCSqH9evyvfH72GT gPCOnd8gRsjhY1z3qe1fn87su187lNunzvuNP8Hu9XSnJ1/hVH/yz0yLBE/s/O7MWmOp IISfaQN2A52vkmjJTOQnAdykDjp+1D09i9tvVdR/GDvAPiTMJcTHbtEaly3uzkkF+/3o ecIg== X-Gm-Message-State: AOAM533u/dPVKaAyiUdni4apvXVOTGY2SLmS6MV+m6QZdIZ6vS7k4jtN 2KbbZDHM3844hSfFrJblj8c= X-Google-Smtp-Source: ABdhPJxUp4l017Z3LxXIDdNt72zURp/OZYw7qInNtacqxiOdsSKXWNDj8Z5rSn2lbB9f4ILZc+pDzQ== X-Received: by 2002:a1c:9851:: with SMTP id a78mr15939963wme.116.1635954266187; Wed, 03 Nov 2021 08:44:26 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id p12sm2767866wrr.10.2021.11.03.08.44.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 03 Nov 2021 08:44:25 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v3 06/11] libtracefs: Reimplement kprobe raw APIs Date: Wed, 3 Nov 2021 17:44:12 +0200 Message-Id: <20211103154417.246999-7-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211103154417.246999-1-tz.stoyanov@gmail.com> References: <20211103154417.246999-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 eb71df3..767a878 100644 --- a/src/tracefs-kprobes.c +++ b/src/tracefs-kprobes.c @@ -125,37 +125,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; } /** @@ -181,7 +164,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); } /** @@ -207,7 +190,7 @@ 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 Wed Nov 3 15:44:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 12601049 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 3BA33C433FE for ; Wed, 3 Nov 2021 15:44:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 223EE6109F for ; Wed, 3 Nov 2021 15:44:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231814AbhKCPrG (ORCPT ); Wed, 3 Nov 2021 11:47:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47160 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231877AbhKCPrF (ORCPT ); Wed, 3 Nov 2021 11:47:05 -0400 Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com [IPv6:2a00:1450:4864:20::32d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AB987C061714 for ; Wed, 3 Nov 2021 08:44:28 -0700 (PDT) Received: by mail-wm1-x32d.google.com with SMTP id z200so2325507wmc.1 for ; Wed, 03 Nov 2021 08:44:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=qQ0sZ2dDwBpprPA0s279wFEVczh2Thbc9T6dMutfR8M=; b=ct8/+5zgKeB9+z9LSTzqcgIQf0GV4Em4TVrdqvJ5gsT6t5bnK0tGLkMzFzTM0hCgCf /iYjJJKvoAtZYveCG3ocCwz6XaP3xX04YeQAJMWbfUPLS6u9tDofkHGjhPWwdfVE0CYR cS2F2PnPaJ9g74XSvDM23AEZGN5/N8JWFORaz3koeynnFPDMkGcz2OGOwK+SmnG+KbZ8 scgeaq8jGSD1VpPg28Q9RLGJEgtvVE0v/BKr8vP1/JG8sT8F/29VW+nsun9EaXmkdYhI lHhUpWMX4y6y2FkwVkXLVwA8sDNAGbXwJmEpwBfe7gtx9l0naSRwUJ4eh065fvw/dmQ8 7Skw== 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=qQ0sZ2dDwBpprPA0s279wFEVczh2Thbc9T6dMutfR8M=; b=422qsdz5ZlNpqaKfPoobz2GZErt6AyZpG8/5lCcINOo1UUhv+CmdaqOPExQQ6zYEUN VWhuRVvImUF5DhekQm+mlw2+XZRON9PL01I04Z5jqUmqbl59UW6S6Fyb3wMHJRv4PWh5 k/ps5eIs+wNpnky+Gu3clpKHzqH+3ReS6FGxTiUiaLJrKqhTLbhKk7VSpsqIw29cFlz8 FLR9kScCwVV1hlZBsDaj4wVf05hlfj7pXtk95W161HOfO+mREmJEaasv6BI+a6ekxqUf Ec5mnMoseuRImNqDJR1GxlFgvpebYU6UrPEH23bAuzLyjcnZ+eeaXNhtFFUOsLJZFNFQ 7WCQ== X-Gm-Message-State: AOAM530SZcwpY9cVLc69A6Th5ViYjrYHg/lrlBfyl1rlZXC50KqMUfaF 9ePw6nil8uHnWzCu86hWBVw= X-Google-Smtp-Source: ABdhPJxyzojTVzFdCaQNbLjrJ2svJUNx7SCvXTpWHXoP2jmeQUtR7PU18S+rOZVpZ1Yp7FFSwIwiDw== X-Received: by 2002:a1c:ed03:: with SMTP id l3mr16582473wmh.86.1635954267220; Wed, 03 Nov 2021 08:44:27 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id p12sm2767866wrr.10.2021.11.03.08.44.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 03 Nov 2021 08:44:26 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v3 07/11] libtracefs: Extend kprobes unit test Date: Wed, 3 Nov 2021 17:44:13 +0200 Message-Id: <20211103154417.246999-8-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211103154417.246999-1-tz.stoyanov@gmail.com> References: <20211103154417.246999-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 | 417 +++++++++++++++++++++++++----------------- 1 file changed, 247 insertions(+), 170 deletions(-) diff --git a/utest/tracefs-utest.c b/utest/tracefs-utest.c index 09bb8f2..431ae15 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" @@ -457,28 +441,267 @@ static void test_instance_file_read(struct tracefs_instance *inst, const char *f free(file); } +#define KPROBE_DEFAULT_GROUP "kprobes" +struct kprobe_test { + enum tracefs_dynevent_type type; + char *prefix; + char *system; + char *event; + char *address; + char *format; +}; + +static bool check_kprobes(struct kprobe_test *kprobes, int count, + struct tracefs_dynevent **devents, bool in_system) +{ + + enum tracefs_dynevent_type ktype; + char *ename; + char *kaddress; + char *kevent; + char *ksystem; + char *kformat; + char *kprefix; + int found = 0; + int ret; + int i, j; + + for (i = 0; devents[i]; i++) { + ktype = tracefs_kprobe_info(devents[i], &ksystem, + &kevent, &kprefix, &kaddress, &kformat); + for (j = 0; j < count; j++) { + if (ktype != kprobes[j].type) + continue; + if (kprobes[j].event) + ename = kprobes[j].event; + else + ename = kprobes[j].address; + if (strcmp(ename, kevent)) + continue; + if (kprobes[j].system) { + CU_TEST(strcmp(kprobes[j].system, ksystem) == 0); + } else { + CU_TEST(strcmp(KPROBE_DEFAULT_GROUP, ksystem) == 0); + } + CU_TEST(strcmp(kprobes[j].address, kaddress) == 0); + if (kprobes[j].format) { + CU_TEST(strcmp(kprobes[j].format, kformat) == 0); + } + if (kprobes[j].prefix) { + CU_TEST(strcmp(kprobes[j].prefix, kprefix) == 0); + } + ret = tracefs_event_enable(test_instance, ksystem, kevent); + if (in_system) { + CU_TEST(ret == 0); + } else { + CU_TEST(ret != 0); + } + ret = tracefs_event_disable(test_instance, ksystem, kevent); + if (in_system) { + CU_TEST(ret == 0); + } else { + CU_TEST(ret != 0); + } + + found++; + break; + } + free(ksystem); + free(kevent); + free(kprefix); + free(kaddress); + free(kformat); + } + + CU_TEST(found == count); + if (found != count) + return false; + + return true; +} + +static struct tracefs_dynevent **get_kprobes_check(enum tracefs_dynevent_type type, int count) +{ + struct tracefs_dynevent **devents; + int mask = 0; + int i; + + if (TRACEFS_DYNEVENT_KPROBE == type || TRACEFS_DYNEVENT_MAX == type) + TRACEFS_BIT_SET(mask, TRACEFS_DYNEVENT_KPROBE); + if (TRACEFS_DYNEVENT_KRETPROBE == type || TRACEFS_DYNEVENT_MAX == type) + TRACEFS_BIT_SET(mask, TRACEFS_DYNEVENT_KRETPROBE); + devents = tracefs_dynevent_get_all(mask, NULL); + if (count) { + CU_TEST(devents != NULL); + i = 0; + while (devents[i]) + i++; + CU_TEST(i == count); + } else { + CU_TEST(devents == NULL); + } + + return devents; +} + +#define KPROBE_COUNT 3 +#define KRETPROBE_COUNT 2 +static void test_kprobes(void) +{ + struct kprobe_test ktests[KPROBE_COUNT] = { + { TRACEFS_DYNEVENT_KPROBE, "p", NULL, "mkdir", "do_mkdirat", "path=+u0($arg2):ustring" }, + { TRACEFS_DYNEVENT_KPROBE, "p", NULL, "close", "close_fd", NULL }, + { TRACEFS_DYNEVENT_KPROBE, "p", "ptest", "open2", "do_sys_openat2", + "file=+u0($arg2):ustring flags=+0($arg3):x64" }, + }; + struct kprobe_test kretests[KRETPROBE_COUNT] = { + { TRACEFS_DYNEVENT_KRETPROBE, NULL, NULL, "retopen", "do_sys_openat2", "ret=$retval" }, + { TRACEFS_DYNEVENT_KRETPROBE, NULL, NULL, NULL, "do_sys_open", "ret=$retval" }, + }; + struct tracefs_dynevent *dkretprobe[KRETPROBE_COUNT + 1]; + struct tracefs_dynevent *dkprobe[KPROBE_COUNT + 1]; + struct tracefs_dynevent **devents; + int all_mask = 0; + char *tmp; + int ret; + int i; + + TRACEFS_BIT_SET(all_mask, TRACEFS_DYNEVENT_KPROBE); + TRACEFS_BIT_SET(all_mask, TRACEFS_DYNEVENT_KRETPROBE); + + /* 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_kprobe_info(NULL, &tmp, &tmp, &tmp, &tmp, &tmp) == TRACEFS_DYNEVENT_MAX); + CU_TEST(tracefs_kprobe_raw("test", "test", NULL, "test") != 0); + CU_TEST(tracefs_kretprobe_raw("test", "test", NULL, "test") != 0); + CU_TEST(tracefs_kprobe_raw("test", "test", "test", NULL) != 0); + CU_TEST(tracefs_kretprobe_raw("test", "test", "test", NULL) != 0); + + /* kprobes APIs */ + ret = tracefs_dynevent_destroy_all(all_mask, true); + CU_TEST(ret == 0); + get_kprobes_check(TRACEFS_DYNEVENT_MAX, 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_kprobes_check(TRACEFS_DYNEVENT_MAX, 0); + CU_TEST(check_kprobes(ktests, KPROBE_COUNT, dkprobe, false)); + + 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_kprobes_check(TRACEFS_DYNEVENT_MAX, 0); + CU_TEST(check_kprobes(kretests, KRETPROBE_COUNT, dkretprobe, false)); + + for (i = 0; i < KPROBE_COUNT; i++) { + CU_TEST(tracefs_dynevent_create(dkprobe[i]) == 0); + } + devents = get_kprobes_check(TRACEFS_DYNEVENT_MAX, KPROBE_COUNT); + CU_TEST(check_kprobes(ktests, KPROBE_COUNT, devents, true)); + CU_TEST(check_kprobes(kretests, KRETPROBE_COUNT, dkretprobe, false)); + tracefs_dynevent_list_free(devents); + devents = NULL; + + for (i = 0; i < KRETPROBE_COUNT; i++) { + CU_TEST(tracefs_dynevent_create(dkretprobe[i]) == 0); + } + devents = get_kprobes_check(TRACEFS_DYNEVENT_MAX, KPROBE_COUNT + KRETPROBE_COUNT); + CU_TEST(check_kprobes(ktests, KPROBE_COUNT, devents, true)); + CU_TEST(check_kprobes(kretests, KRETPROBE_COUNT, devents, true)); + 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_kprobes_check(TRACEFS_DYNEVENT_MAX, KPROBE_COUNT); + CU_TEST(check_kprobes(ktests, KPROBE_COUNT, devents, true)); + CU_TEST(check_kprobes(kretests, KRETPROBE_COUNT, dkretprobe, false)); + tracefs_dynevent_list_free(devents); + devents = NULL; + + for (i = 0; i < KPROBE_COUNT; i++) { + CU_TEST(tracefs_dynevent_destroy(dkprobe[i], false) == 0); + } + get_kprobes_check(TRACEFS_DYNEVENT_MAX, 0); + CU_TEST(check_kprobes(ktests, KPROBE_COUNT, dkprobe, false)); + CU_TEST(check_kprobes(kretests, KRETPROBE_COUNT, dkretprobe, false)); + 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(all_mask, true); + CU_TEST(ret == 0); + get_kprobes_check(TRACEFS_DYNEVENT_MAX, 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_kprobes_check(TRACEFS_DYNEVENT_KPROBE, KPROBE_COUNT); + CU_TEST(check_kprobes(ktests, KPROBE_COUNT, devents, true)); + 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_kprobes_check(TRACEFS_DYNEVENT_KPROBE, KPROBE_COUNT); + CU_TEST(check_kprobes(ktests, KPROBE_COUNT, devents, true)); + tracefs_dynevent_list_free(devents); + devents = NULL; + + devents = get_kprobes_check(TRACEFS_DYNEVENT_KRETPROBE, KRETPROBE_COUNT); + CU_TEST(check_kprobes(kretests, KRETPROBE_COUNT, devents, true)); + tracefs_dynevent_list_free(devents); + devents = NULL; + + devents = get_kprobes_check(TRACEFS_DYNEVENT_MAX, KPROBE_COUNT + KRETPROBE_COUNT); + CU_TEST(check_kprobes(ktests, KPROBE_COUNT, devents, true)); + CU_TEST(check_kprobes(kretests, KRETPROBE_COUNT, devents, true)); + tracefs_dynevent_list_free(devents); + devents = NULL; + + ret = tracefs_dynevent_destroy_all(all_mask, true); + CU_TEST(ret == 0); + get_kprobes_check(TRACEFS_DYNEVENT_MAX, 0); +} + 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 +764,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 +1518,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 Wed Nov 3 15:44:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 12601051 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 C2281C433F5 for ; Wed, 3 Nov 2021 15:44:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AABE06023E for ; Wed, 3 Nov 2021 15:44:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231877AbhKCPrG (ORCPT ); Wed, 3 Nov 2021 11:47:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47162 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231876AbhKCPrG (ORCPT ); Wed, 3 Nov 2021 11:47:06 -0400 Received: from mail-wm1-x32f.google.com (mail-wm1-x32f.google.com [IPv6:2a00:1450:4864:20::32f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 94626C061714 for ; Wed, 3 Nov 2021 08:44:29 -0700 (PDT) Received: by mail-wm1-x32f.google.com with SMTP id f7-20020a1c1f07000000b0032ee11917ceso2211902wmf.0 for ; Wed, 03 Nov 2021 08:44:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=M3ggEzeCUo4hp56OrMsHEbxHXlYaNvdo6FJoU+100xo=; b=hWtbH8FqUVTwp+3jYv0paVgifqjbK3z3D/alMXPsrxvAcIdJ+/v0q+FTC3o8q/eJKC ehPnlMPGHUL/c77V5lshbOjSOXfzCkWDe+iGLGvlDVC0Pkh+MmwEfmNmVk3uVm3Kj+86 pCkajqchCuilnnRbnhpkJyr7CClq6L7cNlKaxoJU9tbn0qtrRSuKkdkZ1dCX871pdeK6 gxCKR9kZ1T67mVAgWaEDj+HpGZByCuoBEI5kSW5z8wkrhcp0/IAk8oQEbH+eKlVWHmdg T4bUEl9MaUwaZDsdbte7cBf7bbYkrKOzq3/DPICb7bYvy7wlfOB4w86xKJHYMGs8g3Zs FMYw== 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=M3ggEzeCUo4hp56OrMsHEbxHXlYaNvdo6FJoU+100xo=; b=TmKloSowyvQeqqu5Jto724LZ0lrfSq8bPQAR6bl7SJ2ouJB7OMWT1qRvuHAi7559KC kmsshCNWxb5glLCxRvUKMB5JniQCRzvqphs0NMVrTUFYcz+q3xs/19K2PcS2mpEGmDLc 3UEzS2sb45bIKlP2kmCkSC0hDp250W/4//pZB28Z8sTqrYL4GRAxAZZrVesP5NZpssqq 4TRaDNJYnUjxEaD3Ck0kTV13FEAnEqeJYdoZ1zYUi9CABbP22ZzPUsZ13fgarU68d4Bd ipBtiHKsKKOBrfwKr2J/PwHVs395YizSNsKQcMzRJybZ4nQa11v6wXmiA7HueCDRvh+5 HCOA== X-Gm-Message-State: AOAM530GbZa+LxRnud4bfkTY5OCPQ11AnaJ1e56xCurUsjhl1hGWk1I8 /zfq6zvUS/pUligPL8kHvCg= X-Google-Smtp-Source: ABdhPJzhxwd8kE72WsE4kf0ZL4gUuSO3CCcwBP+TiLiX9+qhmeQmYdDfbgCZWSTcUcDZMJciedTLcw== X-Received: by 2002:a1c:4e04:: with SMTP id g4mr15688742wmh.15.1635954268135; Wed, 03 Nov 2021 08:44:28 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id p12sm2767866wrr.10.2021.11.03.08.44.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 03 Nov 2021 08:44:27 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v3 08/11] libtracefs: Rename tracefs_synth_init API Date: Wed, 3 Nov 2021 17:44:14 +0200 Message-Id: <20211103154417.246999-9-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211103154417.246999-1-tz.stoyanov@gmail.com> References: <20211103154417.246999-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 8ff9d12..67c7af1 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -482,15 +482,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 Wed Nov 3 15:44:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 12601053 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 B2AF4C433EF for ; Wed, 3 Nov 2021 15:44:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9B866610FC for ; Wed, 3 Nov 2021 15:44:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231878AbhKCPrH (ORCPT ); Wed, 3 Nov 2021 11:47:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47170 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231876AbhKCPrH (ORCPT ); Wed, 3 Nov 2021 11:47:07 -0400 Received: from mail-wm1-x32f.google.com (mail-wm1-x32f.google.com [IPv6:2a00:1450:4864:20::32f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B585DC061714 for ; Wed, 3 Nov 2021 08:44:30 -0700 (PDT) Received: by mail-wm1-x32f.google.com with SMTP id d72-20020a1c1d4b000000b00331140f3dc8so2186124wmd.1 for ; Wed, 03 Nov 2021 08:44:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=x3VwFCoyTfqgVhXpSDmiowloIpFHoLKymQedOdiM59w=; b=NQs/X2LB1g+ic/oyBfnHvybg1z2kcs55DDbIJuJ60nQbELO2GaukrWfnIryyegVX37 kpwaiLEfSctqIqiT758BY1hnyzW8LBruOog3g4dSDREfmdhTeqNXatbJk/k7U57az5y7 mnYDl9yHmOgwNTWWS8uEEo41uDnO4gg6IVa/s/YngZqNOKtw9ixmabYcJweAbQQZ3+Ik ugIs+dEAkWqZ/KsMAsfClFV45Fi7D+TqsoVhJhbLQHN66akUGjbgt2JO+7bXCl+CEyrd 5RoUIrGf2rFP2v4CXo+QtJ61bFfwLGRz1Q304tgk4haF3UrrgIg3/HamUhr4lzDNmo7B Vn/Q== 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=x3VwFCoyTfqgVhXpSDmiowloIpFHoLKymQedOdiM59w=; b=zhzhUZclcjxVCHR/Xpk6EC1j1P25Wvf7603pQXiuebhUU7MnRSgEUga8nqUgTZnnDg KtO4Y1T9UVzdzUfULDndGzIZPLli1pMednJ63JL2pCLMGuQ3jWFCaawJpVt7HCGzv9Fw OId9uiqtZ0DAdkvyREhAlnCFHlW9jP4VzBb4mH4t4OBrRi4WE0J73wQ2Z2vBLdX4Xw3u 4cRGkGpxKNeqqFf3hyqaVI6XQ/hZ9/YQuguhrfOBBE1ThCvNmjYPnG5J/+qqkFnCIVRF MlYUmT6dFstvuGRz4G4zoC5i6kbQsGZQMgF6Qg/2UgnwCszibhSyUSKbPCz1KEF2PvUN RjIg== X-Gm-Message-State: AOAM532Mqq2Ptc0FAHZfojtxOq51F+frsuZaTYNNr4YFghUwjalWOxHZ BeRRoxr64KZZxd+zQaBvd8c= X-Google-Smtp-Source: ABdhPJz87NXv8v7nMninUtI+S4fprozczPP9ajbgKLy3kGy/e4wtta5xJaq7YOTgqjkvI8ouROLuXQ== X-Received: by 2002:a05:600c:358e:: with SMTP id p14mr4593952wmq.76.1635954269274; Wed, 03 Nov 2021 08:44:29 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id p12sm2767866wrr.10.2021.11.03.08.44.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 03 Nov 2021 08:44:28 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v3 09/11] libtracefs: Use the internal dynamic events API when creating synthetic events Date: Wed, 3 Nov 2021 17:44:15 +0200 Message-Id: <20211103154417.246999-10-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211103154417.246999-1-tz.stoyanov@gmail.com> References: <20211103154417.246999-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 | 103 +++++++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 56 deletions(-) diff --git a/src/tracefs-hist.c b/src/tracefs-hist.c index 9009dba..08bb2da 100644 --- a/src/tracefs-hist.c +++ b/src/tracefs-hist.c @@ -661,6 +661,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 +720,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 +891,28 @@ synth_init_from(struct tep_handle *tep, const char *start_system, return synth; } +static int alloc_synthetic_event(struct tracefs_synth *synth) +{ + char *synthetic_format; + const char *field; + int i; + + synthetic_format = strdup(""); + if (!synthetic_format) + return -1; + + for (i = 0; synth->synthetic_fields && synth->synthetic_fields[i]; i++) { + field = synth->synthetic_fields[i]; + synthetic_format = append_string(synthetic_format, " ", field); + } + + synth->dyn_event = dynevent_alloc(TRACEFS_DYNEVENT_SYNTH, NULL, + synth->name, NULL, synthetic_format); + free(synthetic_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 +1633,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 +1911,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 +1928,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 +1967,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 +1992,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 +2025,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, false); return ret ? -1 : 0; } @@ -2067,7 +2047,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 +2062,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 +2099,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 Wed Nov 3 15:44:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 12601055 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 68D73C433EF for ; Wed, 3 Nov 2021 15:44:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 526546109F for ; Wed, 3 Nov 2021 15:44:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231856AbhKCPrN (ORCPT ); Wed, 3 Nov 2021 11:47:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47178 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231880AbhKCPrI (ORCPT ); Wed, 3 Nov 2021 11:47:08 -0400 Received: from mail-wm1-x329.google.com (mail-wm1-x329.google.com [IPv6:2a00:1450:4864:20::329]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B8498C061714 for ; Wed, 3 Nov 2021 08:44:31 -0700 (PDT) Received: by mail-wm1-x329.google.com with SMTP id r9-20020a7bc089000000b00332f4abf43fso3669358wmh.0 for ; Wed, 03 Nov 2021 08:44:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=X58UzyB0GLSm23F3DovGKA2tUpNpMQEd/EUrBeLPFWg=; b=fkAA69LCF79YquhRQ+vDP7irRafC6xUbqAzWRloIGUygrA1Hg/Nf6N7OgW0uVlWL+m KcLfJP5+aZT7xy8hMwI3KUCZ+FPgAARNE6nscDSgLBlTXVIUnfyYBAldh4ILNgumkdwc qTJYByEqqGLqq0TvB51CljTydQjp2tdxdZALWA/bIgdsQMDSjlh6cHSXzeVAMBv0TL2o cih9un/JZJq84uO+YOieVTsQWf2kadoxhsb966t58Dfikl6ErfTAvt/KPlFvaF1ThDFG sUf8TllO1GP7qzz7Q3b1V+HW1ypDMBlBKTLkHsGDouY/84kRr+U2e06gnqkJ72NHsCXx bZLQ== 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=X58UzyB0GLSm23F3DovGKA2tUpNpMQEd/EUrBeLPFWg=; b=0WUVgy/IS3H/Tg0xHRJ9z/LBmx5WgDTko5gam1Swx6/jNO01uav6uavIMAEkRshYVH diGLqNfhZS0jHaCz2stLkxP0fbTW2M9S5O22F0VvErPGKjSMQPFECGL4u5hexQWjLSX4 isTFCzU85QF4WI6LFkBIbcQfB5YKIubgAo1djQ2QAxBkQVo5wyfb69w7pLSqBq/RAs26 5gZRajX9Pi53UOa1mVSXS+ziMAc98rVfmVIr0IyqZOxnfLtrwh3iPUW8225ZG89kkjyQ CC76CF9pqCGD/UKHXsNc6lmwcuU1F/1EZcsmWPecUWJgIzlksprskXfmJa/tfrmGEdTK 0x+Q== X-Gm-Message-State: AOAM530lmBvEZqaJlxXJpOBibPsu7s6xvDjiBkDV+9o9lHgz4bJw+a5F Qc2viEjnck6u7g0QcRdrcew= X-Google-Smtp-Source: ABdhPJz0v+xvi2w07G9ALCLeytb8HWd4gAlUvzzQ82nouRG/jQGCKL4dXWm4GlqiP6RU5UY5CmLJRw== X-Received: by 2002:a05:600c:a08:: with SMTP id z8mr16292500wmp.52.1635954270285; Wed, 03 Nov 2021 08:44:30 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id p12sm2767866wrr.10.2021.11.03.08.44.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 03 Nov 2021 08:44:29 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v3 10/11] libtracefs: Update kprobes man pages Date: Wed, 3 Nov 2021 17:44:16 +0200 Message-Id: <20211103154417.246999-11-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211103154417.246999-1-tz.stoyanov@gmail.com> References: <20211103154417.246999-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 | 111 +++++++++++++-------------- Documentation/libtracefs.txt | 7 ++ 2 files changed, 60 insertions(+), 58 deletions(-) diff --git a/Documentation/libtracefs-kprobes.txt b/Documentation/libtracefs-kprobes.txt index c10576e..fedac96 100644 --- a/Documentation/libtracefs-kprobes.txt +++ b/Documentation/libtracefs-kprobes.txt @@ -3,7 +3,9 @@ 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_info, +tracefs_kprobe_raw, tracefs_kretprobe_raw - Allocate, get, and create kprobes + SYNOPSIS -------- @@ -11,18 +13,44 @@ 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_, int _max_); +enum tracefs_dynevent_type *tracefs_kprobe_info*(struct tracefs_dynevent pass:[*]_kprobe_, + char pass:[*]pass:[*]_system_, char pass:[*]pass:[*]_event_, + char pass:[*]pass:[*]_prefix_, char pass:[*]pass:[*]_addr_, + char pass:[*]pass:[*]_format_); +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). 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 + +*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_info*() returns the type and information of a given _kprobe_. 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 +kprobe. If _prefix_ is non NULL, then it will hold an allocated string that holds the prefix portion +of the kprobe in the kprobe_events file (the content up to the ":", including it). Note that for +kretprobes, the max active count is encoded in the prefix srting. 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 _group_, _event_, _prefix_, _addr_, and +_format_ must be freed with free(3) if they are set. + *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 +64,21 @@ 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_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_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. +The *tracefs_kprobe_alloc*() and *tracefs_kretprobe_alloc*() APIs return pointer to allocated +tracefs_dynevent structure, describing the probe. This pointer must be freed by +*tracefs_dynevent_free*(3). -*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. +*tracefs_kprobe_info*() returns the type of the given kprobe. It returns TRACEFS_DYNEVENT_KPROBE for +normal kprobes, TRACEFS_DYNEVENT_KRETPROBE for kretprobes or TRACEFS_DYNEVENT_MAX 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 ------ @@ -96,9 +90,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 +212,7 @@ int main (int argc, char **argv, char **env) exit(-1); } - tracefs_kprobe_clear_probe(mykprobe, NULL, true); + tracefs_kprobe_destroy(NULL, true); kprobe_create("open", "do_sys_openat2", "file=+0($arg2):ustring flags=+0($arg3):x64 mode=+8($arg3):x64\n"); @@ -247,7 +242,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_kprobe_destroy(NULL, true); tracefs_instance_destroy(instance); tep_free(tep); @@ -293,5 +288,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..f679002 100644 --- a/Documentation/libtracefs.txt +++ b/Documentation/libtracefs.txt @@ -63,6 +63,13 @@ 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_, int _max_); + enum tracefs_kprobe_type *tracefs_kprobe_info*(struct tracefs_dynevent pass:[*]_kprobe_, char pass:[*]pass:[*]_system_, char pass:[*]pass:[*]_event_, char pass:[*]pass:[*]_prefix_, char pass:[*]pass:[*]_addr_, char pass:[*]pass:[*]_format_); + 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 Wed Nov 3 15:44:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 12601057 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 E3981C433EF for ; Wed, 3 Nov 2021 15:44:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CE2E86023E for ; Wed, 3 Nov 2021 15:44:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231958AbhKCPrU (ORCPT ); Wed, 3 Nov 2021 11:47:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47184 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231898AbhKCPrJ (ORCPT ); Wed, 3 Nov 2021 11:47:09 -0400 Received: from mail-wr1-x432.google.com (mail-wr1-x432.google.com [IPv6:2a00:1450:4864:20::432]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CADF8C061203 for ; Wed, 3 Nov 2021 08:44:32 -0700 (PDT) Received: by mail-wr1-x432.google.com with SMTP id d5so4270005wrc.1 for ; Wed, 03 Nov 2021 08:44:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=mV1kSFuvRGQt5pE2neYmRbtlaO0+g5jmzYMKSeowzlU=; b=cNZBfDyXIfnPsE8B0jD4CTfviZBwN8gmLKycpO7xS/E2f/zU81daCmzYMR84AubpYu ltA3pQQbvOFY3vnoHevqLcNbkw4qMGmct6qQeLwwYrG19Nd7eImeIP8iJZy0zRDSKl3b ygNtxfxYBPkw4y7gP31P/z6iMgBxYViCkB8k1fMMzamSaiGTofCDmfgu75VRKmS1owIC /JsWKRHTftub5E2ltfbk5izI9/hveAvEz8ZwYoEFO84W8cUsuCXjhW7iZ/Gc8DMxM64y 1vR/kbvakT+SzdAMC0A01asj91QTf5n4ViR60lYSPqUQ5uEtxqwdTqC2zXEHugm+/OJP 4uvQ== 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=mV1kSFuvRGQt5pE2neYmRbtlaO0+g5jmzYMKSeowzlU=; b=mDBaLNzmGlVKlRRMRwWmnyCgUzkg1WEiKElghsONSw1rN342xQK8Oid7z3lFrsGZAv Zi/Yd4/saeqf7KX0a/X01izk7u4S7sYlahHhs5uKxHcVV2lHUzJ72QdebTLNFc4oMor3 e9CldlZDKKHQrx9IYcdQ3nojQ5tGn6MocEVwtqETQpaa6PTcOqJLQklVfX86psS5jnku UPkF+2+p1WRup5vbC2SvGJLBtjbv+pfjstcwJmiO8RCJuu5nfG9ivmrl4GZwuaF/T7M2 oIWnI1/qjzj2UZtIk4/slGaxUbuJGuwcXWSfWhIWlrV/N5RIQKGXiQLDxZBRHZq7nsDC 2/9g== X-Gm-Message-State: AOAM530A5RkcWkx3SiZYRJaE+BmbHHImwCp7khVwv/z2AoOFo4WEBPtr PHKHtUdarWEjzdsa0B97JRg= X-Google-Smtp-Source: ABdhPJzyyPgb/bbGZ8stacb5NuFfbCs5zmopRS66tbCUpr+XYFt1jIcYYahY9ZO+ZQbc13jQ5hG/aQ== X-Received: by 2002:a5d:518d:: with SMTP id k13mr53188349wrv.120.1635954271314; Wed, 03 Nov 2021 08:44:31 -0700 (PDT) Received: from oberon.zico.biz ([83.222.187.186]) by smtp.gmail.com with ESMTPSA id p12sm2767866wrr.10.2021.11.03.08.44.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 03 Nov 2021 08:44:30 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org, y.karadz@gmail.com Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v3 11/11] libtracefs: Document dynamic events APIs Date: Wed, 3 Nov 2021 17:44:17 +0200 Message-Id: <20211103154417.246999-12-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211103154417.246999-1-tz.stoyanov@gmail.com> References: <20211103154417.246999-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: int tracefs_dynevent_create(struct tracefs_dynevent *devent); int tracefs_dynevent_destroy(struct tracefs_dynevent *devent, bool force); int tracefs_dynevent_destroy_all(unsigned long type_mask, 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 long type_mask, const char *system); Signed-off-by: Tzvetomir Stoyanov (VMware) --- Documentation/libtracefs-dynevents.txt | 257 +++++++++++++++++++++++++ Documentation/libtracefs.txt | 10 + 2 files changed, 267 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..1f28d77 --- /dev/null +++ b/Documentation/libtracefs-dynevents.txt @@ -0,0 +1,257 @@ +libtracefs(3) +============= + +NAME +---- +tracefs_dynevent_create, tracefs_dynevent_destroy, tracefs_dynevent_destroy_all, +tracefs_dynevent_free, tracefs_dynevent_list_free, tracefs_dynevent_get_all - +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 long _type_mask_, 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 long _type_mask_, const char pass:[*]_system_); +-- + +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 _type_mask_ parameter is a bitmask with dynamic events types *tracefs_dynevent_type*, +that will be removed. The *TRACEFS_BIT_SET* macro can be used to set desired types in the bitmask. +If _type_mask_ 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 _type_mask_ parameter is a bitmask with dynamic events types *tracefs_dynevent_type*, +that will be retrieved. The *TRACEFS_BIT_SET* macro can be used to set desired types in the bitmask. +If _type_mask_ 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. + +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*(). + +ERRORS +------ +The following errors are for all the above calls: + +*EPERM* Not run as root user + +*ENODEV* dynamic events of requested type are not configured for the running kernel. + +*ENOMEM* Memory allocation error. + +*tracefs_dynevent_create*() can fail with the following errors: + +*EINVAL* Most likely a parsing error occurred (use *tracefs_error_last*(3) to possibly + see what that error was). + +Other errors may also happen caused by internal system calls. + +EXAMPLE +------- +[source,c] +-- +#include +#include +#include + +#include + +static struct tep_event *open_event; +static struct tep_format_field *file_field; + +static struct tep_event *openret_event; +static struct tep_format_field *ret_field; + +static int callback(struct tep_event *event, struct tep_record *record, + int cpu, void *data) +{ + struct trace_seq seq; + + trace_seq_init(&seq); + tep_print_event(event->tep, &seq, record, "%d-%s: ", TEP_PRINT_PID, TEP_PRINT_COMM); + + if (event->id == open_event->id) { + trace_seq_puts(&seq, "open file='"); + tep_print_field(&seq, record->data, file_field); + trace_seq_puts(&seq, "'\n"); + } else if (event->id == openret_event->id) { + unsigned long long ret; + tep_read_number_field(ret_field, record->data, &ret); + trace_seq_printf(&seq, "open ret=%lld\n", ret); + } else { + goto out; + } + + trace_seq_terminate(&seq); + trace_seq_do_printf(&seq); +out: + trace_seq_destroy(&seq); + + return 0; +} + +static pid_t run_exec(char **argv, char **env) +{ + pid_t pid; + + pid = fork(); + if (pid) + return pid; + + execve(argv[0], argv, env); + perror("exec"); + exit(-1); +} + +const char *mykprobe = "my_kprobes"; + + + +int main (int argc, char **argv, char **env) +{ + struct tracefs_dynevent *kprobe, *kretprobe; + const char *sysnames[] = { mykprobe, NULL }; + struct tracefs_instance *instance; + unsigned long kmask = 0; + 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_BIT_SET(kmask, TRACEFS_DYNEVENT_KPROBE); + TRACEFS_BIT_SET(kmask, TRACEFS_DYNEVENT_KRETPROBE); + tracefs_dynevent_destroy_all(kmask, 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(kmask, 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 f679002..12c2e97 100644 --- a/Documentation/libtracefs.txt +++ b/Documentation/libtracefs.txt @@ -64,6 +64,16 @@ 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 long _type_mask_, 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 long _type_mask_, const char pass:[*]_system_); + 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_, int _max_);