From nobody Mon Jun 29 18:39:50 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B644EC433F5 for ; Fri, 4 Feb 2022 03:57:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1356864AbiBDD5K (ORCPT ); Thu, 3 Feb 2022 22:57:10 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45086 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229783AbiBDD5G (ORCPT ); Thu, 3 Feb 2022 22:57:06 -0500 Received: from mail-pj1-x102d.google.com (mail-pj1-x102d.google.com [IPv6:2607:f8b0:4864:20::102d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C49B7C061714 for ; Thu, 3 Feb 2022 19:57:06 -0800 (PST) Received: by mail-pj1-x102d.google.com with SMTP id s2-20020a17090ad48200b001b501977b23so11929029pju.2 for ; Thu, 03 Feb 2022 19:57:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=CxDQl1fCqzvo3qX4LpXaLQ366nP4H3lfOsG0DmBCceo=; b=PuljHKFsH8d9ex+gVfK6KgA2SOhfMUIrgYolgbDuNsAIEkCicGQBE0QNR39dQW7pFi T1WNDNH4yXk4iwM/qY/mkGeVn5GwGuWW2A5myyZTTvZ1QQ1URlRgLtMq9buLjQk8TDsq G/9aIQXMBSqpMZCi0/CCINqoCeRZV/xOZdU5fEPAs76954xEjZjjiQ8q5iwI/vwq7jQY p2+Tve6Gs36+3HYOue72FgZbtzNMyQsy2mzCybF+TJvNtVF/HVKLMs7hcstiZFllI1cy qp4iZ6s9bJ3sMBMO+FAm74E93qp0m3xz0Sycsi+vYi0t1Z4PmieYGDn5Hvhr6ns4r9Fg rFog== 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=CxDQl1fCqzvo3qX4LpXaLQ366nP4H3lfOsG0DmBCceo=; b=olhhQne5CYQAoG+Ao1y7SZJj5sI5skkLplNH8PY/JrzD2v6gq1DDxMz/x67XTwgmWG 9MlWyD5bpHMpp1h2fgXTHYYHws52GeREQvBEat5AoJNb4SBr6QaNqZZz1LfLYOk+7WV5 kx8+zfEBAAIG6uSaWCc7Z6Yc4L5l6iQj1/4JItl1QtxKpgSmcdH/X0tYg3ivIe1tuv5g sD3uXEikCE2/A6zmDiWn/ze7rxFYDUYHCBlCvqGIWMPaMYHGXBfvwNgMKcgwvCVeTqFr GTc4g4atwRGGhKFzes7KuDZVLFedGnRRZXbgaxXk0uHq0HXqDqeZNKxgdLgZ8Xxu/hxn m0PQ== X-Gm-Message-State: AOAM530J8q44unYtTFHEW3sRU8wf8Ls1YYKMF76tSY0x+KCffHj9zHuh 1Mz30QVyZThvNWJeOyTYNYY= X-Google-Smtp-Source: ABdhPJw3cIrwHtWNVVbJ1Bnp0gjH0PHsuIGpC91CV8WtGonzJD6JoxxOaU0sU7Is9muDCeymDMoS4Q== X-Received: by 2002:a17:90b:3141:: with SMTP id ip1mr1002055pjb.161.1643947026246; Thu, 03 Feb 2022 19:57:06 -0800 (PST) Received: from localhost.localdomain (li567-56.members.linode.com. [192.155.81.56]) by smtp.gmail.com with ESMTPSA id 204sm506229pfu.91.2022.02.03.19.57.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Feb 2022 19:57:05 -0800 (PST) From: Jeff Xie To: rostedt@goodmis.org Cc: mhiramat@kernel.org, mingo@redhat.com, zanussi@kernel.org, linux-kernel@vger.kernel.org, Jeff Xie Subject: [PATCH v9 1/4] trace: Add trace any kernel object Date: Fri, 4 Feb 2022 11:56:41 +0800 Message-Id: <20220204035644.734878-2-xiehuan09@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220204035644.734878-1-xiehuan09@gmail.com> References: <20220204035644.734878-1-xiehuan09@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Introduce objtrace trigger to get the call flow by tracing any kernel object in the function parameter. The objtrace trigger makes a list of the target object address from the given event parameter, and records all kernel function calls which has the object address in its parameter. Syntax: objtrace:add:obj[:count][if ] Usage: # echo 'p bio_add_page arg1=3D$arg1' > kprobe_events # cd events/kprobes/p_bio_add_page_0 # echo 'objtrace:add:arg1:1 if comm =3D=3D "cat"' > ./trigger # cat /test.txt Signed-off-by: Jeff Xie Reviewed-by: Masami Hiramatsu Tested-by: Masami Hiramatsu --- include/linux/trace_events.h | 1 + kernel/trace/Kconfig | 10 + kernel/trace/Makefile | 1 + kernel/trace/trace.c | 3 + kernel/trace/trace.h | 8 + kernel/trace/trace_entries.h | 17 + kernel/trace/trace_events_trigger.c | 1 + kernel/trace/trace_object.c | 515 ++++++++++++++++++++++++++++ kernel/trace/trace_output.c | 40 +++ 9 files changed, 596 insertions(+) create mode 100644 kernel/trace/trace_object.c diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h index 70c069aef02c..3ccdbc1d25dd 100644 --- a/include/linux/trace_events.h +++ b/include/linux/trace_events.h @@ -685,6 +685,7 @@ enum event_trigger_type { ETT_EVENT_HIST =3D (1 << 4), ETT_HIST_ENABLE =3D (1 << 5), ETT_EVENT_EPROBE =3D (1 << 6), + ETT_TRACE_OBJECT =3D (1 << 7), }; =20 extern int filter_match_preds(struct event_filter *filter, void *rec); diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index a5eb5e7fd624..c51b7eb1508d 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -250,6 +250,16 @@ config FUNCTION_PROFILER =20 If in doubt, say N. =20 +config TRACE_OBJECT + bool "Trace kernel object in function parameter" + depends on FUNCTION_TRACER + depends on HAVE_FUNCTION_ARG_ACCESS_API + select TRACING + default y + help + You can trace the kernel object in the kernel function parameter. + The kernel object is dynamically specified via event trigger. + config STACK_TRACER bool "Trace max stack" depends on HAVE_FUNCTION_TRACER diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile index bedc5caceec7..b924b8e55922 100644 --- a/kernel/trace/Makefile +++ b/kernel/trace/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) +=3D trace_functions_= graph.o obj-$(CONFIG_TRACE_BRANCH_PROFILING) +=3D trace_branch.o obj-$(CONFIG_BLK_DEV_IO_TRACE) +=3D blktrace.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) +=3D fgraph.o +obj-$(CONFIG_TRACE_OBJECT) +=3D trace_object.o ifeq ($(CONFIG_BLOCK),y) obj-$(CONFIG_EVENT_TRACING) +=3D blktrace.o endif diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index a734d5ae34c8..b4513c2bbd52 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -5605,6 +5605,9 @@ static const char readme_msg[] =3D "\t enable_hist::\n" "\t disable_hist::\n" #endif +#ifdef CONFIG_TRACE_OBJECT + "\t objtrace:add:obj[:count][if ]\n" +#endif #ifdef CONFIG_STACKTRACE "\t\t stacktrace\n" #endif diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 0f5e22238cd2..8b66515a36d5 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -54,6 +54,7 @@ enum trace_type { TRACE_TIMERLAT, TRACE_RAW_DATA, TRACE_FUNC_REPEATS, + TRACE_OBJECT, =20 __TRACE_LAST_TYPE, }; @@ -472,6 +473,7 @@ extern void __ftrace_bad_type(void); TRACE_GRAPH_RET); \ IF_ASSIGN(var, ent, struct func_repeats_entry, \ TRACE_FUNC_REPEATS); \ + IF_ASSIGN(var, ent, struct trace_object_entry, TRACE_OBJECT);\ __ftrace_bad_type(); \ } while (0) =20 @@ -1537,6 +1539,12 @@ static inline int register_trigger_hist_cmd(void) { = return 0; } static inline int register_trigger_hist_enable_disable_cmds(void) { return= 0; } #endif =20 +#ifdef CONFIG_TRACE_OBJECT +extern int register_trigger_object_cmd(void); +#else +static inline int register_trigger_object_cmd(void) { return 0; } +#endif + extern int register_trigger_cmds(void); extern void clear_event_triggers(struct trace_array *tr); =20 diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h index cd41e863b51c..bb120d9498a9 100644 --- a/kernel/trace/trace_entries.h +++ b/kernel/trace/trace_entries.h @@ -401,3 +401,20 @@ FTRACE_ENTRY(timerlat, timerlat_entry, __entry->context, __entry->timer_latency) ); + +/* + * trace object entry: + */ +FTRACE_ENTRY(object, trace_object_entry, + + TRACE_OBJECT, + + F_STRUCT( + __field( unsigned long, ip ) + __field( unsigned long, parent_ip ) + __field( unsigned long, object ) + ), + + F_printk(" %ps <-- %ps object:%lx\n", + (void *)__entry->ip, (void *)__entry->parent_ip, __entry->object) +); diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_event= s_trigger.c index d00fee705f9c..c3371a6902af 100644 --- a/kernel/trace/trace_events_trigger.c +++ b/kernel/trace/trace_events_trigger.c @@ -2025,6 +2025,7 @@ __init int register_trigger_cmds(void) register_trigger_enable_disable_cmds(); register_trigger_hist_enable_disable_cmds(); register_trigger_hist_cmd(); + register_trigger_object_cmd(); =20 return 0; } diff --git a/kernel/trace/trace_object.c b/kernel/trace/trace_object.c new file mode 100644 index 000000000000..540e387c613a --- /dev/null +++ b/kernel/trace/trace_object.c @@ -0,0 +1,515 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * trace the kernel object in the kernel function parameter + * Copyright (C) 2021 Jeff Xie + */ + +#define pr_fmt(fmt) "trace_object: " fmt + +#include "trace_output.h" + +#define MAX_TRACED_OBJECT 5 +#define OBJTRACE_CMD_LEN 10 +static DEFINE_PER_CPU(unsigned int, trace_object_event_disable); +static DEFINE_RAW_SPINLOCK(trace_obj_lock); +static struct trace_event_file event_trace_file; +static const int max_args_num =3D 6; +static atomic_t trace_object_ref; +static atomic_t num_traced_obj; +static int exit_trace_object(void); +static int init_trace_object(void); + +static struct object_instance { + void *obj; +} traced_obj[MAX_TRACED_OBJECT]; + +/* objtrace private data */ +struct objtrace_trigger_data { + struct ftrace_event_field *field; + char objtrace_cmd[OBJTRACE_CMD_LEN]; +}; + +static bool object_exist(void *obj) +{ + int i, max; + + max =3D atomic_read(&num_traced_obj); + smp_rmb(); + for (i =3D 0; i < max; i++) { + if (traced_obj[i].obj =3D=3D obj) + return true; + } + return false; +} + +static bool object_empty(void) +{ + return !atomic_read(&num_traced_obj); +} + +static void set_trace_object(void *obj) +{ + unsigned long flags; + + if (in_nmi()) + return; + + if (!obj) + return; + + if (object_exist(obj)) + return; + + /* only this place has write operations */ + raw_spin_lock_irqsave(&trace_obj_lock, flags); + if (atomic_read(&num_traced_obj) =3D=3D MAX_TRACED_OBJECT) { + trace_printk("object_pool is full, can't trace object:0x%px\n", obj); + goto out; + } + traced_obj[atomic_read(&num_traced_obj)].obj =3D obj; + /* make sure the num_traced_obj update always appears after traced_obj up= date */ + smp_wmb(); + atomic_inc(&num_traced_obj); +out: + raw_spin_unlock_irqrestore(&trace_obj_lock, flags); +} + +static void submit_trace_object(unsigned long ip, unsigned long parent_ip, + unsigned long object) +{ + + struct trace_buffer *buffer; + struct ring_buffer_event *event; + struct trace_object_entry *entry; + int pc; + + pc =3D preempt_count(); + event =3D trace_event_buffer_lock_reserve(&buffer, &event_trace_file, + TRACE_OBJECT, sizeof(*entry), pc); + if (!event) + return; + entry =3D ring_buffer_event_data(event); + entry->ip =3D ip; + entry->parent_ip =3D parent_ip; + entry->object =3D object; + + event_trigger_unlock_commit(&event_trace_file, buffer, event, + entry, pc); +} + +static void +trace_object_events_call(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *fregs) +{ + struct pt_regs *pt_regs =3D ftrace_get_regs(fregs); + unsigned long obj; + unsigned int disabled; + int n; + + preempt_disable_notrace(); + + disabled =3D this_cpu_inc_return(trace_object_event_disable); + if (disabled !=3D 1) + goto out; + + if (object_empty()) + goto out; + + for (n =3D 0; n < max_args_num; n++) { + obj =3D regs_get_kernel_argument(pt_regs, n); + if (object_exist((void *)obj)) + submit_trace_object(ip, parent_ip, obj); + /* The parameters of a function may match multiple objects */ + } +out: + this_cpu_dec(trace_object_event_disable); + preempt_enable_notrace(); +} + +static struct ftrace_ops trace_ops =3D { + .func =3D trace_object_events_call, + .flags =3D FTRACE_OPS_FL_SAVE_REGS, +}; + +static void +trace_object_trigger(struct event_trigger_data *data, + struct trace_buffer *buffer, void *rec, + struct ring_buffer_event *event) +{ + struct objtrace_trigger_data *obj_data =3D data->private_data; + struct ftrace_event_field *field; + void *obj =3D NULL; + + field =3D obj_data->field; + memcpy(&obj, rec + field->offset, sizeof(obj)); + set_trace_object(obj); +} + +static void +trace_object_trigger_free(struct event_trigger_ops *ops, + struct event_trigger_data *data) +{ + if (WARN_ON_ONCE(data->ref <=3D 0)) + return; + + data->ref--; + if (!data->ref) { + kfree(data->private_data); + trigger_data_free(data); + } +} + +static void +trace_object_count_trigger(struct event_trigger_data *data, + struct trace_buffer *buffer, void *rec, + struct ring_buffer_event *event) +{ + if (!data->count) + return; + + if (data->count !=3D -1) + (data->count)--; + + trace_object_trigger(data, buffer, rec, event); +} + +static int event_object_trigger_init(struct event_trigger_ops *ops, + struct event_trigger_data *data) +{ + data->ref++; + return 0; +} + +static int +event_trigger_print(const char *name, struct seq_file *m, + void *data, char *filter_str, void *objtrace_data) +{ + long count =3D (long)data; + struct objtrace_trigger_data *obj_data =3D objtrace_data; + + seq_puts(m, name); + + seq_printf(m, ":%s", obj_data->objtrace_cmd); + seq_printf(m, ":%s", obj_data->field->name); + + if (count =3D=3D -1) + seq_puts(m, ":unlimited"); + else + seq_printf(m, ":count=3D%ld", count); + + if (filter_str) + seq_printf(m, " if %s\n", filter_str); + else + seq_putc(m, '\n'); + + return 0; +} + +static int +trace_object_trigger_print(struct seq_file *m, struct event_trigger_ops *o= ps, + struct event_trigger_data *data) +{ + return event_trigger_print("objtrace", m, (void *)data->count, + data->filter_str, data->private_data); +} + +static struct event_trigger_ops objecttrace_trigger_ops =3D { + .trigger =3D trace_object_trigger, + .print =3D trace_object_trigger_print, + .init =3D event_object_trigger_init, + .free =3D trace_object_trigger_free, +}; + +static struct event_trigger_ops objecttrace_count_trigger_ops =3D { + .trigger =3D trace_object_count_trigger, + .print =3D trace_object_trigger_print, + .init =3D event_object_trigger_init, + .free =3D trace_object_trigger_free, +}; + +static struct event_trigger_ops * +objecttrace_get_trigger_ops(char *cmd, char *param) +{ + return param ? &objecttrace_count_trigger_ops : &objecttrace_trigger_ops; +} + +static int register_object_trigger(char *glob, + struct event_trigger_data *data, + struct trace_event_file *file) +{ + struct event_trigger_data *test; + int ret =3D 0; + + lockdep_assert_held(&event_mutex); + + list_for_each_entry(test, &file->triggers, list) { + if (test->cmd_ops->trigger_type =3D=3D data->cmd_ops->trigger_type) { + ret =3D -EEXIST; + goto out; + } + } + + if (data->ops->init) { + ret =3D data->ops->init(data->ops, data); + if (ret < 0) + goto out; + } + + list_add_rcu(&data->list, &file->triggers); + ret++; + + update_cond_flag(file); + if (trace_event_trigger_enable_disable(file, 1) < 0) { + list_del_rcu(&data->list); + update_cond_flag(file); + ret--; + } + init_trace_object(); +out: + return ret; +} + +static void unregister_object_trigger(char *glob, + struct event_trigger_data *test, + struct trace_event_file *file) +{ + struct event_trigger_data *data; + bool unregistered =3D false; + + lockdep_assert_held(&event_mutex); + + list_for_each_entry(data, &file->triggers, list) { + if (data->cmd_ops->trigger_type =3D=3D test->cmd_ops->trigger_type) { + unregistered =3D true; + list_del_rcu(&data->list); + trace_event_trigger_enable_disable(file, 0); + update_cond_flag(file); + break; + } + } + + if (unregistered) { + if (data->ops->free) + data->ops->free(data->ops, data); + exit_trace_object(); + } +} + +static bool field_exist(struct trace_event_file *file, + struct event_command *cmd_ops, + const char *field_name) +{ + struct event_trigger_data *data; + struct objtrace_trigger_data *obj_data; + + lockdep_assert_held(&event_mutex); + + list_for_each_entry(data, &file->triggers, list) { + if (data->cmd_ops->trigger_type =3D=3D cmd_ops->trigger_type) { + obj_data =3D data->private_data; + if (!strcmp(obj_data->field->name, field_name)) + return true; + } + } + + return false; +} + +static int +event_object_trigger_parse(struct event_command *cmd_ops, + struct trace_event_file *file, + char *glob, char *cmd, char *param) +{ + struct event_trigger_data *trigger_data; + struct event_trigger_ops *trigger_ops; + struct objtrace_trigger_data *obj_data; + struct trace_event_call *call; + struct ftrace_event_field *field; + char *objtrace_cmd; + char *trigger =3D NULL; + char *arg; + char *number; + int ret; + bool remove =3D false; + + ret =3D -EINVAL; + if (!param) + goto out; + + /* separate the trigger from the filter (c:a:n [if filter]) */ + trigger =3D strsep(¶m, " \t"); + if (!trigger) + goto out; + if (param) { + param =3D skip_spaces(param); + if (!*param) + param =3D NULL; + } + + objtrace_cmd =3D strsep(&trigger, ":"); + if (!objtrace_cmd || strcmp(objtrace_cmd, "add")) + goto out; + + arg =3D strsep(&trigger, ":"); + if (!arg) + goto out; + call =3D file->event_call; + field =3D trace_find_event_field(call, arg); + if (!field) + goto out; + + if (field->size !=3D sizeof(void *)) + goto out; + + if (glob[0] =3D=3D '!') + remove =3D true; + + if (remove && !field_exist(file, cmd_ops, field->name)) + goto out; + trigger_ops =3D cmd_ops->get_trigger_ops(cmd, trigger); + ret =3D -ENOMEM; + obj_data =3D kzalloc(sizeof(*obj_data), GFP_KERNEL); + if (!obj_data) + goto out; + obj_data->field =3D field; + snprintf(obj_data->objtrace_cmd, OBJTRACE_CMD_LEN, objtrace_cmd); + + trigger_data =3D kzalloc(sizeof(*trigger_data), GFP_KERNEL); + if (!trigger_data) { + kfree(obj_data); + goto out; + } + + trigger_data->count =3D -1; + trigger_data->ops =3D trigger_ops; + trigger_data->cmd_ops =3D cmd_ops; + trigger_data->private_data =3D obj_data; + INIT_LIST_HEAD(&trigger_data->list); + INIT_LIST_HEAD(&trigger_data->named_list); + + if (remove) { + cmd_ops->unreg(glob+1, trigger_data, file); + kfree(obj_data); + kfree(trigger_data); + ret =3D 0; + goto out; + } + + if (trigger) { + number =3D strsep(&trigger, ":"); + + ret =3D -EINVAL; + if (!strlen(number)) + goto out_free; + + /* + * We use the callback data field (which is a pointer) + * as our counter. + */ + ret =3D kstrtoul(number, 0, &trigger_data->count); + if (ret) + goto out_free; + } + + if (!param) /* if param is non-empty, it's supposed to be a filter */ + goto out_reg; + + if (!cmd_ops->set_filter) + goto out_reg; + + ret =3D cmd_ops->set_filter(param, trigger_data, file); + if (ret < 0) + goto out_free; + + out_reg: + /* Up the trigger_data count to make sure reg doesn't free it on failure = */ + event_object_trigger_init(trigger_ops, trigger_data); + ret =3D cmd_ops->reg(glob, trigger_data, file); + /* + * The above returns on success the # of functions enabled, + * but if it didn't find any functions it returns zero. + * Consider no functions a failure too. + */ + if (!ret) { + cmd_ops->unreg(glob, trigger_data, file); + ret =3D -ENOENT; + } else if (ret > 0) + ret =3D 0; + + /* Down the counter of trigger_data or free it if not used anymore */ + trace_object_trigger_free(trigger_ops, trigger_data); + out: + return ret; + + out_free: + if (cmd_ops->set_filter) + cmd_ops->set_filter(NULL, trigger_data, NULL); + kfree(obj_data); + kfree(trigger_data); + goto out; +} + +static struct event_command trigger_object_cmd =3D { + .name =3D "objtrace", + .trigger_type =3D ETT_TRACE_OBJECT, + .flags =3D EVENT_CMD_FL_NEEDS_REC, + .parse =3D event_object_trigger_parse, + .reg =3D register_object_trigger, + .unreg =3D unregister_object_trigger, + .get_trigger_ops =3D objecttrace_get_trigger_ops, + .set_filter =3D set_trigger_filter, +}; + +__init int register_trigger_object_cmd(void) +{ + int ret; + + ret =3D register_event_command(&trigger_object_cmd); + WARN_ON(ret < 0); + + return ret; +} + +static int init_trace_object(void) +{ + int ret; + + if (atomic_inc_return(&trace_object_ref) !=3D 1) { + ret =3D 0; + goto out; + } + + event_trace_file.tr =3D top_trace_array(); + if (WARN_ON(!event_trace_file.tr)) { + ret =3D -1; + atomic_dec(&trace_object_ref); + goto out; + } + ret =3D register_ftrace_function(&trace_ops); +out: + return ret; +} + +static int exit_trace_object(void) +{ + int ret; + + if (WARN_ON_ONCE(atomic_read(&trace_object_ref) <=3D 0)) { + ret =3D -1; + goto out; + } + + if (atomic_dec_return(&trace_object_ref) !=3D 0) { + ret =3D 0; + goto out; + } + + ret =3D unregister_ftrace_function(&trace_ops); + if (ret) { + pr_err("can't unregister ftrace for trace object\n"); + goto out; + } + atomic_set(&num_traced_obj, 0); +out: + return ret; +} diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index 8aa493d25c73..265428154638 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c @@ -1547,6 +1547,45 @@ static struct trace_event trace_func_repeats_event = =3D { .funcs =3D &trace_func_repeats_funcs, }; =20 +/* TRACE_OBJECT */ +static enum print_line_t trace_object_print(struct trace_iterator *iter, i= nt flags, + struct trace_event *event) +{ + struct trace_object_entry *field; + struct trace_seq *s =3D &iter->seq; + + trace_assign_type(field, iter->ent); + print_fn_trace(s, field->ip, field->parent_ip, flags); + trace_seq_printf(s, " object:0x%lx", field->object); + trace_seq_putc(s, '\n'); + + return trace_handle_return(s); +} + +static enum print_line_t trace_object_raw(struct trace_iterator *iter, int= flags, + struct trace_event *event) +{ + struct trace_object_entry *field; + + trace_assign_type(field, iter->ent); + + trace_seq_printf(&iter->seq, "%lx %lx\n", + field->ip, + field->parent_ip); + + return trace_handle_return(&iter->seq); +} + +static struct trace_event_functions trace_object_funcs =3D { + .trace =3D trace_object_print, + .raw =3D trace_object_raw, +}; + +static struct trace_event trace_object_event =3D { + .type =3D TRACE_OBJECT, + .funcs =3D &trace_object_funcs, +}; + static struct trace_event *events[] __initdata =3D { &trace_fn_event, &trace_ctx_event, @@ -1561,6 +1600,7 @@ static struct trace_event *events[] __initdata =3D { &trace_timerlat_event, &trace_raw_data_event, &trace_func_repeats_event, + &trace_object_event, NULL }; =20 --=20 2.25.1 From nobody Mon Jun 29 18:39:50 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CD4E8C433EF for ; Fri, 4 Feb 2022 03:57:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1356876AbiBDD5O (ORCPT ); Thu, 3 Feb 2022 22:57:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45110 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1356856AbiBDD5K (ORCPT ); Thu, 3 Feb 2022 22:57:10 -0500 Received: from mail-pg1-x52d.google.com (mail-pg1-x52d.google.com [IPv6:2607:f8b0:4864:20::52d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ED2FFC06173B for ; Thu, 3 Feb 2022 19:57:09 -0800 (PST) Received: by mail-pg1-x52d.google.com with SMTP id p125so4022009pga.2 for ; Thu, 03 Feb 2022 19:57:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Gk4YQW4mvyLv29ht4XvYNml58oYheXfyPj1WiP5QNEA=; b=g6aq8M9z9V4N+5+oVJs5gXEPrOvmuhLHCv1WfF7KE67xoZa+TzA59Jioz3MX0sw3TN iAp1lD3sm5Wzy+UtUJ6epghk+H4ds8AbrTCjXAngqqlnll2a36qEYIPal+3rEyNKSjMy vaazEcfdDslZJIRImxcuPjst0WkvJxDHDVGDki1U6Q/cIFMdtYEo6s9RLBpfymBv+HeG NgNpY9uvt8+KLMsaLrZuQStqFXof7n6vsAOTy06O3eSfXoaeYXSRdDoEF4OXUHwZYbGj AuXlV1Tz415bMF5NkLa9FPFtaetUvk1FLYFzvAct75KT0E7ZhqeEKAguw9Svd8Lv1N2O Lz/A== 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=Gk4YQW4mvyLv29ht4XvYNml58oYheXfyPj1WiP5QNEA=; b=7DQOPaS/Y5bIPtmb7azh1p5Mes+iHjNnVsPdaW7aC85aOEDV6RlZzxCc8kgujwOzok Fg3NhVLwF/CUFFnFpX+7SBniDW1pCtbEAf/RAXiOd1JXnHWtyGIz2Xm63Q9XsFBI91VU /f5TnmWSO76IUsTCn+K29NLUqT72biGLlsAonuRExaOHzCiPqTqKk3GqeFWn45k4rRfk EE+n2RClyXrZgQh09038fsZ5EXuhC29kQAPMOc8oxut6IwTgbab1kHvqLJ+pyqH/Sm+q oDzoqh41c4q5UqgRYcsNgabG5d9P3OAnQhIO4QmHMJAo3obH3bZgIMqMIZIzXX09cPpM 5NBA== X-Gm-Message-State: AOAM532dKE2hYSWw5v783LHgIzPcqTMQ3XAYrKaOdUXBxHtGueJtQtEy oqZUylO16A4QjlNoM93uHw7JoJV1bhk= X-Google-Smtp-Source: ABdhPJwHn533iHe5zTbgiTRb808+sMiV3NU8Vi0m1pILcAXqdtW1YzJfCEMdReW2G5m1dTcFpw+eDw== X-Received: by 2002:a62:8f97:: with SMTP id n145mr1243774pfd.14.1643947029417; Thu, 03 Feb 2022 19:57:09 -0800 (PST) Received: from localhost.localdomain (li567-56.members.linode.com. [192.155.81.56]) by smtp.gmail.com with ESMTPSA id 204sm506229pfu.91.2022.02.03.19.57.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Feb 2022 19:57:08 -0800 (PST) From: Jeff Xie To: rostedt@goodmis.org Cc: mhiramat@kernel.org, mingo@redhat.com, zanussi@kernel.org, linux-kernel@vger.kernel.org, Jeff Xie Subject: [PATCH v9 2/4] trace/objtrace: get the value of the object Date: Fri, 4 Feb 2022 11:56:42 +0800 Message-Id: <20220204035644.734878-3-xiehuan09@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220204035644.734878-1-xiehuan09@gmail.com> References: <20220204035644.734878-1-xiehuan09@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Using objtrace trigger to get the value of the object which from the kernel function parameter. Syntax: objtrace:add:obj[,offset][:type][:count][if ] Usage: # echo 'p bio_add_page arg1=3D$arg1' > ./kprobe_events # gdb vmlinux (gdb) p &(((struct bio *)0)->bi_iter.bi_size) $1 =3D (unsigned int *) 0x28 # echo 'objtrace:add:arg1,0x28:u32:1 if comm =3D=3D "cat"' > ./events/kpro= bes/ \ p_bio_add_page_0/trigger # cat /test.txt Signed-off-by: Jeff Xie Reviewed-by: Masami Hiramatsu Tested-by: Masami Hiramatsu --- kernel/trace/trace.c | 2 +- kernel/trace/trace_entries.h | 5 +- kernel/trace/trace_object.c | 231 +++++++++++++++++++++++++++++------ kernel/trace/trace_output.c | 6 +- 4 files changed, 203 insertions(+), 41 deletions(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index b4513c2bbd52..5f145837d2ff 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -5606,7 +5606,7 @@ static const char readme_msg[] =3D "\t disable_hist::\n" #endif #ifdef CONFIG_TRACE_OBJECT - "\t objtrace:add:obj[:count][if ]\n" + "\t objtrace:add:obj[,offset][:type][:count][if ]\n" #endif #ifdef CONFIG_STACKTRACE "\t\t stacktrace\n" diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h index bb120d9498a9..2407c45a568c 100644 --- a/kernel/trace/trace_entries.h +++ b/kernel/trace/trace_entries.h @@ -413,8 +413,9 @@ FTRACE_ENTRY(object, trace_object_entry, __field( unsigned long, ip ) __field( unsigned long, parent_ip ) __field( unsigned long, object ) + __field( unsigned long, value ) ), =20 - F_printk(" %ps <-- %ps object:%lx\n", - (void *)__entry->ip, (void *)__entry->parent_ip, __entry->object) + F_printk(" %ps <-- %ps object:%lx value:%lx\n", (void *)__entry->ip, + (void *)__entry->parent_ip, __entry->object, __entry->value) ); diff --git a/kernel/trace/trace_object.c b/kernel/trace/trace_object.c index 540e387c613a..8eb2d61c277a 100644 --- a/kernel/trace/trace_object.c +++ b/kernel/trace/trace_object.c @@ -19,14 +19,34 @@ static atomic_t num_traced_obj; static int exit_trace_object(void); static int init_trace_object(void); =20 +/* + * get the offset from the special object and + * the type size of the value + */ static struct object_instance { void *obj; + int obj_offset; + int obj_value_type_size; } traced_obj[MAX_TRACED_OBJECT]; =20 /* objtrace private data */ struct objtrace_trigger_data { struct ftrace_event_field *field; char objtrace_cmd[OBJTRACE_CMD_LEN]; + int obj_offset; + int obj_value_type_size; +}; + +/* get the type size for the special object */ +struct objtrace_fetch_type { + char *name; + int type_size; +}; + +enum objattr { + OBJ_OFFSET, + OBJ_VAL_TYPE_SIZE, + MAX_OBJ_ATTR }; =20 static bool object_exist(void *obj) @@ -42,13 +62,37 @@ static bool object_exist(void *obj) return false; } =20 +static int get_object_attr(void *obj, int objattr, int *result) +{ + int i, max; + + max =3D atomic_read(&num_traced_obj); + smp_rmb(); + for (i =3D 0; i < max; i++) { + if (traced_obj[i].obj =3D=3D obj) { + switch (objattr) { + case OBJ_OFFSET: + *result =3D traced_obj[i].obj_offset; + return 0; + case OBJ_VAL_TYPE_SIZE: + *result =3D traced_obj[i].obj_value_type_size; + return 0; + default: + return -EINVAL; + } + } + } + return -EINVAL; +} + static bool object_empty(void) { return !atomic_read(&num_traced_obj); } =20 -static void set_trace_object(void *obj) +static void set_trace_object(void *obj, int obj_offset, int obj_value_type= _size) { + unsigned int traced_objs; unsigned long flags; =20 if (in_nmi()) @@ -62,11 +106,14 @@ static void set_trace_object(void *obj) =20 /* only this place has write operations */ raw_spin_lock_irqsave(&trace_obj_lock, flags); - if (atomic_read(&num_traced_obj) =3D=3D MAX_TRACED_OBJECT) { + traced_objs =3D atomic_read(&num_traced_obj); + if (traced_objs =3D=3D MAX_TRACED_OBJECT) { trace_printk("object_pool is full, can't trace object:0x%px\n", obj); goto out; } - traced_obj[atomic_read(&num_traced_obj)].obj =3D obj; + traced_obj[traced_objs].obj =3D obj; + traced_obj[traced_objs].obj_value_type_size =3D obj_value_type_size; + traced_obj[traced_objs].obj_offset =3D obj_offset; /* make sure the num_traced_obj update always appears after traced_obj up= date */ smp_wmb(); atomic_inc(&num_traced_obj); @@ -75,7 +122,7 @@ static void set_trace_object(void *obj) } =20 static void submit_trace_object(unsigned long ip, unsigned long parent_ip, - unsigned long object) + unsigned long object, unsigned long value) { =20 struct trace_buffer *buffer; @@ -92,19 +139,52 @@ static void submit_trace_object(unsigned long ip, unsi= gned long parent_ip, entry->ip =3D ip; entry->parent_ip =3D parent_ip; entry->object =3D object; + entry->value =3D value; =20 event_trigger_unlock_commit(&event_trace_file, buffer, event, entry, pc); } =20 +static inline long get_object_value(unsigned long *val, void *obj, int typ= e_size) +{ + char tmp[sizeof(u64)]; + long ret =3D 0; + + ret =3D copy_from_kernel_nofault(tmp, obj, sizeof(tmp)); + if (ret) + return ret; + switch (type_size) { + case 1: { + *val =3D (unsigned long)*(u8 *)tmp; + break; + } + case 2: { + *val =3D (unsigned long)*(u16 *)tmp; + break; + } + case 4: { + *val =3D (unsigned long)*(u32 *)tmp; + break; + } + case 8: { + *val =3D (unsigned long)*(u64 *)tmp; + break; + } + default: + return -EINVAL; + } + + return 0; +} + static void trace_object_events_call(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct ftrace_regs *fregs) { struct pt_regs *pt_regs =3D ftrace_get_regs(fregs); - unsigned long obj; + int n, ret, val_type_size, obj_offset; + unsigned long obj, val; unsigned int disabled; - int n; =20 preempt_disable_notrace(); =20 @@ -117,8 +197,19 @@ trace_object_events_call(unsigned long ip, unsigned lo= ng parent_ip, =20 for (n =3D 0; n < max_args_num; n++) { obj =3D regs_get_kernel_argument(pt_regs, n); - if (object_exist((void *)obj)) - submit_trace_object(ip, parent_ip, obj); + if (object_exist((void *)obj)) { + ret =3D get_object_attr((void *)obj, OBJ_OFFSET, &obj_offset); + if (unlikely(ret) < 0) + goto out; + + get_object_attr((void *)obj, OBJ_VAL_TYPE_SIZE, &val_type_size); + if (unlikely(ret) < 0) + goto out; + + if (get_object_value(&val, (void *)(obj + obj_offset), val_type_size)) + continue; + submit_trace_object(ip, parent_ip, obj, val); + } /* The parameters of a function may match multiple objects */ } out: @@ -138,11 +229,12 @@ trace_object_trigger(struct event_trigger_data *data, { struct objtrace_trigger_data *obj_data =3D data->private_data; struct ftrace_event_field *field; - void *obj =3D NULL; + void *obj; =20 field =3D obj_data->field; memcpy(&obj, rec + field->offset, sizeof(obj)); - set_trace_object(obj); + /* set the offset from the special object and the type size of the value*/ + set_trace_object(obj, obj_data->obj_offset, obj_data->obj_value_type_size= ); } =20 static void @@ -180,18 +272,45 @@ static int event_object_trigger_init(struct event_tri= gger_ops *ops, return 0; } =20 +static const struct objtrace_fetch_type objtrace_fetch_types[] =3D { + {"u8", 1}, + {"s8", 1}, + {"x8", 1}, + {"u16", 2}, + {"s16", 2}, + {"x16", 2}, + {"u32", 4}, + {"s32", 4}, + {"x32", 4}, + {"u64", 8}, + {"s64", 8}, + {"x64", 8}, + {} +}; + static int event_trigger_print(const char *name, struct seq_file *m, - void *data, char *filter_str, void *objtrace_data) + void *data, char *filter_str, void *objtrace_data) { + int i; long count =3D (long)data; struct objtrace_trigger_data *obj_data =3D objtrace_data; + const char *value_type_name; =20 seq_puts(m, name); =20 seq_printf(m, ":%s", obj_data->objtrace_cmd); seq_printf(m, ":%s", obj_data->field->name); + if (obj_data->obj_offset) + seq_printf(m, ",0x%x", obj_data->obj_offset); =20 + for (i =3D 0; objtrace_fetch_types[i].name; i++) { + if (objtrace_fetch_types[i].type_size =3D=3D obj_data->obj_value_type_si= ze) { + value_type_name =3D objtrace_fetch_types[i].name; + break; + } + } + seq_printf(m, ":%s", value_type_name); if (count =3D=3D -1) seq_puts(m, ":unlimited"); else @@ -325,18 +444,20 @@ event_object_trigger_parse(struct event_command *cmd_= ops, struct objtrace_trigger_data *obj_data; struct trace_event_call *call; struct ftrace_event_field *field; - char *objtrace_cmd; - char *trigger =3D NULL; - char *arg; - char *number; - int ret; + char *type, *tr, *obj, *tmp, *trigger =3D NULL; + char *number, *objtrace_cmd; + int ret, i, def_type_size, obj_value_type_size =3D 0; + long offset =3D 0; bool remove =3D false; =20 ret =3D -EINVAL; if (!param) goto out; =20 - /* separate the trigger from the filter (c:a:n [if filter]) */ + /* + * separate the trigger from the filter: + * objtrace:add:OBJ[,OFFS][:TYPE][:COUNT] [if filter] + */ trigger =3D strsep(¶m, " \t"); if (!trigger) goto out; @@ -345,16 +466,27 @@ event_object_trigger_parse(struct event_command *cmd_= ops, if (!*param) param =3D NULL; } - objtrace_cmd =3D strsep(&trigger, ":"); if (!objtrace_cmd || strcmp(objtrace_cmd, "add")) goto out; =20 - arg =3D strsep(&trigger, ":"); - if (!arg) + obj =3D strsep(&trigger, ":"); + if (!obj) goto out; + + tr =3D strchr(obj, ','); + if (!tr) + offset =3D 0; + else { + *tr++ =3D '\0'; + ret =3D kstrtol(tr, 0, &offset); + if (ret) + goto out; + } + + ret =3D -EINVAL; call =3D file->event_call; - field =3D trace_find_event_field(call, arg); + field =3D trace_find_event_field(call, obj); if (!field) goto out; =20 @@ -365,36 +497,65 @@ event_object_trigger_parse(struct event_command *cmd_= ops, remove =3D true; =20 if (remove && !field_exist(file, cmd_ops, field->name)) - goto out; - trigger_ops =3D cmd_ops->get_trigger_ops(cmd, trigger); - ret =3D -ENOMEM; - obj_data =3D kzalloc(sizeof(*obj_data), GFP_KERNEL); - if (!obj_data) goto out; - obj_data->field =3D field; - snprintf(obj_data->objtrace_cmd, OBJTRACE_CMD_LEN, objtrace_cmd); - + ret =3D -ENOMEM; trigger_data =3D kzalloc(sizeof(*trigger_data), GFP_KERNEL); - if (!trigger_data) { - kfree(obj_data); + if (!trigger_data) goto out; - } =20 trigger_data->count =3D -1; - trigger_data->ops =3D trigger_ops; trigger_data->cmd_ops =3D cmd_ops; - trigger_data->private_data =3D obj_data; INIT_LIST_HEAD(&trigger_data->list); INIT_LIST_HEAD(&trigger_data->named_list); =20 if (remove) { cmd_ops->unreg(glob+1, trigger_data, file); - kfree(obj_data); kfree(trigger_data); ret =3D 0; goto out; } =20 + ret =3D -EINVAL; + def_type_size =3D sizeof(void *); + if (!trigger) { + obj_value_type_size =3D def_type_size; + goto skip_get_type; + } + + tmp =3D trigger; + type =3D strsep(&trigger, ":"); + if (!type) + obj_value_type_size =3D def_type_size; + else if (isdigit(type[0])) { + obj_value_type_size =3D def_type_size; + trigger =3D tmp; + } else { + for (i =3D 0; objtrace_fetch_types[i].name; i++) { + if (strcmp(objtrace_fetch_types[i].name, type) =3D=3D 0) { + obj_value_type_size =3D objtrace_fetch_types[i].type_size; + break; + } + } + } + if (!obj_value_type_size) + goto out; +skip_get_type: + trigger_ops =3D cmd_ops->get_trigger_ops(cmd, trigger); + trigger_data->ops =3D trigger_ops; + + ret =3D -ENOMEM; + obj_data =3D kzalloc(sizeof(*obj_data), GFP_KERNEL); + if (!obj_data) { + kfree(trigger_data); + goto out; + } + + obj_data->field =3D field; + obj_data->obj_offset =3D offset; + obj_data->obj_value_type_size =3D obj_value_type_size; + snprintf(obj_data->objtrace_cmd, OBJTRACE_CMD_LEN, objtrace_cmd); + trigger_data->private_data =3D obj_data; + if (trigger) { number =3D strsep(&trigger, ":"); =20 diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index 265428154638..04804f53cadd 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c @@ -1557,6 +1557,7 @@ static enum print_line_t trace_object_print(struct tr= ace_iterator *iter, int fla trace_assign_type(field, iter->ent); print_fn_trace(s, field->ip, field->parent_ip, flags); trace_seq_printf(s, " object:0x%lx", field->object); + trace_seq_printf(s, " value:0x%lx", field->value); trace_seq_putc(s, '\n'); =20 return trace_handle_return(s); @@ -1569,9 +1570,8 @@ static enum print_line_t trace_object_raw(struct trac= e_iterator *iter, int flags =20 trace_assign_type(field, iter->ent); =20 - trace_seq_printf(&iter->seq, "%lx %lx\n", - field->ip, - field->parent_ip); + trace_seq_printf(&iter->seq, "%lx %lx %lx %lx\n", field->ip, + field->parent_ip, field->object, field->value); =20 return trace_handle_return(&iter->seq); } --=20 2.25.1 From nobody Mon Jun 29 18:39:50 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B301FC433F5 for ; Fri, 4 Feb 2022 03:57:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1356882AbiBDD5T (ORCPT ); Thu, 3 Feb 2022 22:57:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45136 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1356873AbiBDD5N (ORCPT ); Thu, 3 Feb 2022 22:57:13 -0500 Received: from mail-pj1-x102b.google.com (mail-pj1-x102b.google.com [IPv6:2607:f8b0:4864:20::102b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0ACC8C061714 for ; Thu, 3 Feb 2022 19:57:13 -0800 (PST) Received: by mail-pj1-x102b.google.com with SMTP id o16-20020a17090aac1000b001b62f629953so11905382pjq.3 for ; Thu, 03 Feb 2022 19:57:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=3RAHC5JpxAqYMofiRYRDeUYE27k98N5i2YcPubXjat4=; b=SJyXuCfQLgYHmeTZ7aZCE98hIP2BB4/vL0Duh8M6pd27jCJyirDKscDdTAp7zstDb6 SXnRBLJ58sk8+GfxsLGYzd20RSvcC6bwMdNY67BHXO0ZyfC2Hsk9m1em0YABkNWpC0r5 hnmFLqBqbdw3X9ahgizBIXf85JIxMwv/dTW4d1ZkeNmYyBR4Tbk9hWv7Z7fVAST0dmxg qQbBUYEwXjGJ0cc7k49Na0+LRgRrDO+ilL4xyLqDsllXcPa8bsP8tlaCarHcRcfqlQnG OywyZx7eury2E7Ed8tOOzmx1a8RGi3jKUe5gUu9OdyPdkIkAzjd4ucvhVistRYz2SYKW Iomw== 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=3RAHC5JpxAqYMofiRYRDeUYE27k98N5i2YcPubXjat4=; b=4TSacPkWZrM/Y13Iv8jzqzZcCVoVlxlt0ylO+fGqSOpg8bofhE45jlrilixj00upNj UZ+wnmJn0Rlzg3t7w1GujVzSgGIYpqWJAS1Azppl/WuhusIbM1LxJllBvokGQTC2z1g0 Ol7GFXWAJkjHnRLJR4x0GUZV7FXcnF9nvcTyuAK+MUg9i8pfwmd+S3xm0+Fxety7iEjK 2gTxHEldYZECeHyTYKsoFyIHpNmt+uZtTfPObHnjAEHcmk/qtYuv8XlJOZHjTb+9YjNS W84r3ngNVX0Shz5+T9rWz+FSf/qI+oCAdOTYZlFfk63zMN+T3MoY2Dwt5/0HxGxRjcXj JwFw== X-Gm-Message-State: AOAM533cUpukX+gh/jTV9wlCvbmMg4Nq9g7u8ZmFP3xWjQmB9Ra5n8Ko ZcLasP32M3p9sLIaWEEDaKTIFZVX2NU= X-Google-Smtp-Source: ABdhPJyqTzTqqws9bis9joTymlm/KreHOU9PXVebXLbPPPopXwlBsT1+9Ed9ZBC0T4irvJEB9e3zKg== X-Received: by 2002:a17:90b:1012:: with SMTP id gm18mr1065375pjb.84.1643947032421; Thu, 03 Feb 2022 19:57:12 -0800 (PST) Received: from localhost.localdomain (li567-56.members.linode.com. [192.155.81.56]) by smtp.gmail.com with ESMTPSA id 204sm506229pfu.91.2022.02.03.19.57.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Feb 2022 19:57:11 -0800 (PST) From: Jeff Xie To: rostedt@goodmis.org Cc: mhiramat@kernel.org, mingo@redhat.com, zanussi@kernel.org, linux-kernel@vger.kernel.org, Jeff Xie Subject: [PATCH v9 3/4] trace/objtrace: Add testcases for objtrace Date: Fri, 4 Feb 2022 11:56:43 +0800 Message-Id: <20220204035644.734878-4-xiehuan09@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220204035644.734878-1-xiehuan09@gmail.com> References: <20220204035644.734878-1-xiehuan09@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add a series of testcases to illustrate correct and incorrect usage of objtrace trigger. Signed-off-by: Jeff Xie Reviewed-by: Masami Hiramatsu Tested-by: Masami Hiramatsu --- .../ftrace/test.d/trigger/trigger-objtrace.tc | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/trigger-o= bjtrace.tc diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-objtrace= .tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-objtrace.tc new file mode 100644 index 000000000000..d894442b6a30 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-objtrace.tc @@ -0,0 +1,41 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: event trigger - test objtrace-trigger +# requires: kprobe_events "objtrace":README + +fail() { #msg + echo $1 + exit_fail +} + +echo 'p bio_add_page arg1=3D$arg1 arg2=3D$arg2' > kprobe_events + +FEATURE=3D`grep objtrace events/kprobes/p_bio_add_page_0/trigger` +if [ -z "$FEATURE" ]; then + echo "objtrace trigger is not supported" + exit_unsupported +fi + +echo "Test objtrace trigger" +echo 'objtrace:add:arg1,0x28:u32:1 if comm =3D=3D "cat"' > \ + events/kprobes/p_bio_add_page_0/trigger +if [ -z $? ]; then + fail "objtrace trigger syntax error" +fi + +echo "Test objtrace semantic errors" + +# Being lack of objtrace command +! echo 'objtrace:arg1,0x28:u32:1' > events/kprobes/p_bio_add_page_0/trigger +# Bad parameter name +! echo 'objtrace:add:argx:u32:1' > events/kprobes/p_bio_add_page_0/trigger +# The parameter existed on event +! echo 'objtrace:add:arg2:u32:1' > events/kprobes/p_bio_add_page_0/trigger + +echo "reset objtrace trigger" + +echo '!objtrace:add:arg1,0x28:u32' > \ + events/kprobes/p_bio_add_page_0/trigger +echo '-:p_bio_add_page_0' >> ./kprobe_events + +exit 0 --=20 2.25.1 From nobody Mon Jun 29 18:39:50 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 05379C433EF for ; Fri, 4 Feb 2022 03:57:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1356893AbiBDD5V (ORCPT ); Thu, 3 Feb 2022 22:57:21 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45152 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1356883AbiBDD5P (ORCPT ); Thu, 3 Feb 2022 22:57:15 -0500 Received: from mail-pl1-x62c.google.com (mail-pl1-x62c.google.com [IPv6:2607:f8b0:4864:20::62c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D6F37C06173E for ; Thu, 3 Feb 2022 19:57:15 -0800 (PST) Received: by mail-pl1-x62c.google.com with SMTP id x11so4072105plg.6 for ; Thu, 03 Feb 2022 19:57:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=DekJ8UcrLNS24H0kwzTpTKU7qq2O3Iea6VLoLOi4nfQ=; b=Und4MgI6NSGJyfDIEDMUVl6dQVuLuW8aIUfA6RNo/dnXNEI1klN/+DJFL57J/qJJE/ 09cG8yNUxPkfTKJtNYNkNoc6RBf9vlzHEYLIVIR6utl8z57x430573w8jsV7k8xW8Gkw HlsXHrskEdSqrzPp1a+uRx9gaG/XuYfZOSTIJe/lxubomLmzAt3537oxhPCpKWKcuUL+ /OHZJ9xnnw9YX8Qsj5Hhm9apzdW64H1/vbxLxHWHLjMsM/WdrG1LOZ/V0anF9neUg7vn e+4ZksPLG6jOt3I+iZDrECRLfWTdGEsQMA0EtP38bSE4ZPHdb+SRSoXjJdKQPd1zU1vi Er6Q== 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=DekJ8UcrLNS24H0kwzTpTKU7qq2O3Iea6VLoLOi4nfQ=; b=upcE/WAtdJr9Cpthp+gQj4JkXsR8Z1njilcf3+4nHriCyVgdacROGUU1kCKcxyLd9H lJ2KHqMNVNtPo3Bb16KAQb+1UtWmj4qTV45w6OzaNjJAciYYgXT9m5gDJnCFKCNiL0wr k/scwZIlZvhCXTI4gYEqHoFojk+DrrPCwCeyl6r9Dg9L7ecenoVkWRy6AoafFW/b70Dr sv3kES+5WnxdNuSKC4hnX/G6k9I1a7wGjVyqxsaxCCbBo9PbDZbSkUWwxvZL3WjYYON1 q7cUiNNiDJNOCPNrE6MiBwliKNE+z4Wk1+1l7DH9NyfSwarWrOpdze2AaFVJ5I2sk2Ni 1iKw== X-Gm-Message-State: AOAM532TyBGolZwFw6cF+JNG2Lu2iyL0no8khUzKAxBXon8P6vVZv4Bz T/3MzTl3zn4kJxvqEkXa5kzviNDHFCo= X-Google-Smtp-Source: ABdhPJwa7oYr69h3LKDsg9zzXwc50Ddh8Oo4oBrL/VxVbo0wLHkpzn+jN8ZsZw5g+IF+FXzIGzrmxA== X-Received: by 2002:a17:90a:d343:: with SMTP id i3mr1048267pjx.104.1643947035352; Thu, 03 Feb 2022 19:57:15 -0800 (PST) Received: from localhost.localdomain (li567-56.members.linode.com. [192.155.81.56]) by smtp.gmail.com with ESMTPSA id 204sm506229pfu.91.2022.02.03.19.57.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Feb 2022 19:57:14 -0800 (PST) From: Jeff Xie To: rostedt@goodmis.org Cc: mhiramat@kernel.org, mingo@redhat.com, zanussi@kernel.org, linux-kernel@vger.kernel.org, Jeff Xie Subject: [PATCH v9 4/4] trace/objtrace: Add documentation for objtrace Date: Fri, 4 Feb 2022 11:56:44 +0800 Message-Id: <20220204035644.734878-5-xiehuan09@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220204035644.734878-1-xiehuan09@gmail.com> References: <20220204035644.734878-1-xiehuan09@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Added documentation explaining how to use objtrace trigger to get the value of the object. Signed-off-by: Jeff Xie Reviewed-by: Masami Hiramatsu Tested-by: Masami Hiramatsu --- Documentation/trace/events.rst | 83 ++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/Documentation/trace/events.rst b/Documentation/trace/events.rst index c47f381d0c00..0dc475160133 100644 --- a/Documentation/trace/events.rst +++ b/Documentation/trace/events.rst @@ -546,6 +546,89 @@ The following commands are supported: =20 See Documentation/trace/histogram.rst for details and examples. =20 +- objtrace + + This command provides a way to get the value of any object, The object + can be obtained from the dynamic event(kprobe_event/uprobe_event) or the + static event(tracepoint). + + Usage: + When using the kprobe event, only need to set the objtrace(a new trigger= ), + we can get the value of the object. The object is from the setting of the + kprobe event. + + For example: + For the function bio_add_page(): + + int bio_add_page(struct bio *bio, struct page *page, + unsigned int len, unsigned int offset) + + Firstly, we can set the base of the object, thus the first string "arg1" + stands for the value of the first parameter of this function bio_add_gag= e(), + + # echo 'p bio_add_page arg1=3D$arg1' > ./kprobe_events + + Secondly, we can get the value dynamically based on above object. + + find the offset of the bi_size in struct bio: + $ gdb vmlinux + (gdb) p &(((struct bio *)0)->bi_iter.bi_size) + $1 =3D (unsigned int *) 0x28 + + # echo 'objtrace:add:arg1,0x28:u32:1 if comm =3D=3D "cat"' > ./events/kp= robes/ \ + p_bio_add_page_0/trigger + + # cd /sys/kernel/debug/tracing/ + # echo 'p bio_add_page arg1=3D$arg1' > ./kprobe_events + # echo 'objtrace:add:arg1,0x28:u32:1 if comm =3D=3D "cat"' > ./events/kp= robes/p_bio_add_page_0/trigger + + # du -sh /test.txt + 12.0K /test.txt + + # cat /test.txt > /dev/null + # cat ./trace + # tracer: nop + # + # entries-in-buffer/entries-written: 128/128 #P:4 + # + # _-----=3D> irqs-off/BH-disabled + # / _----=3D> need-resched + # | / _---=3D> hardirq/softirq + # || / _--=3D> preempt-depth + # ||| / _-=3D> migrate-disable + # |||| / delay + # TASK-PID CPU# ||||| TIMESTAMP FUNCTION + # | | | ||||| | | + cat-117 [002] ...1. 1.602243: __bio_try_merge_page = <-bio_add_page object:0xffff88811bee4000 value:0x0 + cat-117 [002] ...1. 1.602244: __bio_add_page <-bio_= add_page object:0xffff88811bee4000 value:0x0 + cat-117 [002] ...2. 1.602244: bio_add_page <-ext4_m= page_readpages object:0xffff88811bee4000 value:0x1000 + cat-117 [002] ...1. 1.602245: __bio_try_merge_page = <-bio_add_page object:0xffff88811bee4000 value:0x1000 + cat-117 [002] ...1. 1.602245: __bio_add_page <-bio_= add_page object:0xffff88811bee4000 value:0x1000 + cat-117 [002] ...2. 1.602245: bio_add_page <-ext4_m= page_readpages object:0xffff88811bee4000 value:0x2000 + cat-117 [002] ...1. 1.602245: __bio_try_merge_page = <-bio_add_page object:0xffff88811bee4000 value:0x2000 + cat-117 [002] ...1. 1.602245: __bio_add_page <-bio_= add_page object:0xffff88811bee4000 value:0x2000 + cat-117 [002] ...1. 1.602245: submit_bio <-ext4_mpa= ge_readpages object:0xffff88811bee4000 value:0x3000 + cat-117 [002] ...1. 1.602245: submit_bio_noacct <-e= xt4_mpage_readpages object:0xffff88811bee4000 value:0x3000 + cat-117 [002] ...1. 1.602246: __submit_bio <-submit= _bio_noacct object:0xffff88811bee4000 value:0x3000 + cat-117 [002] ...1. 1.602246: submit_bio_checks <-_= _submit_bio object:0xffff88811bee4000 value:0x3000 + cat-117 [002] ...1. 1.602246: __cond_resched <-subm= it_bio_checks object:0xffff88811bee4000 value:0x3000 + cat-117 [002] ...1. 1.602246: should_fail_bio <-sub= mit_bio_checks object:0xffff88811bee4000 value:0x3000 + cat-117 [002] ...1. 1.602246: blk_mq_submit_bio <-s= ubmit_bio_noacct object:0xffff88811bee4000 value:0x3000 + cat-117 [002] ...1. 1.602246: blk_attempt_plug_merg= e <-blk_mq_submit_bio object:0xffff88811bee4000 value:0x3000 + cat-117 [002] ...1. 1.602246: blk_mq_sched_bio_merg= e <-blk_mq_submit_bio object:0xffff88811bee4000 value:0x3000 + cat-117 [002] ...1. 1.602247: __rcu_read_lock <-blk= _mq_submit_bio object:0xffff88811bee4000 value:0x3000 + cat-117 [002] ...1. 1.602247: __rcu_read_unlock <-b= lk_mq_submit_bio object:0xffff88811bee4000 value:0x3000 + cat-117 [002] ...1. 1.602247: __blk_mq_alloc_reques= ts <-blk_mq_submit_bio object:0xffff88811bee4000 value:0x3000 + -0 [002] d..3. 1.602298: bio_endio <-blk_updat= e_request object:0xffff88811bee4000 value:0x0 + -0 [002] d..3. 1.602298: mpage_end_io <-blk_up= date_request object:0xffff88811bee4000 value:0x0 + -0 [002] d..3. 1.602298: __read_end_io <-blk_u= pdate_request object:0xffff88811bee4000 value:0x0 + -0 [002] d..3. 1.602300: bio_put <-blk_update_= request object:0xffff88811bee4000 value:0x0 + -0 [002] d..3. 1.602300: bio_free <-blk_update= _request object:0xffff88811bee4000 value:0x0 + -0 [002] d..3. 1.602300: mempool_free <-blk_up= date_request object:0xffff88811bee4000 value:0x0 + -0 [002] d..3. 1.602300: mempool_free_slab <-b= lk_update_request object:0xffff88811bee4000 value:0x0 + -0 [002] d..3. 1.602300: kmem_cache_free <-blk= _update_request object:0xffff88811bee4000 value:0x0 + ... + 7. In-kernel trace event API =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D =20 --=20 2.25.1