From patchwork Mon Oct 7 11:49:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11177275 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AF13476 for ; Mon, 7 Oct 2019 11:49:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 83C982173B for ; Mon, 7 Oct 2019 11:49:54 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Mictb2N5" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727791AbfJGLty (ORCPT ); Mon, 7 Oct 2019 07:49:54 -0400 Received: from mail-wr1-f68.google.com ([209.85.221.68]:42986 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727496AbfJGLtx (ORCPT ); Mon, 7 Oct 2019 07:49:53 -0400 Received: by mail-wr1-f68.google.com with SMTP id n14so14868367wrw.9 for ; Mon, 07 Oct 2019 04:49:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=tOACvFcJA2eCXoootLKpMeCtmUdCKinOsSx+unALFog=; b=Mictb2N5Vtwxw7/muT7HCAZov4RzOitXsB4rPovU0GuM15dWdXJddi/Sf00hVSc+Jj uxPIOjakKJn5oUTE7WWERrG11B8M1MU1x4Al8A8Bd83P/pcJBvEhZhlbhImht01v70ZV O3MTOsGrPX8iKwkNd/mlgMOZkAC61oaiWXuphHqFaWomZzy1B5BTUVzCg1gPDLKxoAJe fnhcFVLm/RWfQH9QGCiqxxzMZ1LRZHqYiYOXD0xKTK8cNFNQkBEsxxa83wyojvapEJtd ac6cWnmGB6TE8k1YE6cWn0I7NsfS+a2FMzRtMR6Tgy8LDiR2pajDlutvgrcyH6dXnGf1 oM4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=tOACvFcJA2eCXoootLKpMeCtmUdCKinOsSx+unALFog=; b=XfCedvObeBh3R6oVzQNsEE8qUzBEmSnkmc85fCqahMKML7rHnY9r/ipDFvtIyhiNJ/ y1g06/tgpElm2aeImVhHqtv9kN3Trj9HLEa+6c8tmv4cBxS89cmy/lsaMlXSVVQbPIzZ hMKPedelKzkrHvmwvwXU7t37T2aumJC9JriWns3L0sfY7PcFGNJYiryoGBDbkNsmag0l AX6Y614sl22xxtTRE+v92RZnZZ3mL80FGAx0WlKGBWA5uGb/xWQ5BePG5vccPvxzoZuI cqThJSa7BACbzQEIx1CukXfqhs5bjbfBN2cFAumFfTo0sue+K5M1V4zo5woV4Q74r+75 LSTQ== X-Gm-Message-State: APjAAAV8+Utta4niwhS7SyY4YgqPR410LvEN6gstsResy26978KWJzyk P7oVk9Jg+6nx+iJYyxFmXMrWHTWh X-Google-Smtp-Source: APXvYqzGMKTzWmM4SMudTC7QJTUcwRQFtfW9ulA4SE9+K94vFmYFadUiqPFKZh26Cgb4A89GOOpDbQ== X-Received: by 2002:a5d:4d05:: with SMTP id z5mr13593604wrt.76.1570448990791; Mon, 07 Oct 2019 04:49:50 -0700 (PDT) Received: from oberon.eng.vmware.com ([146.247.46.5]) by smtp.gmail.com with ESMTPSA id t13sm39350773wra.70.2019.10.07.04.49.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Oct 2019 04:49:50 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v6 1/3] trace-cmd: Introduced new traceevent API, for adding new plugins directories. Date: Mon, 7 Oct 2019 14:49:45 +0300 Message-Id: <20191007114947.17104-2-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191007114947.17104-1-tz.stoyanov@gmail.com> References: <20191007114947.17104-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Sender: linux-trace-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org Implement new traceevent plugin API, which can be used to add new plugins directories: enum tep_plugin_load_priority { TEP_PLUGIN_FIRST, TEP_PLUGIN_LAST, }; int tep_add_plugin_path(struct tep_handle *tep, char *path, enum tep_plugin_load_priority prio); It adds the "path" as new plugin directory, in the context of the handler "tep". The tep_load_plugins() API searches for plugins in this new location. Depending of the priority "prio", the plugins from this directory are loaded before (TEP_PLUGIN_FIRST) or after (TEP_PLUGIN_LAST) the ordinary libtraceevent plugin locations. Signed-off-by: Tzvetomir Stoyanov (VMware) --- include/traceevent/event-parse.h | 7 +++ lib/traceevent/event-parse-local.h | 5 ++- lib/traceevent/event-parse.c | 1 + lib/traceevent/event-plugin.c | 70 ++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 1 deletion(-) diff --git a/include/traceevent/event-parse.h b/include/traceevent/event-parse.h index 5dff952..d66647b 100644 --- a/include/traceevent/event-parse.h +++ b/include/traceevent/event-parse.h @@ -379,6 +379,13 @@ struct tep_plugin_list; #define INVALID_PLUGIN_LIST_OPTION ((char **)((unsigned long)-1)) +enum tep_plugin_load_priority { + TEP_PLUGIN_FIRST, + TEP_PLUGIN_LAST, +}; + +int tep_add_plugin_path(struct tep_handle *tep, char *path, + enum tep_plugin_load_priority prio); struct tep_plugin_list *tep_load_plugins(struct tep_handle *tep); void tep_unload_plugins(struct tep_plugin_list *plugin_list, struct tep_handle *tep); diff --git a/lib/traceevent/event-parse-local.h b/lib/traceevent/event-parse-local.h index 6e58ee1..abaeadf 100644 --- a/lib/traceevent/event-parse-local.h +++ b/lib/traceevent/event-parse-local.h @@ -13,6 +13,7 @@ struct func_map; struct func_list; struct event_handler; struct func_resolver; +struct tep_plugins_dir; struct tep_handle { int ref_count; @@ -47,7 +48,6 @@ struct tep_handle { struct printk_list *printklist; unsigned int printk_count; - struct tep_event **events; int nr_events; struct tep_event **sort_events; @@ -83,10 +83,13 @@ struct tep_handle { struct tep_event *last_event; char *trace_clock; + + struct tep_plugins_dir *plugins_dir; }; void tep_free_event(struct tep_event *event); void tep_free_format_field(struct tep_format_field *field); +void tep_free_plugin_paths(struct tep_handle *tep); unsigned short tep_data2host2(struct tep_handle *tep, unsigned short data); unsigned int tep_data2host4(struct tep_handle *tep, unsigned int data); diff --git a/lib/traceevent/event-parse.c b/lib/traceevent/event-parse.c index 7fbbbcc..b92e52c 100644 --- a/lib/traceevent/event-parse.c +++ b/lib/traceevent/event-parse.c @@ -7063,6 +7063,7 @@ void tep_free(struct tep_handle *tep) free(tep->events); free(tep->sort_events); free(tep->func_resolver); + tep_free_plugin_paths(tep); free(tep); } diff --git a/lib/traceevent/event-plugin.c b/lib/traceevent/event-plugin.c index 6ea4ac0..30c1526 100644 --- a/lib/traceevent/event-plugin.c +++ b/lib/traceevent/event-plugin.c @@ -39,6 +39,12 @@ struct tep_plugin_list { void *handle; }; +struct tep_plugins_dir { + struct tep_plugins_dir *next; + char *path; + enum tep_plugin_load_priority prio; +}; + static void lower_case(char *str) { if (!str) @@ -545,6 +551,7 @@ void tep_load_plugins_hook(struct tep_handle *tep, const char *suffix, void *data), void *data) { + struct tep_plugins_dir *dir = NULL; char *home; char *path; char *envdir; @@ -553,6 +560,15 @@ void tep_load_plugins_hook(struct tep_handle *tep, const char *suffix, if (tep && tep->flags & TEP_DISABLE_PLUGINS) return; + if (tep) + dir = tep->plugins_dir; + while (dir) { + if (dir->prio == TEP_PLUGIN_FIRST) + load_plugins_dir(tep, suffix, dir->path, + load_plugin, data); + dir = dir->next; + } + /* * If a system plugin directory was defined, * check that first. @@ -587,6 +603,15 @@ void tep_load_plugins_hook(struct tep_handle *tep, const char *suffix, load_plugins_dir(tep, suffix, path, load_plugin, data); + if (tep) + dir = tep->plugins_dir; + while (dir) { + if (dir->prio == TEP_PLUGIN_LAST) + load_plugins_dir(tep, suffix, dir->path, + load_plugin, data); + dir = dir->next; + } + free(path); } @@ -599,6 +624,51 @@ tep_load_plugins(struct tep_handle *tep) return list; } +/** + * tep_add_plugin_path - Add a new plugin directory. + * @tep: Trace event handler. + * @path: Path to a directory. All files with extension .so in that + * directory will be loaded as plugins. + *@prio: Load priority of the plugins in that directory. + * + * Returns -1 in case of an error, 0 otherwise. + */ +int tep_add_plugin_path(struct tep_handle *tep, char *path, + enum tep_plugin_load_priority prio) +{ + struct tep_plugins_dir *dir; + + if (!tep || !path) + return -1; + + dir = calloc(1, sizeof(*dir)); + if (!dir) + return -1; + + dir->path = strdup(path); + dir->prio = prio; + dir->next = tep->plugins_dir; + tep->plugins_dir = dir; + + return 0; +} + +void tep_free_plugin_paths(struct tep_handle *tep) +{ + struct tep_plugins_dir *dir; + + if (!tep) + return; + + dir = tep->plugins_dir; + while (dir) { + tep->plugins_dir = tep->plugins_dir->next; + free(dir->path); + free(dir); + dir = tep->plugins_dir; + } +} + void tep_unload_plugins(struct tep_plugin_list *plugin_list, struct tep_handle *tep) { From patchwork Mon Oct 7 11:49:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11177279 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 43AA076 for ; Mon, 7 Oct 2019 11:49:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 18D34206C2 for ; Mon, 7 Oct 2019 11:49:56 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="HgSj9n2M" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727561AbfJGLtz (ORCPT ); Mon, 7 Oct 2019 07:49:55 -0400 Received: from mail-wm1-f68.google.com ([209.85.128.68]:52768 "EHLO mail-wm1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727588AbfJGLty (ORCPT ); Mon, 7 Oct 2019 07:49:54 -0400 Received: by mail-wm1-f68.google.com with SMTP id r19so12315970wmh.2 for ; Mon, 07 Oct 2019 04:49:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=quTCgnXAEANb78+ujZiZtqg/yjkhnjJTI4XREtGC+Hk=; b=HgSj9n2Ml0jaPd0FN2NU1m/TTdy+2Zv73VEuiZaiuykCK6mXcmOKDkKC0JmMgL82PT xtuaPJb1Wg9SgI5Npi79cOSnm7XEMIdtYOk4wCzqvtLxFyO2O3K1BgQwDmCzTR7x2JuN i4uNWPm1ci3i/tnuM2viiMKtXk9agZkDl6F+n7+/ufY/KFW5T/JENwkbde33sS+TTD0S BqPiB1KD2V/NKyt7ugoeByd2JursdprUfpE8889W5SASOPltrq4J3jmBP6Weu3z4eQ+t iEzNVa74rbNxK1qBZPow9yfzcx0JrpMd60IV/HoLtQGsl1UXmN49RBjDiP9HGq5RYmNU y2Hw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=quTCgnXAEANb78+ujZiZtqg/yjkhnjJTI4XREtGC+Hk=; b=OWcrViC2Fb227lphV6G1iAoP5JaHUavljJyC8ybbeJzfpEE8F8XNPh2ow/UOWyMIXg HOalUHxJX+0DVfET4OMJNhl2iJY5WxVfFzJN8fkdHag10I5/I6hfTgarJiq/9mDUEw6i WLPTxr6GT0VQ3fK2IwUEARAqkUC1NiY3lyjOPF89OIu4+Ff3Rijm+M4zrkXb2lClESTx cEVn3OrnUM3aS1n2VcmKFBP6mAQqgvxbHQPtA8aQVhOm91AJIOzlVe8vw4ZOecyEr9Ac wL1zn38Y7+fACmPDKCRmmdZOkdL8IYJNYtv3wokgp+XT4FOB0y/pIEY+j3cU069T3rTG 0nTQ== X-Gm-Message-State: APjAAAWXGztuNN3kOAtirjiRUtwmeTOkGNp9t1PRHxHtn++IyLejGXAZ uboHIralv0wGgXgIKI1fnaQ= X-Google-Smtp-Source: APXvYqyhloQRNORCfOhqwmqrT7QI7Cc59raai/S+m0DPKeMWdHrCyWP1L7MLYaxQ0jVeJLEPsjXELw== X-Received: by 2002:a7b:c10b:: with SMTP id w11mr19300350wmi.108.1570448991781; Mon, 07 Oct 2019 04:49:51 -0700 (PDT) Received: from oberon.eng.vmware.com ([146.247.46.5]) by smtp.gmail.com with ESMTPSA id t13sm39350773wra.70.2019.10.07.04.49.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Oct 2019 04:49:51 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v6 2/3] trace-cmd: Load libtraceevent plugins from build folder, if exists. Date: Mon, 7 Oct 2019 14:49:46 +0300 Message-Id: <20191007114947.17104-3-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191007114947.17104-1-tz.stoyanov@gmail.com> References: <20191007114947.17104-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Sender: linux-trace-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org When a development version of trace-cmd is built and run on the machine, by default it loads only installed plugins, from system directories. Thus, the development plugins will not be loaded. To simplify the development process, a new logic is added: At plugins load time, check the location of trace-cmd application and look for "plugins" directory around it. If found, load plugins from it. Those plugins will be loaded last, so in case of duplication the "development" plugins win. A two new APIs are introduced to libtraceevent, in order to accomplish this logic: tep_load_plugins_dir() - loads tep plugins from a specific directory. tep_plugins_append() - Append two plugin lists. Signed-off-by: Tzvetomir Stoyanov (VMware) --- include/trace-cmd/trace-cmd.h | 2 ++ lib/trace-cmd/trace-input.c | 7 +----- lib/trace-cmd/trace-util.c | 42 +++++++++++++++++++++++++++++++++++ tracecmd/trace-check-events.c | 7 +----- tracecmd/trace-list.c | 14 ++---------- 5 files changed, 48 insertions(+), 24 deletions(-) diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index 4090eba..d1aaef8 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -24,6 +24,8 @@ void tracecmd_parse_ftrace_printk(struct tep_handle *pevent, char *file, unsigne extern int tracecmd_disable_sys_plugins; extern int tracecmd_disable_plugins; +struct tep_plugin_list *trace_load_plugins(struct tep_handle *tep); + char **tracecmd_event_systems(const char *tracing_dir); char **tracecmd_system_events(const char *tracing_dir, const char *system); struct tep_handle *tracecmd_local_events(const char *tracing_dir); diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c index 6102eb3..28da455 100644 --- a/lib/trace-cmd/trace-input.c +++ b/lib/trace-cmd/trace-input.c @@ -2886,15 +2886,10 @@ struct tracecmd_input *tracecmd_alloc_fd(int fd) if (!handle->pevent) goto failed_read; - if (tracecmd_disable_plugins) - tep_set_flag(handle->pevent, TEP_DISABLE_PLUGINS); - if (tracecmd_disable_sys_plugins) - tep_set_flag(handle->pevent, TEP_DISABLE_SYS_PLUGINS); - /* register default ftrace functions first */ tracecmd_ftrace_overrides(handle, &handle->finfo); - handle->plugin_list = tep_load_plugins(handle->pevent); + handle->plugin_list = trace_load_plugins(handle->pevent); tep_set_file_bigendian(handle->pevent, buf[0]); tep_set_local_bigendian(handle->pevent, tracecmd_host_bigendian()); diff --git a/lib/trace-cmd/trace-util.c b/lib/trace-cmd/trace-util.c index 8aa3b6c..690a135 100644 --- a/lib/trace-cmd/trace-util.c +++ b/lib/trace-cmd/trace-util.c @@ -860,6 +860,48 @@ void trace_util_free_plugin_files(char **files) free(files); } +static char *get_source_plugins_dir(void) +{ + char *p, path[PATH_MAX+1]; + int ret; + + ret = readlink("/proc/self/exe", path, PATH_MAX); + if (ret > PATH_MAX || ret < 0) + return NULL; + + dirname(path); + p = strrchr(path, '/'); + if (!p) + return NULL; + /* Check if we are in the the source tree */ + if (strcmp(p, "/tracecmd") != 0) + return NULL; + + strcpy(p, "/lib/traceevent/plugins"); + return strdup(path); +} + +struct tep_plugin_list* +trace_load_plugins(struct tep_handle *tep) +{ + struct tep_plugin_list *list; + char *path; + + if (tracecmd_disable_plugins) + tep_set_flag(tep, TEP_DISABLE_PLUGINS); + if (tracecmd_disable_sys_plugins) + tep_set_flag(tep, TEP_DISABLE_SYS_PLUGINS); + + path = get_source_plugins_dir(); + if (path) + tep_add_plugin_path(tep, path, TEP_PLUGIN_LAST); + free(path); + + list = tep_load_plugins(tep); + + return list; +} + char *tracecmd_get_tracing_file(const char *name) { static const char *tracing; diff --git a/tracecmd/trace-check-events.c b/tracecmd/trace-check-events.c index b09fcd0..ffaae27 100644 --- a/tracecmd/trace-check-events.c +++ b/tracecmd/trace-check-events.c @@ -43,12 +43,7 @@ void trace_check_events(int argc, char **argv) if (!pevent) exit(EINVAL); - if (tracecmd_disable_plugins) - tep_set_flag(pevent, TEP_DISABLE_PLUGINS); - if (tracecmd_disable_sys_plugins) - tep_set_flag(pevent, TEP_DISABLE_SYS_PLUGINS); - - list = tep_load_plugins(pevent); + list = trace_load_plugins(pevent); ret = tracecmd_fill_local_events(tracing, pevent, &parsing_failures); if (ret || parsing_failures) ret = EINVAL; diff --git a/tracecmd/trace-list.c b/tracecmd/trace-list.c index 65099a5..6b59117 100644 --- a/tracecmd/trace-list.c +++ b/tracecmd/trace-list.c @@ -317,14 +317,9 @@ static void show_plugin_options(void) if (!pevent) die("Can not allocate pevent\n"); - if (tracecmd_disable_plugins) - tep_set_flag(pevent, TEP_DISABLE_PLUGINS); - if (tracecmd_disable_sys_plugins) - tep_set_flag(pevent, TEP_DISABLE_SYS_PLUGINS); - trace_seq_init(&s); - list = tep_load_plugins(pevent); + list = trace_load_plugins(pevent); tep_plugin_print_options(&s); trace_seq_do_printf(&s); tep_unload_plugins(list, pevent); @@ -348,14 +343,9 @@ static void show_plugins(void) if (!pevent) die("Can not allocate pevent\n"); - if (tracecmd_disable_plugins) - tep_set_flag(pevent, TEP_DISABLE_PLUGINS); - if (tracecmd_disable_sys_plugins) - tep_set_flag(pevent, TEP_DISABLE_SYS_PLUGINS); - trace_seq_init(&s); - list = tep_load_plugins(pevent); + list = trace_load_plugins(pevent); tep_print_plugins(&s, " ", "\n", list); trace_seq_do_printf(&s); From patchwork Mon Oct 7 11:49:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11177281 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C9D2F76 for ; Mon, 7 Oct 2019 11:49:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 94F4C2173B for ; Mon, 7 Oct 2019 11:49:57 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="cYvPha7v" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727688AbfJGLt5 (ORCPT ); Mon, 7 Oct 2019 07:49:57 -0400 Received: from mail-wr1-f45.google.com ([209.85.221.45]:40134 "EHLO mail-wr1-f45.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727502AbfJGLt5 (ORCPT ); Mon, 7 Oct 2019 07:49:57 -0400 Received: by mail-wr1-f45.google.com with SMTP id h4so6178122wrv.7 for ; Mon, 07 Oct 2019 04:49:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=pTObwY/P/CcDke8HveT6Y/VzW04pygROLp6/b1NuUcs=; b=cYvPha7vyeEMClnYKzZ3kUDlRWoE/957Y13440YhACQ8bb2132JNxV74IGANRTp0h0 icIylZUt0d1dLvsgHF63xhxvVrzW7HoIYrs7zQdp0nCjWqhFt9XVX6NI+mWoJw0ISz5i iEGcAt63/1IhPl20sp0kDOc3MzuRVOyaukjRU+2HhLbyjcTRtJTLIb5dGbukBlPZw9Mf dHAvaJesbnG9wluy/ziFv5XqUfGH3Kr0Rf4D4XrmG4HR88BXs1Mdq53jqTN3vqxLFPrl qNVI+pBneluCg6ilglC5Q7pbl/2mW7MUar1vh9xyKAwaqkulTSZWrpQE1yGhvY4Itf7e xDYA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=pTObwY/P/CcDke8HveT6Y/VzW04pygROLp6/b1NuUcs=; b=mbSJrCU+t3ZMObt3Gig/nUG5ujhBj/T+boi0Ze+icEfbD7Vdhf59HmuxzM8Rpii6TW HWDNkjNqQNEIlWVemIzgLcomyalPoAzbjppdAuGXlIp8GeMlv56OiPpLviu706hJ6aXt X28wBnYHuyH57yRkbiTYv1WFj1moFOy1+Ie92jc74OClP9rfe2/c9xA0JRB8vLCfWkSg RcRFGwRSX+bKK8VVO0cV0ekUr04bFL5EOF77zaIUlRNKRlS9UnNgnsEmqKwrw8S2PnlY iHSMtq21wWgeoULrMJcex7STJy5YEsKVykjZwxYjn3U6YB9I/j6zR6hKEjtPAM+Hobcx +F9A== X-Gm-Message-State: APjAAAWuf6cEyoB35l+K3VS6Pc+6a+TOuMswWS4C7lRe9LWEvhpaSViy BEJgofPJoDw4lV/ym4Y1beSVeG5M X-Google-Smtp-Source: APXvYqxXiod20+bqiMWAlzEKfrVkjWIZBrb9AnIGWz88KeZz7ez73om5k/dsVNDYvBgzbW614mgUnQ== X-Received: by 2002:a5d:6446:: with SMTP id d6mr8181025wrw.309.1570448992864; Mon, 07 Oct 2019 04:49:52 -0700 (PDT) Received: from oberon.eng.vmware.com ([146.247.46.5]) by smtp.gmail.com with ESMTPSA id t13sm39350773wra.70.2019.10.07.04.49.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Oct 2019 04:49:52 -0700 (PDT) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v6 3/3] trace-cmd: Add initial infrastructure for trace-cmd specific plugins. Date: Mon, 7 Oct 2019 14:49:47 +0300 Message-Id: <20191007114947.17104-4-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191007114947.17104-1-tz.stoyanov@gmail.com> References: <20191007114947.17104-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Sender: linux-trace-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org Create a new directory lib/trace-cmd/plugins, where the libtracecmd plugins will be placed. Plugins compilation is integrated in the trace-cmd build process. New plugins are installed in $(HOME)/.local/lib/trace-cmd/plugins or $(libdir)/trace-cmd/plugins directories. Current python_plugin.so is part of libtraceevent plugins, so the python plugins path is changed from $(HOME)/.trace-cmd/python to $(HOME)/.local/lib/traceevent/python and $(libdir)/trace-cmd/python to $(libdir)/traceevent/python Added an initial set of APIs for working with trace-cmd plugins. Signed-off-by: Tzvetomir Stoyanov (VMware) --- .gitignore | 1 + Makefile | 40 ++++- include/trace-cmd/trace-cmd.h | 40 +++++ lib/trace-cmd/Makefile | 1 + lib/trace-cmd/plugins/Makefile | 58 ++++++ lib/trace-cmd/trace-plugin.c | 313 +++++++++++++++++++++++++++++++++ 6 files changed, 445 insertions(+), 8 deletions(-) create mode 100644 lib/trace-cmd/plugins/Makefile create mode 100644 lib/trace-cmd/trace-plugin.c diff --git a/.gitignore b/.gitignore index 20bb5a3..6759e51 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ TAGS cscope* traceevent_plugin_dir trace_python_dir +tracecmd_plugin_dir diff --git a/Makefile b/Makefile index bbdf15e..ab76f1f 100644 --- a/Makefile +++ b/Makefile @@ -57,14 +57,17 @@ export DESTDIR DESTDIR_SQ ifeq ($(prefix),$(HOME)) plugin_traceevent_dir = $(HOME)/.local/lib/traceevent/plugins -python_dir = $(HOME)/.trace-cmd/python +plugin_tracecmd_dir = $(libdir)/trace-cmd/plugins +python_dir ?= $(libdir)/traceevent/python var_dir = $(HOME)/.trace-cmd/ else plugin_traceevent_dir = $(libdir)/traceevent/plugins python_dir ?= $(libdir)/trace-cmd/python PLUGIN_DIR_TRACEEVENT = -DPLUGIN_TRACEEVENT_DIR="$(plugin_traceevent_dir)" +PLUGIN_DIR_TRACECMD = -DPLUGIN_TRACECMD_DIR="$(plugin_tracecmd_dir)" PYTHON_DIR = -DPYTHON_DIR="$(python_dir)" PLUGIN_DIR_TRACEEVENT_SQ = '$(subst ','\'',$(PLUGIN_DIR_TRACEEVENT))' +PLUGIN_DIR_TRACECMD_SQ = '$(subst ','\'',$(PLUGIN_DIR_TRACECMD))' PYTHON_DIR_SQ = '$(subst ','\'',$(PYTHON_DIR))' var_dir = /var endif @@ -73,6 +76,7 @@ endif bindir_SQ = $(subst ','\'',$(bindir)) bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) plugin_traceevent_dir_SQ = $(subst ','\'',$(plugin_traceevent_dir)) +plugin_tracecmd_dir_SQ = $(subst ','\'',$(plugin_tracecmd_dir)) python_dir_SQ = $(subst ','\'',$(python_dir)) VAR_DIR = -DVAR_DIR="$(var_dir)" @@ -86,9 +90,11 @@ HELP_DIR_SQ = '$(subst ','\'',$(HELP_DIR))' BASH_COMPLETE_DIR ?= /etc/bash_completion.d export PLUGIN_DIR_TRACEEVENT +export PLUGIN_DIR_TRACECMD export PYTHON_DIR export PYTHON_DIR_SQ export plugin_traceevent_dir_SQ +export plugin_tracecmd_dir_SQ export python_dir_SQ export var_dir @@ -239,7 +245,8 @@ LIBS += -laudit endif # Append required CFLAGS -override CFLAGS += $(INCLUDES) $(PLUGIN_DIR_TRACEEVENT_SQ) $(VAR_DIR) +override CFLAGS += $(INCLUDES) $(VAR_DIR) +override CFLAGS += $(PLUGIN_DIR_TRACEEVENT_SQ) $(PLUGIN_DIR_TRACECMD_SQ) override CFLAGS += $(udis86-flags) $(blk-flags) override LDFLAGS += $(udis86-ldflags) @@ -268,13 +275,16 @@ gui: force $(CMD_TARGETS) $(kshark-dir)/build/Makefile @echo "gui build complete" @echo " kernelshark located at $(kshark-dir)/bin" -trace-cmd: force $(LIBTRACEEVENT_STATIC) $(LIBTRACECMD_STATIC) +trace-cmd: force $(LIBTRACEEVENT_STATIC) $(LIBTRACECMD_STATIC) \ + force $(obj)/lib/trace-cmd/plugins/tracecmd_plugin_dir $(Q)$(MAKE) -C $(src)/tracecmd $(obj)/tracecmd/$@ -$(LIBTRACEEVENT_SHARED): force $(obj)/lib/traceevent/plugins/traceevent_plugin_dir +$(LIBTRACEEVENT_SHARED): force $(obj)/lib/traceevent/plugins/trace_python_dir \ + $(obj)/lib/traceevent/plugins/traceevent_plugin_dir $(Q)$(MAKE) -C $(src)/lib/traceevent $@ -$(LIBTRACEEVENT_STATIC): force $(obj)/lib/traceevent/plugins/traceevent_plugin_dir +$(LIBTRACEEVENT_STATIC): force $(obj)/lib/traceevent/plugins/trace_python_dir \ + $(obj)/lib/traceevent/plugins/traceevent_plugin_dir $(Q)$(MAKE) -C $(src)/lib/traceevent $@ $(LIBTRACECMD_STATIC): force @@ -290,12 +300,21 @@ libtracecmd.so: $(LIBTRACECMD_SHARED) libs: $(LIBTRACECMD_SHARED) $(LIBTRACEEVENT_SHARED) -plugins: force $(obj)/lib/traceevent/plugins/traceevent_plugin_dir $(obj)/lib/traceevent/plugins/trace_python_dir +plugins_traceevent: force $(obj)/lib/traceevent/plugins/traceevent_plugin_dir \ + $(obj)/lib/traceevent/plugins/trace_python_dir $(Q)$(MAKE) -C $(src)/lib/traceevent/plugins +plugins_tracecmd: force $(obj)/lib/trace-cmd/plugins/tracecmd_plugin_dir + $(Q)$(MAKE) -C $(src)/lib/trace-cmd/plugins + +plugins: plugins_traceevent plugins_tracecmd + $(obj)/lib/traceevent/plugins/traceevent_plugin_dir: force $(Q)$(MAKE) -C $(src)/lib/traceevent/plugins $@ +$(obj)/lib/trace-cmd/plugins/tracecmd_plugin_dir: force + $(Q)$(MAKE) -C $(src)/lib/trace-cmd/plugins $@ + $(obj)/lib/traceevent/plugins/trace_python_dir: force $(Q)$(MAKE) -C $(src)/lib/traceevent/plugins $@ @@ -322,8 +341,12 @@ cscope: force $(RM) cscope* $(call find_tag_files) | cscope -b -q -install_plugins: force - $(Q)$(MAKE) -C $(src)/lib/traceevent/plugins $@ +install_plugins_traceevent: force + $(Q)$(MAKE) -C $(src)/lib/traceevent/plugins install_plugins +install_plugins_tracecmd: force + $(Q)$(MAKE) -C $(src)/lib/trace-cmd/plugins install_plugins + +install_plugins: install_plugins_traceevent install_plugins_tracecmd install_python: force $(Q)$(MAKE) -C $(src)/python $@ @@ -371,6 +394,7 @@ clean: $(MAKE) -C $(src)/lib/traceevent clean $(MAKE) -C $(src)/lib/trace-cmd clean $(MAKE) -C $(src)/lib/traceevent/plugins clean + $(MAKE) -C $(src)/lib/trace-cmd/plugins clean $(MAKE) -C $(src)/python clean $(MAKE) -C $(src)/tracecmd clean if [ -f $(kshark-dir)/build/Makefile ]; then $(MAKE) -C $(kshark-dir)/build clean; fi diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index d1aaef8..092a80c 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -54,6 +54,46 @@ struct tracecmd_output; struct tracecmd_recorder; struct hook_list; +/* --- tracecmd plugins --- */ + +extern int tracecmd_disable_sys_plugins; +extern int tracecmd_disable_plugins; + +enum tracecmd_context { + TRACECMD_INPUT, + TRACECMD_OUTPUT, +}; + +enum tracecmd_plugin_flag { + TRACECMD_DISABLE_SYS_PLUGINS = 1, + TRACECMD_DISABLE_PLUGINS = 1 << 1, +}; + +struct trace_plugin_context; + +struct trace_plugin_context * +tracecmd_plugin_context_create(enum tracecmd_context context, void *data); + +void tracecmd_plugin_set_flag(struct trace_plugin_context *context, + enum tracecmd_plugin_flag flag); + +#define TRACECMD_PLUGIN_LOADER tracecmd_plugin_loader +#define TRACECMD_PLUGIN_UNLOADER tracecmd_plugin_unloader +#define TRACECMD_PLUGIN_ALIAS tracecmd_plugin_alias +#define _MAKE_STR(x) #x +#define MAKE_STR(x) _MAKE_STR(x) +#define TRACECMD_PLUGIN_LOADER_NAME MAKE_STR(TRACECMD_PLUGIN_LOADER) +#define TRACECMD_PLUGIN_UNLOADER_NAME MAKE_STR(TRACECMD_PLUGIN_UNLOADER) +#define TRACECMD_PLUGIN_ALIAS_NAME MAKE_STR(TRACECMD_PLUGIN_ALIAS) + +typedef int (*tracecmd_plugin_load_func)(struct trace_plugin_context *trace); +typedef int (*tracecmd_plugin_unload_func)(struct trace_plugin_context *trace); + +struct tracecmd_input * +tracecmd_plugin_context_input(struct trace_plugin_context *trace_context); +struct tracecmd_output * +tracecmd_plugin_context_output(struct trace_plugin_context *trace_context); + void tracecmd_set_quiet(struct tracecmd_output *handle, bool set_quiet); bool tracecmd_get_quiet(struct tracecmd_output *handle); diff --git a/lib/trace-cmd/Makefile b/lib/trace-cmd/Makefile index 3b4b5aa..6f3e6b1 100644 --- a/lib/trace-cmd/Makefile +++ b/lib/trace-cmd/Makefile @@ -15,6 +15,7 @@ OBJS += trace-recorder.o OBJS += trace-util.o OBJS += trace-filter-hash.o OBJS += trace-msg.o +OBJS += trace-plugin.o # Additional util objects OBJS += trace-blk-hack.o diff --git a/lib/trace-cmd/plugins/Makefile b/lib/trace-cmd/plugins/Makefile new file mode 100644 index 0000000..240e6be --- /dev/null +++ b/lib/trace-cmd/plugins/Makefile @@ -0,0 +1,58 @@ +include $(src)/scripts/utils.mk + +bdir:=$(obj)/lib/trace-cmd/plugins + +PLUGIN_OBJS = + +PLUGIN_OBJS := $(PLUGIN_OBJS:%.o=$(bdir)/%.o) +PLUGIN_BUILD := $(PLUGIN_OBJS:$(bdir)/%.o=$(bdir)/%.so) + +PLUGINS := $(PLUGIN_BUILD) + +DEPS := $(PLUGIN_OBJS:$(bdir)/%.o=$(bdir)/.%.d) + +all: $(PLUGINS) + +$(bdir): + @mkdir -p $(bdir) + +$(PLUGIN_OBJS): | $(bdir) +$(DEPS): | $(bdir) + +$(PLUGIN_OBJS): $(bdir)/%.o : %.c + $(Q)$(do_compile_plugin_obj) + +$(PLUGIN_BUILD): $(bdir)/%.so: $(bdir)/%.o + $(Q)$(do_plugin_build) + +$(DEPS): $(bdir)/.%.d: %.c + $(Q)$(CC) -M $(CPPFLAGS) $(CFLAGS) $< > $@ + +$(PLUGIN_OBJS): $(bdir)/%.o : $(bdir)/.%.d + +PLUGINS_INSTALL = $(subst .so,.install,$(PLUGINS)) + +$(PLUGINS_INSTALL): $(bdir)/%.install : $(bdir)/%.so force + $(Q)$(call do_install_data,$<,$(plugin_tracecmd_dir_SQ)) + +install_plugins: $(PLUGINS_INSTALL) + +# The following targets are necessary to trigger a rebuild when +# $(PLUGIN_DIR_TRACECMD) change. Without them, a full clean build would +# necessary in order to get the binaries updated. + +$(bdir)/tracecmd_plugin_dir: $(bdir) force + $(Q)$(N)$(call update_dir, 'PLUGIN_DIR_TRACECMD=$(PLUGIN_DIR_TRACECMD)') + +dep_includes := $(wildcard $(DEPS)) + +ifneq ($(dep_includes),) + include $(dep_includes) +endif + +clean: + $(RM) -f $(bdir)/*.a $(bdir)/*.so $(bdir)/*.o $(bdir)/.*.d\ + $(bdir)/tracecmd_plugin_dir + +force: +.PHONY: clean force diff --git a/lib/trace-cmd/trace-plugin.c b/lib/trace-cmd/trace-plugin.c new file mode 100644 index 0000000..6bec18b --- /dev/null +++ b/lib/trace-cmd/trace-plugin.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt + * + */ +#include +#include +#include +#include +#include +#include "trace-cmd.h" +#include "trace-local.h" + +#define LOCAL_PLUGIN_DIR ".local/lib/trace-cmd/plugins/" + +struct trace_plugin_list { + struct trace_plugin_list *next; + char *name; + void *handle; +}; + +struct trace_plugin_context { + enum tracecmd_context context; + enum tracecmd_plugin_flag flags; + union { + void *data; + struct tracecmd_input *trace_input; + struct tracecmd_output *trace_output; + }; +}; + +/** + * tracecmd_plugin_context_create - Create and initialize tracecmd plugins context. + * @context: Context of the trace-cmd command. + * @data: Pointer to the context specific data, which will be passed to plugins. + * + * Returns a pointer to created tracecmd plugins context, or NULL in case memory + * allocation fails. The returned pointer should be freed by free (). + */ +struct trace_plugin_context * +tracecmd_plugin_context_create(enum tracecmd_context context, void *data) +{ + struct trace_plugin_context *trace; + + trace = calloc(1, sizeof(struct trace_plugin_context)); + if (!trace) + return NULL; + trace->context = context; + trace->data = data; + return trace; +} + +/** + * tracecmd_plugin_set_flag - Set a flag to tracecmd plugins context. + * @context: Context of the trace-cmd command. + * @flag: Flag, whil will be set. + * + */ +void tracecmd_plugin_set_flag(struct trace_plugin_context *context, + enum tracecmd_plugin_flag flag) +{ + if (context) + context->flags |= flag; +} + +/** + * tracecmd_plugin_context_input - Get a tracecmd_input plugin context. + * @context: Context of the trace-cmd command. + * + * Returns pointer to tracecmd_input, if such context is available or + * NULL otherwise. + */ +struct tracecmd_input * +tracecmd_plugin_context_input(struct trace_plugin_context *context) +{ + if (!context || context->context != TRACECMD_INPUT) + return NULL; + return context->trace_input; +} + +/** + * tracecmd_plugin_context_output - Get a tracecmd_output plugin context + * @context: Context of the trace-cmd command. + * + * Returns pointer to tracecmd_output, if such context is available or + * NULL otherwise. + */ +struct tracecmd_output * +tracecmd_plugin_context_output(struct trace_plugin_context *context) +{ + if (!context || context->context != TRACECMD_OUTPUT) + return NULL; + return context->trace_output; +} + +static void +load_plugin(struct trace_plugin_context *trace, const char *path, + const char *file, void *data) +{ + struct trace_plugin_list **plugin_list = data; + tracecmd_plugin_load_func func; + struct trace_plugin_list *list; + const char *alias; + char *plugin; + void *handle; + int ret; + + ret = asprintf(&plugin, "%s/%s", path, file); + if (ret < 0) { + warning("could not allocate plugin memory\n"); + return; + } + + handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL); + if (!handle) { + warning("could not load plugin '%s'\n%s\n", + plugin, dlerror()); + goto out_free; + } + + alias = dlsym(handle, TRACECMD_PLUGIN_ALIAS_NAME); + if (!alias) + alias = file; + + func = dlsym(handle, TRACECMD_PLUGIN_LOADER_NAME); + if (!func) { + warning("could not find func '%s' in plugin '%s'\n%s\n", + TRACECMD_PLUGIN_LOADER_NAME, plugin, dlerror()); + goto out_free; + } + + list = malloc(sizeof(*list)); + if (!list) { + warning("could not allocate plugin memory\n"); + goto out_free; + } + + list->next = *plugin_list; + list->handle = handle; + list->name = plugin; + *plugin_list = list; + + pr_stat("registering plugin: %s", plugin); + func(trace); + return; + + out_free: + free(plugin); +} + +static void +load_plugins_dir(struct trace_plugin_context *trace, const char *suffix, + const char *path, + void (*load_plugin)(struct trace_plugin_context *trace, + const char *path, + const char *name, + void *data), + void *data) +{ + struct dirent *dent; + struct stat st; + DIR *dir; + int ret; + + ret = stat(path, &st); + if (ret < 0) + return; + + if (!S_ISDIR(st.st_mode)) + return; + + dir = opendir(path); + if (!dir) + return; + + while ((dent = readdir(dir))) { + const char *name = dent->d_name; + + if (strcmp(name, ".") == 0 || + strcmp(name, "..") == 0) + continue; + + /* Only load plugins that end in suffix */ + if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0) + continue; + + load_plugin(trace, path, name, data); + } + + closedir(dir); +} + +static char *get_source_plugins_dir(void) +{ + char *p, path[PATH_MAX+1]; + int ret; + + ret = readlink("/proc/self/exe", path, PATH_MAX); + if (ret > PATH_MAX || ret < 0) + return NULL; + + dirname(path); + p = strrchr(path, '/'); + if (!p) + return NULL; + /* Check if we are in the the source tree */ + if (strcmp(p, "/tracecmd") != 0) + return NULL; + + strcpy(p, "/lib/trace-cmd/plugins"); + return strdup(path); +} + +static void +load_plugins_hook(struct trace_plugin_context *trace, const char *suffix, + void (*load_plugin)(struct trace_plugin_context *trace, + const char *path, + const char *name, + void *data), + void *data) +{ + char *home; + char *path; + char *envdir; + int ret; + + if (trace && trace->flags & TRACECMD_DISABLE_PLUGINS) + return; + + /* + * If a system plugin directory was defined, + * check that first. + */ +#ifdef PLUGIN_TRACECMD_DIR + if (!trace || !(trace->flags & TRACECMD_DISABLE_SYS_PLUGINS)) + load_plugins_dir(trace, suffix, PLUGIN_TRACECMD_DIR, + load_plugin, data); +#endif + + /* + * Next let the environment-set plugin directory + * override the system defaults. + */ + envdir = getenv("TRACECMD_PLUGIN_DIR"); + if (envdir) + load_plugins_dir(trace, suffix, envdir, load_plugin, data); + + /* + * Now let the home directory override the environment + * or system defaults. + */ + home = getenv("HOME"); + if (!home) + return; + + ret = asprintf(&path, "%s/%s", home, LOCAL_PLUGIN_DIR); + if (ret < 0) { + warning("could not allocate plugin memory\n"); + return; + } + + load_plugins_dir(trace, suffix, path, load_plugin, data); + + free(path); + + path = get_source_plugins_dir(); + if (path) { + load_plugins_dir(trace, suffix, path, load_plugin, data); + free(path); + } +} + +/** + * tracecmd_load_plugins - Load trace-cmd specific plugins. + * @context: Context of the trace-cmd command, will be passed to the plugins + * at load time. + * + * Returns a list of loaded plugins + */ +struct trace_plugin_list* +tracecmd_load_plugins(struct trace_plugin_context *trace) +{ + struct trace_plugin_list *list = NULL; + + load_plugins_hook(trace, ".so", load_plugin, &list); + return list; +} + +/** + * tracecmd_unload_plugins - Unload trace-cmd specific plugins. + * @plugin_list - List of plugins, previously loaded with tracecmd_load_plugins. + * @context: Context of the trace-cmd command, will be passed to the plugins + * at unload time. + * + */ +void +tracecmd_unload_plugins(struct trace_plugin_list *plugin_list, + struct trace_plugin_context *trace) +{ + tracecmd_plugin_unload_func func; + struct trace_plugin_list *list; + + while (plugin_list) { + list = plugin_list; + plugin_list = list->next; + func = dlsym(list->handle, TRACECMD_PLUGIN_UNLOADER_NAME); + if (func) + func(trace); + dlclose(list->handle); + free(list->name); + free(list); + } +}