linux-kselftest.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
@ 2018-04-25 12:16 mhiramat
  2018-04-25 12:16 ` Masami Hiramatsu
                   ` (19 more replies)
  0 siblings, 20 replies; 72+ messages in thread
From: mhiramat @ 2018-04-25 12:16 UTC (permalink / raw)


Hi,

This is the 7th version of the fetch-arg improvement series.
This includes variable changes on fetcharg framework like,

- Add fetcharg testcases (syntax, argN, symbol, string and array)
  and probepoint testcase.
- Rewrite fetcharg framework with fetch_insn, switch-case based
  instead of function pointer.
- Add "symbol" type support, which shows symbol+offset instead of
  address value.
- Add "$argN" fetcharg, which fetches function parameters.
  (currently only for x86-64)
- Add array type support (including string arrary :) ) ,
  which enables to get fixed length array from probe-events.
- Add array type support for perf-probe, so that user can
  dump partial array entries.

V6 is here:
 https://lkml.org/lkml/2018/3/17/75

Changes from the v6 are here:
 [6/16]  - Fix to return an error if failed to fetch string and
        fill zero-length data_loc in error case.
 [11/16] - Update document for restructured text.
 [15/16] - Fix README test.
 [16/16] - Add type-casting description (and note) to documentation.

And rebased on the latest Steve's ftrace/core branch.

Thank you,

---

Masami Hiramatsu (16):
      tracing: probeevent: Cleanup print argument functions
      tracing: probeevent: Cleanup argument field definition
      tracing: probeevent: Remove NOKPROBE_SYMBOL from print functions
      tracing: probeevent: Introduce new argument fetching code
      tracing: probeevent: Unify fetch type tables
      tracing: probeevent: Return consumed bytes of dynamic area
      tracing: probeevent: Append traceprobe_ for exported function
      tracing: probeevent: Unify fetch_insn processing common part
      tracing: probeevent: Add symbol type
      x86: ptrace: Add function argument access API
      tracing: probeevent: Add $argN for accessing function args
      tracing: probeevent: Add array type support
      selftests: ftrace: Add a testcase for symbol type
      selftests: ftrace: Add a testcase for $argN with kprobe_event
      selftests: ftrace: Add a testcase for array type with kprobe_event
      perf-probe: Add array argument support


 Documentation/trace/kprobetrace.rst                |   23 +
 arch/Kconfig                                       |    7 
 arch/x86/Kconfig                                   |    1 
 arch/x86/include/asm/ptrace.h                      |   38 +
 kernel/trace/trace.c                               |    9 
 kernel/trace/trace_kprobe.c                        |  358 ++++--------
 kernel/trace/trace_probe.c                         |  620 +++++++++-----------
 kernel/trace/trace_probe.h                         |  282 +++------
 kernel/trace/trace_probe_tmpl.h                    |  216 +++++++
 kernel/trace/trace_uprobe.c                        |  176 ++----
 tools/perf/Documentation/perf-probe.txt            |   12 
 tools/perf/util/probe-event.c                      |   20 +
 tools/perf/util/probe-event.h                      |    2 
 tools/perf/util/probe-file.c                       |    5 
 tools/perf/util/probe-file.h                       |    1 
 tools/perf/util/probe-finder.c                     |   95 ++-
 .../ftrace/test.d/kprobe/kprobe_args_argN.tc       |   25 +
 .../ftrace/test.d/kprobe/kprobe_args_array.tc      |   92 +++
 .../ftrace/test.d/kprobe/kprobe_args_symbol.tc     |   77 ++
 19 files changed, 1127 insertions(+), 932 deletions(-)
 create mode 100644 kernel/trace/trace_probe_tmpl.h
 create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc
 create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc
 create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc

--
Masami Hiramatsu (Linaro) <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
@ 2018-04-25 12:16 ` Masami Hiramatsu
  2018-04-25 12:16 ` [PATCH v7 01/16] tracing: probeevent: Cleanup print argument functions mhiramat
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-04-25 12:16 UTC (permalink / raw)


Hi,

This is the 7th version of the fetch-arg improvement series.
This includes variable changes on fetcharg framework like,

- Add fetcharg testcases (syntax, argN, symbol, string and array)
  and probepoint testcase.
- Rewrite fetcharg framework with fetch_insn, switch-case based
  instead of function pointer.
- Add "symbol" type support, which shows symbol+offset instead of
  address value.
- Add "$argN" fetcharg, which fetches function parameters.
  (currently only for x86-64)
- Add array type support (including string arrary :) ) ,
  which enables to get fixed length array from probe-events.
- Add array type support for perf-probe, so that user can
  dump partial array entries.

V6 is here:
 https://lkml.org/lkml/2018/3/17/75

Changes from the v6 are here:
 [6/16]  - Fix to return an error if failed to fetch string and
        fill zero-length data_loc in error case.
 [11/16] - Update document for restructured text.
 [15/16] - Fix README test.
 [16/16] - Add type-casting description (and note) to documentation.

And rebased on the latest Steve's ftrace/core branch.

Thank you,

---

Masami Hiramatsu (16):
      tracing: probeevent: Cleanup print argument functions
      tracing: probeevent: Cleanup argument field definition
      tracing: probeevent: Remove NOKPROBE_SYMBOL from print functions
      tracing: probeevent: Introduce new argument fetching code
      tracing: probeevent: Unify fetch type tables
      tracing: probeevent: Return consumed bytes of dynamic area
      tracing: probeevent: Append traceprobe_ for exported function
      tracing: probeevent: Unify fetch_insn processing common part
      tracing: probeevent: Add symbol type
      x86: ptrace: Add function argument access API
      tracing: probeevent: Add $argN for accessing function args
      tracing: probeevent: Add array type support
      selftests: ftrace: Add a testcase for symbol type
      selftests: ftrace: Add a testcase for $argN with kprobe_event
      selftests: ftrace: Add a testcase for array type with kprobe_event
      perf-probe: Add array argument support


 Documentation/trace/kprobetrace.rst                |   23 +
 arch/Kconfig                                       |    7 
 arch/x86/Kconfig                                   |    1 
 arch/x86/include/asm/ptrace.h                      |   38 +
 kernel/trace/trace.c                               |    9 
 kernel/trace/trace_kprobe.c                        |  358 ++++--------
 kernel/trace/trace_probe.c                         |  620 +++++++++-----------
 kernel/trace/trace_probe.h                         |  282 +++------
 kernel/trace/trace_probe_tmpl.h                    |  216 +++++++
 kernel/trace/trace_uprobe.c                        |  176 ++----
 tools/perf/Documentation/perf-probe.txt            |   12 
 tools/perf/util/probe-event.c                      |   20 +
 tools/perf/util/probe-event.h                      |    2 
 tools/perf/util/probe-file.c                       |    5 
 tools/perf/util/probe-file.h                       |    1 
 tools/perf/util/probe-finder.c                     |   95 ++-
 .../ftrace/test.d/kprobe/kprobe_args_argN.tc       |   25 +
 .../ftrace/test.d/kprobe/kprobe_args_array.tc      |   92 +++
 .../ftrace/test.d/kprobe/kprobe_args_symbol.tc     |   77 ++
 19 files changed, 1127 insertions(+), 932 deletions(-)
 create mode 100644 kernel/trace/trace_probe_tmpl.h
 create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc
 create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc
 create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc

--
Masami Hiramatsu (Linaro) <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 01/16] tracing: probeevent: Cleanup print argument functions
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
  2018-04-25 12:16 ` Masami Hiramatsu
@ 2018-04-25 12:16 ` mhiramat
  2018-04-25 12:16   ` Masami Hiramatsu
  2018-04-25 12:17 ` [PATCH v7 02/16] tracing: probeevent: Cleanup argument field definition mhiramat
                   ` (17 subsequent siblings)
  19 siblings, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-04-25 12:16 UTC (permalink / raw)


Cleanup the print-argument function to decouple it into
print-name and print-value, so that it can support more
flexible expression, like array type.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 kernel/trace/trace_kprobe.c |   20 ++++++--------------
 kernel/trace/trace_probe.c  |   12 +++++-------
 kernel/trace/trace_probe.h  |   19 ++++++++++++++++---
 kernel/trace/trace_uprobe.c |    9 ++-------
 4 files changed, 29 insertions(+), 31 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 1cd3fb4d70f8..81e2eb5a1566 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -1090,8 +1090,6 @@ print_kprobe_event(struct trace_iterator *iter, int flags,
 	struct kprobe_trace_entry_head *field;
 	struct trace_seq *s = &iter->seq;
 	struct trace_probe *tp;
-	u8 *data;
-	int i;
 
 	field = (struct kprobe_trace_entry_head *)iter->ent;
 	tp = container_of(event, struct trace_probe, call.event);
@@ -1103,11 +1101,9 @@ print_kprobe_event(struct trace_iterator *iter, int flags,
 
 	trace_seq_putc(s, ')');
 
-	data = (u8 *)&field[1];
-	for (i = 0; i < tp->nr_args; i++)
-		if (!tp->args[i].type->print(s, tp->args[i].name,
-					     data + tp->args[i].offset, field))
-			goto out;
+	if (print_probe_args(s, tp->args, tp->nr_args,
+			     (u8 *)&field[1], field) < 0)
+		goto out;
 
 	trace_seq_putc(s, '\n');
  out:
@@ -1121,8 +1117,6 @@ print_kretprobe_event(struct trace_iterator *iter, int flags,
 	struct kretprobe_trace_entry_head *field;
 	struct trace_seq *s = &iter->seq;
 	struct trace_probe *tp;
-	u8 *data;
-	int i;
 
 	field = (struct kretprobe_trace_entry_head *)iter->ent;
 	tp = container_of(event, struct trace_probe, call.event);
@@ -1139,11 +1133,9 @@ print_kretprobe_event(struct trace_iterator *iter, int flags,
 
 	trace_seq_putc(s, ')');
 
-	data = (u8 *)&field[1];
-	for (i = 0; i < tp->nr_args; i++)
-		if (!tp->args[i].type->print(s, tp->args[i].name,
-					     data + tp->args[i].offset, field))
-			goto out;
+	if (print_probe_args(s, tp->args, tp->nr_args,
+			     (u8 *)&field[1], field) < 0)
+		goto out;
 
 	trace_seq_putc(s, '\n');
 
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index daf54bda4dc8..8894b81e29b0 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -38,10 +38,9 @@ const char *reserved_field_names[] = {
 
 /* Printing  in basic type function template */
 #define DEFINE_BASIC_PRINT_TYPE_FUNC(tname, type, fmt)			\
-int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, const char *name,	\
-				void *data, void *ent)			\
+int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, void *data, void *ent)\
 {									\
-	trace_seq_printf(s, " %s=" fmt, name, *(type *)data);		\
+	trace_seq_printf(s, fmt, *(type *)data);			\
 	return !trace_seq_has_overflowed(s);				\
 }									\
 const char PRINT_TYPE_FMT_NAME(tname)[] = fmt;				\
@@ -61,15 +60,14 @@ DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x")
 DEFINE_BASIC_PRINT_TYPE_FUNC(x64, u64, "0x%Lx")
 
 /* Print type function for string type */
-int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, const char *name,
-				 void *data, void *ent)
+int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent)
 {
 	int len = *(u32 *)data >> 16;
 
 	if (!len)
-		trace_seq_printf(s, " %s=(fault)", name);
+		trace_seq_puts(s, "(fault)");
 	else
-		trace_seq_printf(s, " %s=\"%s\"", name,
+		trace_seq_printf(s, "\"%s\"",
 				 (const char *)get_loc_data(data, ent));
 	return !trace_seq_has_overflowed(s);
 }
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 75daff22ccea..0c8e66f9c855 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -94,7 +94,7 @@ static nokprobe_inline void *get_loc_data(u32 *dl, void *ent)
 /* Data fetch function type */
 typedef	void (*fetch_func_t)(struct pt_regs *, void *, void *);
 /* Printing function type */
-typedef int (*print_type_func_t)(struct trace_seq *, const char *, void *, void *);
+typedef int (*print_type_func_t)(struct trace_seq *, void *, void *);
 
 /* Fetch types */
 enum {
@@ -136,8 +136,7 @@ typedef u32 string_size;
 
 /* Printing  in basic type function template */
 #define DECLARE_BASIC_PRINT_TYPE_FUNC(type)				\
-int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, const char *name,	\
-				void *data, void *ent);			\
+int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, void *data, void *ent);\
 extern const char PRINT_TYPE_FMT_NAME(type)[]
 
 DECLARE_BASIC_PRINT_TYPE_FUNC(u8);
@@ -415,6 +414,20 @@ store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs,
 	}
 }
 
+static inline int
+print_probe_args(struct trace_seq *s, struct probe_arg *args, int nr_args,
+		 u8 *data, void *field)
+{
+	int i;
+
+	for (i = 0; i < nr_args; i++) {
+		trace_seq_printf(s, " %s=", args[i].name);
+		if (!args[i].type->print(s, data + args[i].offset, field))
+			return -ENOMEM;
+	}
+	return 0;
+}
+
 extern int set_print_fmt(struct trace_probe *tp, bool is_return);
 
 #ifdef CONFIG_PERF_EVENTS
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 34fd0e0ec51d..d5e7d84e375a 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -851,7 +851,6 @@ print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *e
 	struct trace_seq *s = &iter->seq;
 	struct trace_uprobe *tu;
 	u8 *data;
-	int i;
 
 	entry = (struct uprobe_trace_entry_head *)iter->ent;
 	tu = container_of(event, struct trace_uprobe, tp.call.event);
@@ -868,12 +867,8 @@ print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *e
 		data = DATAOF_TRACE_ENTRY(entry, false);
 	}
 
-	for (i = 0; i < tu->tp.nr_args; i++) {
-		struct probe_arg *parg = &tu->tp.args[i];
-
-		if (!parg->type->print(s, parg->name, data + parg->offset, entry))
-			goto out;
-	}
+	if (print_probe_args(s, tu->tp.args, tu->tp.nr_args, data, entry) < 0)
+		goto out;
 
 	trace_seq_putc(s, '\n');
 

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 01/16] tracing: probeevent: Cleanup print argument functions
  2018-04-25 12:16 ` [PATCH v7 01/16] tracing: probeevent: Cleanup print argument functions mhiramat
@ 2018-04-25 12:16   ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-04-25 12:16 UTC (permalink / raw)


Cleanup the print-argument function to decouple it into
print-name and print-value, so that it can support more
flexible expression, like array type.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 kernel/trace/trace_kprobe.c |   20 ++++++--------------
 kernel/trace/trace_probe.c  |   12 +++++-------
 kernel/trace/trace_probe.h  |   19 ++++++++++++++++---
 kernel/trace/trace_uprobe.c |    9 ++-------
 4 files changed, 29 insertions(+), 31 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 1cd3fb4d70f8..81e2eb5a1566 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -1090,8 +1090,6 @@ print_kprobe_event(struct trace_iterator *iter, int flags,
 	struct kprobe_trace_entry_head *field;
 	struct trace_seq *s = &iter->seq;
 	struct trace_probe *tp;
-	u8 *data;
-	int i;
 
 	field = (struct kprobe_trace_entry_head *)iter->ent;
 	tp = container_of(event, struct trace_probe, call.event);
@@ -1103,11 +1101,9 @@ print_kprobe_event(struct trace_iterator *iter, int flags,
 
 	trace_seq_putc(s, ')');
 
-	data = (u8 *)&field[1];
-	for (i = 0; i < tp->nr_args; i++)
-		if (!tp->args[i].type->print(s, tp->args[i].name,
-					     data + tp->args[i].offset, field))
-			goto out;
+	if (print_probe_args(s, tp->args, tp->nr_args,
+			     (u8 *)&field[1], field) < 0)
+		goto out;
 
 	trace_seq_putc(s, '\n');
  out:
@@ -1121,8 +1117,6 @@ print_kretprobe_event(struct trace_iterator *iter, int flags,
 	struct kretprobe_trace_entry_head *field;
 	struct trace_seq *s = &iter->seq;
 	struct trace_probe *tp;
-	u8 *data;
-	int i;
 
 	field = (struct kretprobe_trace_entry_head *)iter->ent;
 	tp = container_of(event, struct trace_probe, call.event);
@@ -1139,11 +1133,9 @@ print_kretprobe_event(struct trace_iterator *iter, int flags,
 
 	trace_seq_putc(s, ')');
 
-	data = (u8 *)&field[1];
-	for (i = 0; i < tp->nr_args; i++)
-		if (!tp->args[i].type->print(s, tp->args[i].name,
-					     data + tp->args[i].offset, field))
-			goto out;
+	if (print_probe_args(s, tp->args, tp->nr_args,
+			     (u8 *)&field[1], field) < 0)
+		goto out;
 
 	trace_seq_putc(s, '\n');
 
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index daf54bda4dc8..8894b81e29b0 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -38,10 +38,9 @@ const char *reserved_field_names[] = {
 
 /* Printing  in basic type function template */
 #define DEFINE_BASIC_PRINT_TYPE_FUNC(tname, type, fmt)			\
-int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, const char *name,	\
-				void *data, void *ent)			\
+int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, void *data, void *ent)\
 {									\
-	trace_seq_printf(s, " %s=" fmt, name, *(type *)data);		\
+	trace_seq_printf(s, fmt, *(type *)data);			\
 	return !trace_seq_has_overflowed(s);				\
 }									\
 const char PRINT_TYPE_FMT_NAME(tname)[] = fmt;				\
@@ -61,15 +60,14 @@ DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x")
 DEFINE_BASIC_PRINT_TYPE_FUNC(x64, u64, "0x%Lx")
 
 /* Print type function for string type */
-int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, const char *name,
-				 void *data, void *ent)
+int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent)
 {
 	int len = *(u32 *)data >> 16;
 
 	if (!len)
-		trace_seq_printf(s, " %s=(fault)", name);
+		trace_seq_puts(s, "(fault)");
 	else
-		trace_seq_printf(s, " %s=\"%s\"", name,
+		trace_seq_printf(s, "\"%s\"",
 				 (const char *)get_loc_data(data, ent));
 	return !trace_seq_has_overflowed(s);
 }
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 75daff22ccea..0c8e66f9c855 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -94,7 +94,7 @@ static nokprobe_inline void *get_loc_data(u32 *dl, void *ent)
 /* Data fetch function type */
 typedef	void (*fetch_func_t)(struct pt_regs *, void *, void *);
 /* Printing function type */
-typedef int (*print_type_func_t)(struct trace_seq *, const char *, void *, void *);
+typedef int (*print_type_func_t)(struct trace_seq *, void *, void *);
 
 /* Fetch types */
 enum {
@@ -136,8 +136,7 @@ typedef u32 string_size;
 
 /* Printing  in basic type function template */
 #define DECLARE_BASIC_PRINT_TYPE_FUNC(type)				\
-int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, const char *name,	\
-				void *data, void *ent);			\
+int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, void *data, void *ent);\
 extern const char PRINT_TYPE_FMT_NAME(type)[]
 
 DECLARE_BASIC_PRINT_TYPE_FUNC(u8);
@@ -415,6 +414,20 @@ store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs,
 	}
 }
 
+static inline int
+print_probe_args(struct trace_seq *s, struct probe_arg *args, int nr_args,
+		 u8 *data, void *field)
+{
+	int i;
+
+	for (i = 0; i < nr_args; i++) {
+		trace_seq_printf(s, " %s=", args[i].name);
+		if (!args[i].type->print(s, data + args[i].offset, field))
+			return -ENOMEM;
+	}
+	return 0;
+}
+
 extern int set_print_fmt(struct trace_probe *tp, bool is_return);
 
 #ifdef CONFIG_PERF_EVENTS
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 34fd0e0ec51d..d5e7d84e375a 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -851,7 +851,6 @@ print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *e
 	struct trace_seq *s = &iter->seq;
 	struct trace_uprobe *tu;
 	u8 *data;
-	int i;
 
 	entry = (struct uprobe_trace_entry_head *)iter->ent;
 	tu = container_of(event, struct trace_uprobe, tp.call.event);
@@ -868,12 +867,8 @@ print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *e
 		data = DATAOF_TRACE_ENTRY(entry, false);
 	}
 
-	for (i = 0; i < tu->tp.nr_args; i++) {
-		struct probe_arg *parg = &tu->tp.args[i];
-
-		if (!parg->type->print(s, parg->name, data + parg->offset, entry))
-			goto out;
-	}
+	if (print_probe_args(s, tu->tp.args, tu->tp.nr_args, data, entry) < 0)
+		goto out;
 
 	trace_seq_putc(s, '\n');
 

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 02/16] tracing: probeevent: Cleanup argument field definition
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
  2018-04-25 12:16 ` Masami Hiramatsu
  2018-04-25 12:16 ` [PATCH v7 01/16] tracing: probeevent: Cleanup print argument functions mhiramat
@ 2018-04-25 12:17 ` mhiramat
  2018-04-25 12:17   ` Masami Hiramatsu
  2018-04-25 12:17 ` [PATCH v7 03/16] tracing: probeevent: Remove NOKPROBE_SYMBOL from print functions mhiramat
                   ` (16 subsequent siblings)
  19 siblings, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-04-25 12:17 UTC (permalink / raw)


Cleanup event argument definition code in one place for
maintenancability.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 kernel/trace/trace_kprobe.c |   32 ++++----------------------------
 kernel/trace/trace_probe.c  |   21 +++++++++++++++++++++
 kernel/trace/trace_probe.h  |    2 ++
 kernel/trace/trace_uprobe.c |   15 ++-------------
 4 files changed, 29 insertions(+), 41 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 81e2eb5a1566..a8f8cce066a9 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -1146,49 +1146,25 @@ print_kretprobe_event(struct trace_iterator *iter, int flags,
 
 static int kprobe_event_define_fields(struct trace_event_call *event_call)
 {
-	int ret, i;
+	int ret;
 	struct kprobe_trace_entry_head field;
 	struct trace_kprobe *tk = (struct trace_kprobe *)event_call->data;
 
 	DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0);
-	/* Set argument names as fields */
-	for (i = 0; i < tk->tp.nr_args; i++) {
-		struct probe_arg *parg = &tk->tp.args[i];
 
-		ret = trace_define_field(event_call, parg->type->fmttype,
-					 parg->name,
-					 sizeof(field) + parg->offset,
-					 parg->type->size,
-					 parg->type->is_signed,
-					 FILTER_OTHER);
-		if (ret)
-			return ret;
-	}
-	return 0;
+	return traceprobe_define_arg_fields(event_call, sizeof(field), &tk->tp);
 }
 
 static int kretprobe_event_define_fields(struct trace_event_call *event_call)
 {
-	int ret, i;
+	int ret;
 	struct kretprobe_trace_entry_head field;
 	struct trace_kprobe *tk = (struct trace_kprobe *)event_call->data;
 
 	DEFINE_FIELD(unsigned long, func, FIELD_STRING_FUNC, 0);
 	DEFINE_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP, 0);
-	/* Set argument names as fields */
-	for (i = 0; i < tk->tp.nr_args; i++) {
-		struct probe_arg *parg = &tk->tp.args[i];
 
-		ret = trace_define_field(event_call, parg->type->fmttype,
-					 parg->name,
-					 sizeof(field) + parg->offset,
-					 parg->type->size,
-					 parg->type->is_signed,
-					 FILTER_OTHER);
-		if (ret)
-			return ret;
-	}
-	return 0;
+	return traceprobe_define_arg_fields(event_call, sizeof(field), &tk->tp);
 }
 
 #ifdef CONFIG_PERF_EVENTS
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 8894b81e29b0..049e8531fdf8 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -680,3 +680,24 @@ int set_print_fmt(struct trace_probe *tp, bool is_return)
 
 	return 0;
 }
+
+int traceprobe_define_arg_fields(struct trace_event_call *event_call,
+				 size_t offset, struct trace_probe *tp)
+{
+	int ret, i;
+
+	/* Set argument names as fields */
+	for (i = 0; i < tp->nr_args; i++) {
+		struct probe_arg *parg = &tp->args[i];
+
+		ret = trace_define_field(event_call, parg->type->fmttype,
+					 parg->name,
+					 offset + parg->offset,
+					 parg->type->size,
+					 parg->type->is_signed,
+					 FILTER_OTHER);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 0c8e66f9c855..de928052926b 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -440,3 +440,5 @@ extern struct trace_event_call *
 create_local_trace_uprobe(char *name, unsigned long offs, bool is_return);
 extern void destroy_local_trace_uprobe(struct trace_event_call *event_call);
 #endif
+extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
+					size_t offset, struct trace_probe *tp);
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index d5e7d84e375a..c21c3783d055 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -969,7 +969,7 @@ probe_event_disable(struct trace_uprobe *tu, struct trace_event_file *file)
 
 static int uprobe_event_define_fields(struct trace_event_call *event_call)
 {
-	int ret, i, size;
+	int ret, size;
 	struct uprobe_trace_entry_head field;
 	struct trace_uprobe *tu = event_call->data;
 
@@ -981,19 +981,8 @@ static int uprobe_event_define_fields(struct trace_event_call *event_call)
 		DEFINE_FIELD(unsigned long, vaddr[0], FIELD_STRING_IP, 0);
 		size = SIZEOF_TRACE_ENTRY(false);
 	}
-	/* Set argument names as fields */
-	for (i = 0; i < tu->tp.nr_args; i++) {
-		struct probe_arg *parg = &tu->tp.args[i];
-
-		ret = trace_define_field(event_call, parg->type->fmttype,
-					 parg->name, size + parg->offset,
-					 parg->type->size, parg->type->is_signed,
-					 FILTER_OTHER);
 
-		if (ret)
-			return ret;
-	}
-	return 0;
+	return traceprobe_define_arg_fields(event_call, size, &tu->tp);
 }
 
 #ifdef CONFIG_PERF_EVENTS

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 02/16] tracing: probeevent: Cleanup argument field definition
  2018-04-25 12:17 ` [PATCH v7 02/16] tracing: probeevent: Cleanup argument field definition mhiramat
@ 2018-04-25 12:17   ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-04-25 12:17 UTC (permalink / raw)


Cleanup event argument definition code in one place for
maintenancability.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 kernel/trace/trace_kprobe.c |   32 ++++----------------------------
 kernel/trace/trace_probe.c  |   21 +++++++++++++++++++++
 kernel/trace/trace_probe.h  |    2 ++
 kernel/trace/trace_uprobe.c |   15 ++-------------
 4 files changed, 29 insertions(+), 41 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 81e2eb5a1566..a8f8cce066a9 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -1146,49 +1146,25 @@ print_kretprobe_event(struct trace_iterator *iter, int flags,
 
 static int kprobe_event_define_fields(struct trace_event_call *event_call)
 {
-	int ret, i;
+	int ret;
 	struct kprobe_trace_entry_head field;
 	struct trace_kprobe *tk = (struct trace_kprobe *)event_call->data;
 
 	DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0);
-	/* Set argument names as fields */
-	for (i = 0; i < tk->tp.nr_args; i++) {
-		struct probe_arg *parg = &tk->tp.args[i];
 
-		ret = trace_define_field(event_call, parg->type->fmttype,
-					 parg->name,
-					 sizeof(field) + parg->offset,
-					 parg->type->size,
-					 parg->type->is_signed,
-					 FILTER_OTHER);
-		if (ret)
-			return ret;
-	}
-	return 0;
+	return traceprobe_define_arg_fields(event_call, sizeof(field), &tk->tp);
 }
 
 static int kretprobe_event_define_fields(struct trace_event_call *event_call)
 {
-	int ret, i;
+	int ret;
 	struct kretprobe_trace_entry_head field;
 	struct trace_kprobe *tk = (struct trace_kprobe *)event_call->data;
 
 	DEFINE_FIELD(unsigned long, func, FIELD_STRING_FUNC, 0);
 	DEFINE_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP, 0);
-	/* Set argument names as fields */
-	for (i = 0; i < tk->tp.nr_args; i++) {
-		struct probe_arg *parg = &tk->tp.args[i];
 
-		ret = trace_define_field(event_call, parg->type->fmttype,
-					 parg->name,
-					 sizeof(field) + parg->offset,
-					 parg->type->size,
-					 parg->type->is_signed,
-					 FILTER_OTHER);
-		if (ret)
-			return ret;
-	}
-	return 0;
+	return traceprobe_define_arg_fields(event_call, sizeof(field), &tk->tp);
 }
 
 #ifdef CONFIG_PERF_EVENTS
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 8894b81e29b0..049e8531fdf8 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -680,3 +680,24 @@ int set_print_fmt(struct trace_probe *tp, bool is_return)
 
 	return 0;
 }
+
+int traceprobe_define_arg_fields(struct trace_event_call *event_call,
+				 size_t offset, struct trace_probe *tp)
+{
+	int ret, i;
+
+	/* Set argument names as fields */
+	for (i = 0; i < tp->nr_args; i++) {
+		struct probe_arg *parg = &tp->args[i];
+
+		ret = trace_define_field(event_call, parg->type->fmttype,
+					 parg->name,
+					 offset + parg->offset,
+					 parg->type->size,
+					 parg->type->is_signed,
+					 FILTER_OTHER);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 0c8e66f9c855..de928052926b 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -440,3 +440,5 @@ extern struct trace_event_call *
 create_local_trace_uprobe(char *name, unsigned long offs, bool is_return);
 extern void destroy_local_trace_uprobe(struct trace_event_call *event_call);
 #endif
+extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
+					size_t offset, struct trace_probe *tp);
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index d5e7d84e375a..c21c3783d055 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -969,7 +969,7 @@ probe_event_disable(struct trace_uprobe *tu, struct trace_event_file *file)
 
 static int uprobe_event_define_fields(struct trace_event_call *event_call)
 {
-	int ret, i, size;
+	int ret, size;
 	struct uprobe_trace_entry_head field;
 	struct trace_uprobe *tu = event_call->data;
 
@@ -981,19 +981,8 @@ static int uprobe_event_define_fields(struct trace_event_call *event_call)
 		DEFINE_FIELD(unsigned long, vaddr[0], FIELD_STRING_IP, 0);
 		size = SIZEOF_TRACE_ENTRY(false);
 	}
-	/* Set argument names as fields */
-	for (i = 0; i < tu->tp.nr_args; i++) {
-		struct probe_arg *parg = &tu->tp.args[i];
-
-		ret = trace_define_field(event_call, parg->type->fmttype,
-					 parg->name, size + parg->offset,
-					 parg->type->size, parg->type->is_signed,
-					 FILTER_OTHER);
 
-		if (ret)
-			return ret;
-	}
-	return 0;
+	return traceprobe_define_arg_fields(event_call, size, &tu->tp);
 }
 
 #ifdef CONFIG_PERF_EVENTS

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 03/16] tracing: probeevent: Remove NOKPROBE_SYMBOL from print functions
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
                   ` (2 preceding siblings ...)
  2018-04-25 12:17 ` [PATCH v7 02/16] tracing: probeevent: Cleanup argument field definition mhiramat
@ 2018-04-25 12:17 ` mhiramat
  2018-04-25 12:17   ` Masami Hiramatsu
  2018-04-25 12:18 ` [PATCH v7 04/16] tracing: probeevent: Introduce new argument fetching code mhiramat
                   ` (15 subsequent siblings)
  19 siblings, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-04-25 12:17 UTC (permalink / raw)


Remove unneeded NOKPROBE_SYMBOL from print functions since
the print functions are only used when printing out the
trace data, and not from kprobe handler.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 kernel/trace/trace_probe.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 049e8531fdf8..51ca8f751332 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -43,8 +43,7 @@ int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, void *data, void *ent)\
 	trace_seq_printf(s, fmt, *(type *)data);			\
 	return !trace_seq_has_overflowed(s);				\
 }									\
-const char PRINT_TYPE_FMT_NAME(tname)[] = fmt;				\
-NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(tname));
+const char PRINT_TYPE_FMT_NAME(tname)[] = fmt;
 
 DEFINE_BASIC_PRINT_TYPE_FUNC(u8,  u8,  "%u")
 DEFINE_BASIC_PRINT_TYPE_FUNC(u16, u16, "%u")
@@ -71,7 +70,6 @@ int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent)
 				 (const char *)get_loc_data(data, ent));
 	return !trace_seq_has_overflowed(s);
 }
-NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(string));
 
 const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\"";
 

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 03/16] tracing: probeevent: Remove NOKPROBE_SYMBOL from print functions
  2018-04-25 12:17 ` [PATCH v7 03/16] tracing: probeevent: Remove NOKPROBE_SYMBOL from print functions mhiramat
@ 2018-04-25 12:17   ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-04-25 12:17 UTC (permalink / raw)


Remove unneeded NOKPROBE_SYMBOL from print functions since
the print functions are only used when printing out the
trace data, and not from kprobe handler.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 kernel/trace/trace_probe.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 049e8531fdf8..51ca8f751332 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -43,8 +43,7 @@ int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, void *data, void *ent)\
 	trace_seq_printf(s, fmt, *(type *)data);			\
 	return !trace_seq_has_overflowed(s);				\
 }									\
-const char PRINT_TYPE_FMT_NAME(tname)[] = fmt;				\
-NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(tname));
+const char PRINT_TYPE_FMT_NAME(tname)[] = fmt;
 
 DEFINE_BASIC_PRINT_TYPE_FUNC(u8,  u8,  "%u")
 DEFINE_BASIC_PRINT_TYPE_FUNC(u16, u16, "%u")
@@ -71,7 +70,6 @@ int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent)
 				 (const char *)get_loc_data(data, ent));
 	return !trace_seq_has_overflowed(s);
 }
-NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(string));
 
 const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\"";
 

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 04/16] tracing: probeevent: Introduce new argument fetching code
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
                   ` (3 preceding siblings ...)
  2018-04-25 12:17 ` [PATCH v7 03/16] tracing: probeevent: Remove NOKPROBE_SYMBOL from print functions mhiramat
@ 2018-04-25 12:18 ` mhiramat
  2018-04-25 12:18   ` Masami Hiramatsu
  2018-04-25 12:18 ` [PATCH v7 05/16] tracing: probeevent: Unify fetch type tables mhiramat
                   ` (14 subsequent siblings)
  19 siblings, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-04-25 12:18 UTC (permalink / raw)


Replace {k,u}probe event argument fetching framework
with switch-case based. Currently that is implemented
with structures, macros and chain of function-pointers,
which is more complicated than necessary and may get
a performance penalty by retpoline.

This simplify that with an array of "fetch_insn" (opcode
and oprands), and make process_fetch_insn() just
interprets it. No function pointers are used.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v3:
  - Split out probe type table unification.
---
 kernel/trace/trace_kprobe.c     |  291 +++++++++++++---------------
 kernel/trace/trace_probe.c      |  401 +++++++++++----------------------------
 kernel/trace/trace_probe.h      |  230 ++++------------------
 kernel/trace/trace_probe_tmpl.h |  120 ++++++++++++
 kernel/trace/trace_uprobe.c     |  127 ++++++++----
 5 files changed, 491 insertions(+), 678 deletions(-)
 create mode 100644 kernel/trace/trace_probe_tmpl.h

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index a8f8cce066a9..1d1e37058f8a 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -24,6 +24,7 @@
 #include <linux/error-injection.h>
 
 #include "trace_probe.h"
+#include "trace_probe_tmpl.h"
 
 #define KPROBE_EVENT_SYSTEM "kprobes"
 #define KRETPROBE_MAXACTIVE_MAX 4096
@@ -121,160 +122,6 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs);
 static int kretprobe_dispatcher(struct kretprobe_instance *ri,
 				struct pt_regs *regs);
 
-/* Memory fetching by symbol */
-struct symbol_cache {
-	char		*symbol;
-	long		offset;
-	unsigned long	addr;
-};
-
-unsigned long update_symbol_cache(struct symbol_cache *sc)
-{
-	sc->addr = (unsigned long)kallsyms_lookup_name(sc->symbol);
-
-	if (sc->addr)
-		sc->addr += sc->offset;
-
-	return sc->addr;
-}
-
-void free_symbol_cache(struct symbol_cache *sc)
-{
-	kfree(sc->symbol);
-	kfree(sc);
-}
-
-struct symbol_cache *alloc_symbol_cache(const char *sym, long offset)
-{
-	struct symbol_cache *sc;
-
-	if (!sym || strlen(sym) == 0)
-		return NULL;
-
-	sc = kzalloc(sizeof(struct symbol_cache), GFP_KERNEL);
-	if (!sc)
-		return NULL;
-
-	sc->symbol = kstrdup(sym, GFP_KERNEL);
-	if (!sc->symbol) {
-		kfree(sc);
-		return NULL;
-	}
-	sc->offset = offset;
-	update_symbol_cache(sc);
-
-	return sc;
-}
-
-/*
- * Kprobes-specific fetch functions
- */
-#define DEFINE_FETCH_stack(type)					\
-static void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,		\
-					  void *offset, void *dest)	\
-{									\
-	*(type *)dest = (type)regs_get_kernel_stack_nth(regs,		\
-				(unsigned int)((unsigned long)offset));	\
-}									\
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(stack, type));
-
-DEFINE_BASIC_FETCH_FUNCS(stack)
-/* No string on the stack entry */
-#define fetch_stack_string	NULL
-#define fetch_stack_string_size	NULL
-
-#define DEFINE_FETCH_memory(type)					\
-static void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,		\
-					  void *addr, void *dest)	\
-{									\
-	type retval;							\
-	if (probe_kernel_address(addr, retval))				\
-		*(type *)dest = 0;					\
-	else								\
-		*(type *)dest = retval;					\
-}									\
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, type));
-
-DEFINE_BASIC_FETCH_FUNCS(memory)
-/*
- * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
- * length and relative data location.
- */
-static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
-					    void *addr, void *dest)
-{
-	int maxlen = get_rloc_len(*(u32 *)dest);
-	u8 *dst = get_rloc_data(dest);
-	long ret;
-
-	if (!maxlen)
-		return;
-
-	/*
-	 * Try to get string again, since the string can be changed while
-	 * probing.
-	 */
-	ret = strncpy_from_unsafe(dst, addr, maxlen);
-
-	if (ret < 0) {	/* Failed to fetch string */
-		dst[0] = '\0';
-		*(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
-	} else {
-		*(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest));
-	}
-}
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, string));
-
-/* Return the length of string -- including null terminal byte */
-static void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
-						 void *addr, void *dest)
-{
-	mm_segment_t old_fs;
-	int ret, len = 0;
-	u8 c;
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	pagefault_disable();
-
-	do {
-		ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1);
-		len++;
-	} while (c && ret == 0 && len < MAX_STRING_SIZE);
-
-	pagefault_enable();
-	set_fs(old_fs);
-
-	if (ret < 0)	/* Failed to check the length */
-		*(u32 *)dest = 0;
-	else
-		*(u32 *)dest = len;
-}
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, string_size));
-
-#define DEFINE_FETCH_symbol(type)					\
-void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs, void *data, void *dest)\
-{									\
-	struct symbol_cache *sc = data;					\
-	if (sc->addr)							\
-		fetch_memory_##type(regs, (void *)sc->addr, dest);	\
-	else								\
-		*(type *)dest = 0;					\
-}									\
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(symbol, type));
-
-DEFINE_BASIC_FETCH_FUNCS(symbol)
-DEFINE_FETCH_symbol(string)
-DEFINE_FETCH_symbol(string_size)
-
-/* kprobes don't support file_offset fetch methods */
-#define fetch_file_offset_u8		NULL
-#define fetch_file_offset_u16		NULL
-#define fetch_file_offset_u32		NULL
-#define fetch_file_offset_u64		NULL
-#define fetch_file_offset_string	NULL
-#define fetch_file_offset_string_size	NULL
-
 /* Fetch type information table */
 static const struct fetch_type kprobes_fetch_type_table[] = {
 	/* Special types */
@@ -490,14 +337,11 @@ disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 /* Internal register function - just handle k*probes and flags */
 static int __register_trace_kprobe(struct trace_kprobe *tk)
 {
-	int i, ret;
+	int ret;
 
 	if (trace_probe_is_registered(&tk->tp))
 		return -EINVAL;
 
-	for (i = 0; i < tk->tp.nr_args; i++)
-		traceprobe_update_arg(&tk->tp.args[i]);
-
 	/* Set/clear disabled flag according to tp->flag */
 	if (trace_probe_is_enabled(&tk->tp))
 		tk->rp.kp.flags &= ~KPROBE_FLAG_DISABLED;
@@ -830,8 +674,8 @@ static int create_trace_kprobe(int argc, char **argv)
 
 		/* Parse fetch argument */
 		ret = traceprobe_parse_probe_arg(arg, &tk->tp.size, parg,
-						is_return, true,
-						kprobes_fetch_type_table);
+						 is_return, true,
+						 kprobes_fetch_type_table);
 		if (ret) {
 			pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
 			goto error;
@@ -985,6 +829,133 @@ static const struct file_operations kprobe_profile_ops = {
 	.release        = seq_release,
 };
 
+/* Kprobe specific fetch functions */
+
+/* Return the length of string -- including null terminal byte */
+static nokprobe_inline void
+fetch_store_strlen(unsigned long addr, void *dest)
+{
+	mm_segment_t old_fs;
+	int ret, len = 0;
+	u8 c;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	pagefault_disable();
+
+	do {
+		ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1);
+		len++;
+	} while (c && ret == 0 && len < MAX_STRING_SIZE);
+
+	pagefault_enable();
+	set_fs(old_fs);
+
+	if (ret < 0)	/* Failed to check the length */
+		*(u32 *)dest = 0;
+	else
+		*(u32 *)dest = len;
+}
+
+/*
+ * Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max
+ * length and relative data location.
+ */
+static nokprobe_inline void
+fetch_store_string(unsigned long addr, void *dest)
+{
+	int maxlen = get_rloc_len(*(u32 *)dest);
+	u8 *dst = get_rloc_data(dest);
+	long ret;
+
+	if (!maxlen)
+		return;
+
+	/*
+	 * Try to get string again, since the string can be changed while
+	 * probing.
+	 */
+	ret = strncpy_from_unsafe(dst, (void *)addr, maxlen);
+
+	if (ret < 0) {	/* Failed to fetch string */
+		dst[0] = '\0';
+		*(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
+	} else {
+		*(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest));
+	}
+}
+
+/* Note that we don't verify it, since the code does not come from user space */
+static int
+process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
+		   bool pre)
+{
+	unsigned long val;
+	int ret;
+
+	/* 1st stage: get value from context */
+	switch (code->op) {
+	case FETCH_OP_REG:
+		val = regs_get_register(regs, code->param);
+		break;
+	case FETCH_OP_STACK:
+		val = regs_get_kernel_stack_nth(regs, code->param);
+		break;
+	case FETCH_OP_STACKP:
+		val = kernel_stack_pointer(regs);
+		break;
+	case FETCH_OP_RETVAL:
+		val = regs_return_value(regs);
+		break;
+	case FETCH_OP_IMM:
+		val = code->immediate;
+		break;
+	case FETCH_OP_COMM:
+		val = (unsigned long)current->comm;
+		break;
+	default:
+		return -EILSEQ;
+	}
+	code++;
+
+	/* 2nd stage: dereference memory if needed */
+	while (code->op == FETCH_OP_DEREF) {
+		ret = probe_kernel_read(&val, (void *)val + code->offset,
+					sizeof(val));
+		if (ret)
+			return ret;
+		code++;
+	}
+
+	/* 3rd stage: store value to buffer */
+	switch (code->op) {
+	case FETCH_OP_ST_RAW:
+		fetch_store_raw(val, code, dest);
+		break;
+	case FETCH_OP_ST_MEM:
+		probe_kernel_read(dest, (void *)val + code->offset, code->size);
+		break;
+	case FETCH_OP_ST_STRING:
+		if (pre)
+			fetch_store_strlen(val + code->offset, dest);
+		else
+			fetch_store_string(val + code->offset, dest);
+		break;
+	default:
+		return -EILSEQ;
+	}
+	code++;
+
+	/* 4th stage: modify stored value if needed */
+	if (code->op == FETCH_OP_MOD_BF) {
+		fetch_apply_bitfield(code, dest);
+		code++;
+	}
+
+	return code->op == FETCH_OP_END ? 0 : -EILSEQ;
+}
+NOKPROBE_SYMBOL(process_fetch_insn)
+
 /* Kprobe handler */
 static nokprobe_inline void
 __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs,
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 51ca8f751332..758968ac165d 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -73,174 +73,6 @@ int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent)
 
 const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\"";
 
-#define CHECK_FETCH_FUNCS(method, fn)			\
-	(((FETCH_FUNC_NAME(method, u8) == fn) ||	\
-	  (FETCH_FUNC_NAME(method, u16) == fn) ||	\
-	  (FETCH_FUNC_NAME(method, u32) == fn) ||	\
-	  (FETCH_FUNC_NAME(method, u64) == fn) ||	\
-	  (FETCH_FUNC_NAME(method, string) == fn) ||	\
-	  (FETCH_FUNC_NAME(method, string_size) == fn)) \
-	 && (fn != NULL))
-
-/* Data fetch function templates */
-#define DEFINE_FETCH_reg(type)						\
-void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, void *offset, void *dest)	\
-{									\
-	*(type *)dest = (type)regs_get_register(regs,			\
-				(unsigned int)((unsigned long)offset));	\
-}									\
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(reg, type));
-DEFINE_BASIC_FETCH_FUNCS(reg)
-/* No string on the register */
-#define fetch_reg_string	NULL
-#define fetch_reg_string_size	NULL
-
-#define DEFINE_FETCH_retval(type)					\
-void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs,		\
-				   void *dummy, void *dest)		\
-{									\
-	*(type *)dest = (type)regs_return_value(regs);			\
-}									\
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(retval, type));
-DEFINE_BASIC_FETCH_FUNCS(retval)
-/* No string on the retval */
-#define fetch_retval_string		NULL
-#define fetch_retval_string_size	NULL
-
-/* Dereference memory access function */
-struct deref_fetch_param {
-	struct fetch_param	orig;
-	long			offset;
-	fetch_func_t		fetch;
-	fetch_func_t		fetch_size;
-};
-
-#define DEFINE_FETCH_deref(type)					\
-void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs,			\
-				  void *data, void *dest)		\
-{									\
-	struct deref_fetch_param *dprm = data;				\
-	unsigned long addr;						\
-	call_fetch(&dprm->orig, regs, &addr);				\
-	if (addr) {							\
-		addr += dprm->offset;					\
-		dprm->fetch(regs, (void *)addr, dest);			\
-	} else								\
-		*(type *)dest = 0;					\
-}									\
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, type));
-DEFINE_BASIC_FETCH_FUNCS(deref)
-DEFINE_FETCH_deref(string)
-
-void FETCH_FUNC_NAME(deref, string_size)(struct pt_regs *regs,
-					 void *data, void *dest)
-{
-	struct deref_fetch_param *dprm = data;
-	unsigned long addr;
-
-	call_fetch(&dprm->orig, regs, &addr);
-	if (addr && dprm->fetch_size) {
-		addr += dprm->offset;
-		dprm->fetch_size(regs, (void *)addr, dest);
-	} else
-		*(string_size *)dest = 0;
-}
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, string_size));
-
-static void update_deref_fetch_param(struct deref_fetch_param *data)
-{
-	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
-		update_deref_fetch_param(data->orig.data);
-	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
-		update_symbol_cache(data->orig.data);
-}
-NOKPROBE_SYMBOL(update_deref_fetch_param);
-
-static void free_deref_fetch_param(struct deref_fetch_param *data)
-{
-	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
-		free_deref_fetch_param(data->orig.data);
-	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
-		free_symbol_cache(data->orig.data);
-	kfree(data);
-}
-NOKPROBE_SYMBOL(free_deref_fetch_param);
-
-/* Bitfield fetch function */
-struct bitfield_fetch_param {
-	struct fetch_param	orig;
-	unsigned char		hi_shift;
-	unsigned char		low_shift;
-};
-
-#define DEFINE_FETCH_bitfield(type)					\
-void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs,		\
-				     void *data, void *dest)		\
-{									\
-	struct bitfield_fetch_param *bprm = data;			\
-	type buf = 0;							\
-	call_fetch(&bprm->orig, regs, &buf);				\
-	if (buf) {							\
-		buf <<= bprm->hi_shift;					\
-		buf >>= bprm->low_shift;				\
-	}								\
-	*(type *)dest = buf;						\
-}									\
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(bitfield, type));
-DEFINE_BASIC_FETCH_FUNCS(bitfield)
-#define fetch_bitfield_string		NULL
-#define fetch_bitfield_string_size	NULL
-
-static void
-update_bitfield_fetch_param(struct bitfield_fetch_param *data)
-{
-	/*
-	 * Don't check the bitfield itself, because this must be the
-	 * last fetch function.
-	 */
-	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
-		update_deref_fetch_param(data->orig.data);
-	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
-		update_symbol_cache(data->orig.data);
-}
-
-static void
-free_bitfield_fetch_param(struct bitfield_fetch_param *data)
-{
-	/*
-	 * Don't check the bitfield itself, because this must be the
-	 * last fetch function.
-	 */
-	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
-		free_deref_fetch_param(data->orig.data);
-	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
-		free_symbol_cache(data->orig.data);
-
-	kfree(data);
-}
-
-void FETCH_FUNC_NAME(comm, string)(struct pt_regs *regs,
-					  void *data, void *dest)
-{
-	int maxlen = get_rloc_len(*(u32 *)dest);
-	u8 *dst = get_rloc_data(dest);
-	long ret;
-
-	if (!maxlen)
-		return;
-
-	ret = strlcpy(dst, current->comm, maxlen);
-	*(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest));
-}
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string));
-
-void FETCH_FUNC_NAME(comm, string_size)(struct pt_regs *regs,
-					       void *data, void *dest)
-{
-	*(u32 *)dest = strlen(current->comm) + 1;
-}
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string_size));
-
 static const struct fetch_type *find_fetch_type(const char *type,
 						const struct fetch_type *ftbl)
 {
@@ -284,37 +116,6 @@ static const struct fetch_type *find_fetch_type(const char *type,
 	return NULL;
 }
 
-/* Special function : only accept unsigned long */
-static void fetch_kernel_stack_address(struct pt_regs *regs, void *dummy, void *dest)
-{
-	*(unsigned long *)dest = kernel_stack_pointer(regs);
-}
-NOKPROBE_SYMBOL(fetch_kernel_stack_address);
-
-static void fetch_user_stack_address(struct pt_regs *regs, void *dummy, void *dest)
-{
-	*(unsigned long *)dest = user_stack_pointer(regs);
-}
-NOKPROBE_SYMBOL(fetch_user_stack_address);
-
-static fetch_func_t get_fetch_size_function(const struct fetch_type *type,
-					    fetch_func_t orig_fn,
-					    const struct fetch_type *ftbl)
-{
-	int i;
-
-	if (type != &ftbl[FETCH_TYPE_STRING])
-		return NULL;	/* Only string type needs size function */
-
-	for (i = 0; i < FETCH_MTD_END; i++)
-		if (type->fetch[i] == orig_fn)
-			return ftbl[FETCH_TYPE_STRSIZE].fetch[i];
-
-	WARN_ON(1);	/* This should not happen */
-
-	return NULL;
-}
-
 /* Split symbol and offset. */
 int traceprobe_split_symbol_offset(char *symbol, long *offset)
 {
@@ -339,7 +140,7 @@ int traceprobe_split_symbol_offset(char *symbol, long *offset)
 #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
 
 static int parse_probe_vars(char *arg, const struct fetch_type *t,
-			    struct fetch_param *f, bool is_return,
+			    struct fetch_insn *code, bool is_return,
 			    bool is_kprobe)
 {
 	int ret = 0;
@@ -347,33 +148,24 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
 
 	if (strcmp(arg, "retval") == 0) {
 		if (is_return)
-			f->fn = t->fetch[FETCH_MTD_retval];
+			code->op = FETCH_OP_RETVAL;
 		else
 			ret = -EINVAL;
 	} else if (strncmp(arg, "stack", 5) == 0) {
 		if (arg[5] == '\0') {
-			if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR))
-				return -EINVAL;
-
-			if (is_kprobe)
-				f->fn = fetch_kernel_stack_address;
-			else
-				f->fn = fetch_user_stack_address;
+			code->op = FETCH_OP_STACKP;
 		} else if (isdigit(arg[5])) {
 			ret = kstrtoul(arg + 5, 10, &param);
 			if (ret || (is_kprobe && param > PARAM_MAX_STACK))
 				ret = -EINVAL;
 			else {
-				f->fn = t->fetch[FETCH_MTD_stack];
-				f->data = (void *)param;
+				code->op = FETCH_OP_STACK;
+				code->param = (unsigned int)param;
 			}
 		} else
 			ret = -EINVAL;
 	} else if (strcmp(arg, "comm") == 0) {
-		if (strcmp(t->name, "string") != 0 &&
-		    strcmp(t->name, "string_size") != 0)
-			return -EINVAL;
-		f->fn = t->fetch[FETCH_MTD_comm];
+		code->op = FETCH_OP_COMM;
 	} else
 		ret = -EINVAL;
 
@@ -381,10 +173,13 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
 }
 
 /* Recursive argument parser */
-static int parse_probe_arg(char *arg, const struct fetch_type *t,
-		     struct fetch_param *f, bool is_return, bool is_kprobe,
-		     const struct fetch_type *ftbl)
+static int
+parse_probe_arg(char *arg, const struct fetch_type *type,
+		struct fetch_insn **pcode, struct fetch_insn *end,
+		bool is_return, bool is_kprobe,
+		const struct fetch_type *ftbl)
 {
+	struct fetch_insn *code = *pcode;
 	unsigned long param;
 	long offset;
 	char *tmp;
@@ -392,14 +187,15 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
 
 	switch (arg[0]) {
 	case '$':
-		ret = parse_probe_vars(arg + 1, t, f, is_return, is_kprobe);
+		ret = parse_probe_vars(arg + 1, type, code,
+					is_return, is_kprobe);
 		break;
 
 	case '%':	/* named register */
 		ret = regs_query_register_offset(arg + 1);
 		if (ret >= 0) {
-			f->fn = t->fetch[FETCH_MTD_reg];
-			f->data = (void *)(unsigned long)ret;
+			code->op = FETCH_OP_REG;
+			code->param = (unsigned int)ret;
 			ret = 0;
 		}
 		break;
@@ -409,9 +205,9 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
 			ret = kstrtoul(arg + 1, 0, &param);
 			if (ret)
 				break;
-
-			f->fn = t->fetch[FETCH_MTD_memory];
-			f->data = (void *)param;
+			/* load address */
+			code->op = FETCH_OP_IMM;
+			code->immediate = param;
 		} else if (arg[1] == '+') {
 			/* kprobes don't support file offsets */
 			if (is_kprobe)
@@ -421,8 +217,8 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
 			if (ret)
 				break;
 
-			f->fn = t->fetch[FETCH_MTD_file_offset];
-			f->data = (void *)offset;
+			code->op = FETCH_OP_FOFFS;
+			code->immediate = (unsigned long)offset;  // imm64?
 		} else {
 			/* uprobes don't support symbols */
 			if (!is_kprobe)
@@ -432,10 +228,19 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
 			if (ret)
 				break;
 
-			f->data = alloc_symbol_cache(arg + 1, offset);
-			if (f->data)
-				f->fn = t->fetch[FETCH_MTD_symbol];
+			code->op = FETCH_OP_IMM;
+			code->immediate =
+				(unsigned long)kallsyms_lookup_name(arg + 1);
+			if (!code->immediate)
+				return -ENOENT;
+			code->immediate += offset;
 		}
+		/* These are fetching from memory */
+		if (++code == end)
+			return -E2BIG;
+		*pcode = code;
+		code->op = FETCH_OP_DEREF;
+		code->offset = offset;
 		break;
 
 	case '+':	/* deref memory */
@@ -443,11 +248,10 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
 	case '-':
 		tmp = strchr(arg, '(');
 		if (!tmp)
-			break;
+			return -EINVAL;
 
 		*tmp = '\0';
 		ret = kstrtol(arg, 0, &offset);
-
 		if (ret)
 			break;
 
@@ -455,36 +259,29 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
 		tmp = strrchr(arg, ')');
 
 		if (tmp) {
-			struct deref_fetch_param	*dprm;
-			const struct fetch_type		*t2;
+			const struct fetch_type *t2;
 
 			t2 = find_fetch_type(NULL, ftbl);
 			*tmp = '\0';
-			dprm = kzalloc(sizeof(struct deref_fetch_param), GFP_KERNEL);
-
-			if (!dprm)
-				return -ENOMEM;
-
-			dprm->offset = offset;
-			dprm->fetch = t->fetch[FETCH_MTD_memory];
-			dprm->fetch_size = get_fetch_size_function(t,
-							dprm->fetch, ftbl);
-			ret = parse_probe_arg(arg, t2, &dprm->orig, is_return,
-							is_kprobe, ftbl);
+			ret = parse_probe_arg(arg, t2, &code, end, is_return,
+					      is_kprobe, ftbl);
 			if (ret)
-				kfree(dprm);
-			else {
-				f->fn = t->fetch[FETCH_MTD_deref];
-				f->data = (void *)dprm;
-			}
+				break;
+			if (code->op == FETCH_OP_COMM)
+				return -EINVAL;
+			if (++code == end)
+				return -E2BIG;
+			*pcode = code;
+
+			code->op = FETCH_OP_DEREF;
+			code->offset = offset;
 		}
 		break;
 	}
-	if (!ret && !f->fn) {	/* Parsed, but do not find fetch method */
-		pr_info("%s type has no corresponding fetch method.\n", t->name);
+	if (!ret && code->op == FETCH_OP_NOP) {
+		/* Parsed, but do not find fetch method */
 		ret = -EINVAL;
 	}
-
 	return ret;
 }
 
@@ -493,22 +290,15 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
 /* Bitfield type needs to be parsed into a fetch function */
 static int __parse_bitfield_probe_arg(const char *bf,
 				      const struct fetch_type *t,
-				      struct fetch_param *f)
+				      struct fetch_insn **pcode)
 {
-	struct bitfield_fetch_param *bprm;
+	struct fetch_insn *code = *pcode;
 	unsigned long bw, bo;
 	char *tail;
 
 	if (*bf != 'b')
 		return 0;
 
-	bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
-	if (!bprm)
-		return -ENOMEM;
-
-	bprm->orig = *f;
-	f->fn = t->fetch[FETCH_MTD_bitfield];
-	f->data = (void *)bprm;
 	bw = simple_strtoul(bf + 1, &tail, 0);	/* Use simple one */
 
 	if (bw == 0 || *tail != '@')
@@ -519,9 +309,15 @@ static int __parse_bitfield_probe_arg(const char *bf,
 
 	if (tail == bf || *tail != '/')
 		return -EINVAL;
+	code++;
+	if (code->op != FETCH_OP_NOP)
+		return -E2BIG;
+	*pcode = code;
 
-	bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo);
-	bprm->low_shift = bprm->hi_shift + bo;
+	code->op = FETCH_OP_MOD_BF;
+	code->lshift = BYTES_TO_BITS(t->size) - (bw + bo);
+	code->rshift = BYTES_TO_BITS(t->size) - bw;
+	code->basesize = t->size;
 
 	return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0;
 }
@@ -531,6 +327,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 		struct probe_arg *parg, bool is_return, bool is_kprobe,
 		const struct fetch_type *ftbl)
 {
+	struct fetch_insn *code, *tmp = NULL;
 	const char *t;
 	int ret;
 
@@ -561,18 +358,60 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 	}
 	parg->offset = *size;
 	*size += parg->type->size;
-	ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return,
-			      is_kprobe, ftbl);
-
-	if (ret >= 0 && t != NULL)
-		ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch);
 
-	if (ret >= 0) {
-		parg->fetch_size.fn = get_fetch_size_function(parg->type,
-							      parg->fetch.fn,
-							      ftbl);
-		parg->fetch_size.data = parg->fetch.data;
+	code = tmp = kzalloc(sizeof(*code) * FETCH_INSN_MAX, GFP_KERNEL);
+	if (!code)
+		return -ENOMEM;
+	code[FETCH_INSN_MAX - 1].op = FETCH_OP_END;
+
+	ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1],
+			      is_return, is_kprobe, ftbl);
+	if (ret)
+		goto fail;
+
+	/* Store operation */
+	if (!strcmp(parg->type->name, "string")) {
+		if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_IMM &&
+		    code->op != FETCH_OP_COMM) {
+			pr_info("string only accepts memory or address.\n");
+			ret = -EINVAL;
+			goto fail;
+		}
+		/* Since IMM or COMM must be the 1st insn, this is safe */
+		if (code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM)
+			code++;
+		code->op = FETCH_OP_ST_STRING;	/* In DEREF case, replace it */
+		parg->dynamic = true;
+	} else if (code->op == FETCH_OP_DEREF) {
+		code->op = FETCH_OP_ST_MEM;
+		code->size = parg->type->size;
+	} else {
+		code++;
+		if (code->op != FETCH_OP_NOP) {
+			ret = -E2BIG;
+			goto fail;
+		}
+		code->op = FETCH_OP_ST_RAW;
+		code->size = parg->type->size;
+	}
+	/* Modify operation */
+	if (t != NULL) {
+		ret = __parse_bitfield_probe_arg(t, parg->type, &code);
+		if (ret)
+			goto fail;
 	}
+	code++;
+	code->op = FETCH_OP_END;
+
+	/* Shrink down the code buffer */
+	parg->code = kzalloc(sizeof(*code) * (code - tmp + 1), GFP_KERNEL);
+	if (!parg->code)
+		ret = -ENOMEM;
+	else
+		memcpy(parg->code, tmp, sizeof(*code) * (code - tmp + 1));
+
+fail:
+	kfree(tmp);
 
 	return ret;
 }
@@ -594,25 +433,9 @@ int traceprobe_conflict_field_name(const char *name,
 	return 0;
 }
 
-void traceprobe_update_arg(struct probe_arg *arg)
-{
-	if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))
-		update_bitfield_fetch_param(arg->fetch.data);
-	else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
-		update_deref_fetch_param(arg->fetch.data);
-	else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))
-		update_symbol_cache(arg->fetch.data);
-}
-
 void traceprobe_free_probe_arg(struct probe_arg *arg)
 {
-	if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))
-		free_bitfield_fetch_param(arg->fetch.data);
-	else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
-		free_deref_fetch_param(arg->fetch.data);
-	else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))
-		free_symbol_cache(arg->fetch.data);
-
+	kfree(arg->code);
 	kfree(arg->name);
 	kfree(arg->comm);
 }
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index de928052926b..9d9de7535d06 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -91,25 +91,50 @@ static nokprobe_inline void *get_loc_data(u32 *dl, void *ent)
 	return (u8 *)ent + get_rloc_offs(*dl);
 }
 
-/* Data fetch function type */
-typedef	void (*fetch_func_t)(struct pt_regs *, void *, void *);
 /* Printing function type */
 typedef int (*print_type_func_t)(struct trace_seq *, void *, void *);
 
-/* Fetch types */
-enum {
-	FETCH_MTD_reg = 0,
-	FETCH_MTD_stack,
-	FETCH_MTD_retval,
-	FETCH_MTD_comm,
-	FETCH_MTD_memory,
-	FETCH_MTD_symbol,
-	FETCH_MTD_deref,
-	FETCH_MTD_bitfield,
-	FETCH_MTD_file_offset,
-	FETCH_MTD_END,
+enum fetch_op {
+	FETCH_OP_NOP = 0,
+	// Stage 1 (load) ops
+	FETCH_OP_REG,		/* Register : .param = offset */
+	FETCH_OP_STACK,		/* Stack : .param = index */
+	FETCH_OP_STACKP,	/* Stack pointer */
+	FETCH_OP_RETVAL,	/* Return value */
+	FETCH_OP_IMM,		/* Immediate : .immediate */
+	FETCH_OP_COMM,		/* Current comm */
+	FETCH_OP_FOFFS,		/* File offset: .immediate */
+	// Stage 2 (dereference) op
+	FETCH_OP_DEREF,		/* Dereference: .offset */
+	// Stage 3 (store) ops
+	FETCH_OP_ST_RAW,	/* Raw: .size */
+	FETCH_OP_ST_MEM,	/* Mem: .offset, .size */
+	FETCH_OP_ST_STRING,	/* String: .offset, .size */
+	// Stage 4 (modify) op
+	FETCH_OP_MOD_BF,	/* Bitfield: .basesize, .lshift, .rshift */
+	FETCH_OP_END,
 };
 
+struct fetch_insn {
+	enum fetch_op op;
+	union {
+		unsigned int param;
+		struct {
+			unsigned int size;
+			int offset;
+		};
+		struct {
+			unsigned char basesize;
+			unsigned char lshift;
+			unsigned char rshift;
+		};
+		unsigned long immediate;
+	};
+};
+
+/* fetch + deref*N + store + mod + end <= 16, this allows N=12, enough */
+#define FETCH_INSN_MAX	16
+
 /* Fetch type information table */
 struct fetch_type {
 	const char		*name;		/* Name of type */
@@ -118,13 +143,6 @@ struct fetch_type {
 	print_type_func_t	print;		/* Print functions */
 	const char		*fmt;		/* Fromat string */
 	const char		*fmttype;	/* Name in format file */
-	/* Fetch functions */
-	fetch_func_t		fetch[FETCH_MTD_END];
-};
-
-struct fetch_param {
-	fetch_func_t		fn;
-	void 			*data;
 };
 
 /* For defining macros, define string/string_size types */
@@ -154,66 +172,12 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(x64);
 
 DECLARE_BASIC_PRINT_TYPE_FUNC(string);
 
-#define FETCH_FUNC_NAME(method, type)	fetch_##method##_##type
-
-/* Declare macro for basic types */
-#define DECLARE_FETCH_FUNC(method, type)				\
-extern void FETCH_FUNC_NAME(method, type)(struct pt_regs *regs, 	\
-					  void *data, void *dest)
-
-#define DECLARE_BASIC_FETCH_FUNCS(method) 	\
-DECLARE_FETCH_FUNC(method, u8);			\
-DECLARE_FETCH_FUNC(method, u16);		\
-DECLARE_FETCH_FUNC(method, u32);		\
-DECLARE_FETCH_FUNC(method, u64)
-
-DECLARE_BASIC_FETCH_FUNCS(reg);
-#define fetch_reg_string			NULL
-#define fetch_reg_string_size			NULL
-
-DECLARE_BASIC_FETCH_FUNCS(retval);
-#define fetch_retval_string			NULL
-#define fetch_retval_string_size		NULL
-
-DECLARE_BASIC_FETCH_FUNCS(symbol);
-DECLARE_FETCH_FUNC(symbol, string);
-DECLARE_FETCH_FUNC(symbol, string_size);
-
-DECLARE_BASIC_FETCH_FUNCS(deref);
-DECLARE_FETCH_FUNC(deref, string);
-DECLARE_FETCH_FUNC(deref, string_size);
-
-DECLARE_BASIC_FETCH_FUNCS(bitfield);
-#define fetch_bitfield_string			NULL
-#define fetch_bitfield_string_size		NULL
-
-/* comm only makes sense as a string */
-#define fetch_comm_u8		NULL
-#define fetch_comm_u16		NULL
-#define fetch_comm_u32		NULL
-#define fetch_comm_u64		NULL
-DECLARE_FETCH_FUNC(comm, string);
-DECLARE_FETCH_FUNC(comm, string_size);
-
-/*
- * Define macro for basic types - we don't need to define s* types, because
- * we have to care only about bitwidth at recording time.
- */
-#define DEFINE_BASIC_FETCH_FUNCS(method) \
-DEFINE_FETCH_##method(u8)		\
-DEFINE_FETCH_##method(u16)		\
-DEFINE_FETCH_##method(u32)		\
-DEFINE_FETCH_##method(u64)
-
 /* Default (unsigned long) fetch type */
 #define __DEFAULT_FETCH_TYPE(t) x##t
 #define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t)
 #define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG)
 #define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE)
 
-#define ASSIGN_FETCH_FUNC(method, type)	\
-	[FETCH_MTD_##method] = FETCH_FUNC_NAME(method, type)
-
 #define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype)	\
 	{.name = _name,				\
 	 .size = _size,					\
@@ -221,17 +185,6 @@ DEFINE_FETCH_##method(u64)
 	 .print = PRINT_TYPE_FUNC_NAME(ptype),		\
 	 .fmt = PRINT_TYPE_FMT_NAME(ptype),		\
 	 .fmttype = _fmttype,				\
-	 .fetch = {					\
-ASSIGN_FETCH_FUNC(reg, ftype),				\
-ASSIGN_FETCH_FUNC(stack, ftype),			\
-ASSIGN_FETCH_FUNC(retval, ftype),			\
-ASSIGN_FETCH_FUNC(comm, ftype),				\
-ASSIGN_FETCH_FUNC(memory, ftype),			\
-ASSIGN_FETCH_FUNC(symbol, ftype),			\
-ASSIGN_FETCH_FUNC(deref, ftype),			\
-ASSIGN_FETCH_FUNC(bitfield, ftype),			\
-ASSIGN_FETCH_FUNC(file_offset, ftype),			\
-	  }						\
 	}
 
 #define ASSIGN_FETCH_TYPE(ptype, ftype, sign)			\
@@ -243,42 +196,13 @@ ASSIGN_FETCH_FUNC(file_offset, ftype),			\
 
 #define ASSIGN_FETCH_TYPE_END {}
 
-#define FETCH_TYPE_STRING	0
-#define FETCH_TYPE_STRSIZE	1
+#define FETCH_TYPE_STRING      0
+#define FETCH_TYPE_STRSIZE     1
 
 #ifdef CONFIG_KPROBE_EVENTS
-struct symbol_cache;
-unsigned long update_symbol_cache(struct symbol_cache *sc);
-void free_symbol_cache(struct symbol_cache *sc);
-struct symbol_cache *alloc_symbol_cache(const char *sym, long offset);
 bool trace_kprobe_on_func_entry(struct trace_event_call *call);
 bool trace_kprobe_error_injectable(struct trace_event_call *call);
 #else
-/* uprobes do not support symbol fetch methods */
-#define fetch_symbol_u8			NULL
-#define fetch_symbol_u16		NULL
-#define fetch_symbol_u32		NULL
-#define fetch_symbol_u64		NULL
-#define fetch_symbol_string		NULL
-#define fetch_symbol_string_size	NULL
-
-struct symbol_cache {
-};
-static inline unsigned long __used update_symbol_cache(struct symbol_cache *sc)
-{
-	return 0;
-}
-
-static inline void __used free_symbol_cache(struct symbol_cache *sc)
-{
-}
-
-static inline struct symbol_cache * __used
-alloc_symbol_cache(const char *sym, long offset)
-{
-	return NULL;
-}
-
 static inline bool trace_kprobe_on_func_entry(struct trace_event_call *call)
 {
 	return false;
@@ -291,8 +215,8 @@ static inline bool trace_kprobe_error_injectable(struct trace_event_call *call)
 #endif /* CONFIG_KPROBE_EVENTS */
 
 struct probe_arg {
-	struct fetch_param	fetch;
-	struct fetch_param	fetch_size;
+	struct fetch_insn	*code;
+	bool			dynamic;/* Dynamic array (string) is used */
 	unsigned int		offset;	/* Offset from argument entry */
 	const char		*name;	/* Name of this argument */
 	const char		*comm;	/* Command of this argument */
@@ -324,12 +248,6 @@ static inline bool trace_probe_is_registered(struct trace_probe *tp)
 	return !!(tp->flags & TP_FLAG_REGISTERED);
 }
 
-static nokprobe_inline void call_fetch(struct fetch_param *fprm,
-				 struct pt_regs *regs, void *dest)
-{
-	return fprm->fn(regs, fprm->data, dest);
-}
-
 /* Check the name is good for event/group/fields */
 static inline bool is_good_name(const char *name)
 {
@@ -366,68 +284,6 @@ extern void traceprobe_free_probe_arg(struct probe_arg *arg);
 
 extern int traceprobe_split_symbol_offset(char *symbol, long *offset);
 
-/* Sum up total data length for dynamic arraies (strings) */
-static nokprobe_inline int
-__get_data_size(struct trace_probe *tp, struct pt_regs *regs)
-{
-	int i, ret = 0;
-	u32 len;
-
-	for (i = 0; i < tp->nr_args; i++)
-		if (unlikely(tp->args[i].fetch_size.fn)) {
-			call_fetch(&tp->args[i].fetch_size, regs, &len);
-			ret += len;
-		}
-
-	return ret;
-}
-
-/* Store the value of each argument */
-static nokprobe_inline void
-store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs,
-		 u8 *data, int maxlen)
-{
-	int i;
-	u32 end = tp->size;
-	u32 *dl;	/* Data (relative) location */
-
-	for (i = 0; i < tp->nr_args; i++) {
-		if (unlikely(tp->args[i].fetch_size.fn)) {
-			/*
-			 * First, we set the relative location and
-			 * maximum data length to *dl
-			 */
-			dl = (u32 *)(data + tp->args[i].offset);
-			*dl = make_data_rloc(maxlen, end - tp->args[i].offset);
-			/* Then try to fetch string or dynamic array data */
-			call_fetch(&tp->args[i].fetch, regs, dl);
-			/* Reduce maximum length */
-			end += get_rloc_len(*dl);
-			maxlen -= get_rloc_len(*dl);
-			/* Trick here, convert data_rloc to data_loc */
-			*dl = convert_rloc_to_loc(*dl,
-				 ent_size + tp->args[i].offset);
-		} else
-			/* Just fetching data normally */
-			call_fetch(&tp->args[i].fetch, regs,
-				   data + tp->args[i].offset);
-	}
-}
-
-static inline int
-print_probe_args(struct trace_seq *s, struct probe_arg *args, int nr_args,
-		 u8 *data, void *field)
-{
-	int i;
-
-	for (i = 0; i < nr_args; i++) {
-		trace_seq_printf(s, " %s=", args[i].name);
-		if (!args[i].type->print(s, data + args[i].offset, field))
-			return -ENOMEM;
-	}
-	return 0;
-}
-
 extern int set_print_fmt(struct trace_probe *tp, bool is_return);
 
 #ifdef CONFIG_PERF_EVENTS
diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmpl.h
new file mode 100644
index 000000000000..c8a5272abf01
--- /dev/null
+++ b/kernel/trace/trace_probe_tmpl.h
@@ -0,0 +1,120 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Traceprobe fetch helper inlines
+ */
+
+static nokprobe_inline void
+fetch_store_raw(unsigned long val, struct fetch_insn *code, void *buf)
+{
+	switch (code->size) {
+	case 1:
+		*(u8 *)buf = (u8)val;
+		break;
+	case 2:
+		*(u16 *)buf = (u16)val;
+		break;
+	case 4:
+		*(u32 *)buf = (u32)val;
+		break;
+	case 8:
+		//TBD: 32bit signed
+		*(u64 *)buf = (u64)val;
+		break;
+	default:
+		*(unsigned long *)buf = val;
+	}
+}
+
+static nokprobe_inline void
+fetch_apply_bitfield(struct fetch_insn *code, void *buf)
+{
+	switch (code->basesize) {
+	case 1:
+		*(u8 *)buf <<= code->lshift;
+		*(u8 *)buf >>= code->rshift;
+		break;
+	case 2:
+		*(u16 *)buf <<= code->lshift;
+		*(u16 *)buf >>= code->rshift;
+		break;
+	case 4:
+		*(u32 *)buf <<= code->lshift;
+		*(u32 *)buf >>= code->rshift;
+		break;
+	case 8:
+		*(u64 *)buf <<= code->lshift;
+		*(u64 *)buf >>= code->rshift;
+		break;
+	}
+}
+
+/* Define this for each callsite */
+static int
+process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs,
+		   void *dest, bool pre);
+
+/* Sum up total data length for dynamic arraies (strings) */
+static nokprobe_inline int
+__get_data_size(struct trace_probe *tp, struct pt_regs *regs)
+{
+	struct probe_arg *arg;
+	int i, ret = 0;
+	u32 len;
+
+	for (i = 0; i < tp->nr_args; i++) {
+		arg = tp->args + i;
+		if (unlikely(arg->dynamic)) {
+			process_fetch_insn(arg->code, regs, &len, true);
+			ret += len;
+		}
+	}
+
+	return ret;
+}
+
+/* Store the value of each argument */
+static nokprobe_inline void
+store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs,
+		 u8 *data, int maxlen)
+{
+	struct probe_arg *arg;
+	u32 end = tp->size;
+	u32 *dl;	/* Data (relative) location */
+	int i;
+
+	for (i = 0; i < tp->nr_args; i++) {
+		arg = tp->args + i;
+		if (unlikely(arg->dynamic)) {
+			/*
+			 * First, we set the relative location and
+			 * maximum data length to *dl
+			 */
+			dl = (u32 *)(data + arg->offset);
+			*dl = make_data_rloc(maxlen, end - arg->offset);
+			/* Then try to fetch string or dynamic array data */
+			process_fetch_insn(arg->code, regs, dl, false);
+			/* Reduce maximum length */
+			end += get_rloc_len(*dl);
+			maxlen -= get_rloc_len(*dl);
+			/* Trick here, convert data_rloc to data_loc */
+			*dl = convert_rloc_to_loc(*dl, ent_size + arg->offset);
+		} else
+			/* Just fetching data normally */
+			process_fetch_insn(arg->code, regs, data + arg->offset,
+					   false);
+	}
+}
+
+static inline int
+print_probe_args(struct trace_seq *s, struct probe_arg *args, int nr_args,
+		 u8 *data, void *field)
+{
+	int i;
+
+	for (i = 0; i < nr_args; i++) {
+		trace_seq_printf(s, " %s=", args[i].name);
+		if (!args[i].type->print(s, data + args[i].offset, field))
+			return -ENOMEM;
+	}
+	return 0;
+}
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index c21c3783d055..ff408edd3a68 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -27,6 +27,7 @@
 #include <linux/rculist.h>
 
 #include "trace_probe.h"
+#include "trace_probe_tmpl.h"
 
 #define UPROBE_EVENT_SYSTEM	"uprobes"
 
@@ -109,37 +110,19 @@ static unsigned long get_user_stack_nth(struct pt_regs *regs, unsigned int n)
 /*
  * Uprobes-specific fetch functions
  */
-#define DEFINE_FETCH_stack(type)					\
-static void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,		\
-					 void *offset, void *dest)	\
-{									\
-	*(type *)dest = (type)get_user_stack_nth(regs,			\
-					      ((unsigned long)offset)); \
-}
-DEFINE_BASIC_FETCH_FUNCS(stack)
-/* No string on the stack entry */
-#define fetch_stack_string	NULL
-#define fetch_stack_string_size	NULL
-
-#define DEFINE_FETCH_memory(type)					\
-static void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,		\
-					  void *addr, void *dest)	\
-{									\
-	type retval;							\
-	void __user *vaddr = (void __force __user *) addr;		\
-									\
-	if (copy_from_user(&retval, vaddr, sizeof(type)))		\
-		*(type *)dest = 0;					\
-	else								\
-		*(type *) dest = retval;				\
+static nokprobe_inline int
+probe_user_read(void *dest, void *src, size_t size)
+{
+	void __user *vaddr = (void __force __user *)src;
+
+	return copy_from_user(dest, vaddr, size);
 }
-DEFINE_BASIC_FETCH_FUNCS(memory)
 /*
  * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
  * length and relative data location.
  */
-static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
-					    void *addr, void *dest)
+static nokprobe_inline void
+fetch_store_string(unsigned long addr, void *dest)
 {
 	long ret;
 	u32 rloc = *(u32 *)dest;
@@ -162,8 +145,9 @@ static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
 	}
 }
 
-static void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
-						 void *addr, void *dest)
+/* Return the length of string -- including null terminal byte */
+static nokprobe_inline void
+fetch_store_strlen(unsigned long addr, void *dest)
 {
 	int len;
 	void __user *vaddr = (void __force __user *) addr;
@@ -176,7 +160,7 @@ static void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
 		*(u32 *)dest = len;
 }
 
-static unsigned long translate_user_vaddr(void *file_offset)
+static unsigned long translate_user_vaddr(unsigned long file_offset)
 {
 	unsigned long base_addr;
 	struct uprobe_dispatch_data *udd;
@@ -184,21 +168,9 @@ static unsigned long translate_user_vaddr(void *file_offset)
 	udd = (void *) current->utask->vaddr;
 
 	base_addr = udd->bp_addr - udd->tu->offset;
-	return base_addr + (unsigned long)file_offset;
+	return base_addr + file_offset;
 }
 
-#define DEFINE_FETCH_file_offset(type)					\
-static void FETCH_FUNC_NAME(file_offset, type)(struct pt_regs *regs,	\
-					       void *offset, void *dest)\
-{									\
-	void *vaddr = (void *)translate_user_vaddr(offset);		\
-									\
-	FETCH_FUNC_NAME(memory, type)(regs, vaddr, dest);		\
-}
-DEFINE_BASIC_FETCH_FUNCS(file_offset)
-DEFINE_FETCH_file_offset(string)
-DEFINE_FETCH_file_offset(string_size)
-
 /* Fetch type information table */
 static const struct fetch_type uprobes_fetch_type_table[] = {
 	/* Special types */
@@ -223,6 +195,77 @@ static const struct fetch_type uprobes_fetch_type_table[] = {
 	ASSIGN_FETCH_TYPE_END
 };
 
+/* Note that we don't verify it, since the code does not come from user space */
+static int
+process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
+		   bool pre)
+{
+	unsigned long val;
+	int ret;
+
+	/* 1st stage: get value from context */
+	switch (code->op) {
+	case FETCH_OP_REG:
+		val = regs_get_register(regs, code->param);
+		break;
+	case FETCH_OP_STACK:
+		val = get_user_stack_nth(regs, code->param);
+		break;
+	case FETCH_OP_STACKP:
+		val = user_stack_pointer(regs);
+		break;
+	case FETCH_OP_RETVAL:
+		val = regs_return_value(regs);
+		break;
+	case FETCH_OP_IMM:
+		val = code->immediate;
+		break;
+	case FETCH_OP_FOFFS:
+		val = translate_user_vaddr(code->immediate);
+		break;
+	default:
+		return -EILSEQ;
+	}
+	code++;
+
+	/* 2nd stage: dereference memory if needed */
+	while (code->op == FETCH_OP_DEREF) {
+		ret = probe_user_read(&val, (void *)val + code->offset,
+				      sizeof(val));
+		if (ret)
+			return ret;
+		code++;
+	}
+
+	/* 3rd stage: store value to buffer */
+	switch (code->op) {
+	case FETCH_OP_ST_RAW:
+		fetch_store_raw(val, code, dest);
+		break;
+	case FETCH_OP_ST_MEM:
+		probe_user_read(dest, (void *)val + code->offset, code->size);
+		break;
+	case FETCH_OP_ST_STRING:
+		if (pre)
+			fetch_store_strlen(val + code->offset, dest);
+		else
+			fetch_store_string(val + code->offset, dest);
+		break;
+	default:
+		return -EILSEQ;
+	}
+	code++;
+
+	/* 4th stage: modify stored value if needed */
+	if (code->op == FETCH_OP_MOD_BF) {
+		fetch_apply_bitfield(code, dest);
+		code++;
+	}
+
+	return code->op == FETCH_OP_END ? 0 : -EILSEQ;
+}
+NOKPROBE_SYMBOL(process_fetch_insn)
+
 static inline void init_trace_uprobe_filter(struct trace_uprobe_filter *filter)
 {
 	rwlock_init(&filter->rwlock);

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 04/16] tracing: probeevent: Introduce new argument fetching code
  2018-04-25 12:18 ` [PATCH v7 04/16] tracing: probeevent: Introduce new argument fetching code mhiramat
@ 2018-04-25 12:18   ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-04-25 12:18 UTC (permalink / raw)


Replace {k,u}probe event argument fetching framework
with switch-case based. Currently that is implemented
with structures, macros and chain of function-pointers,
which is more complicated than necessary and may get
a performance penalty by retpoline.

This simplify that with an array of "fetch_insn" (opcode
and oprands), and make process_fetch_insn() just
interprets it. No function pointers are used.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v3:
  - Split out probe type table unification.
---
 kernel/trace/trace_kprobe.c     |  291 +++++++++++++---------------
 kernel/trace/trace_probe.c      |  401 +++++++++++----------------------------
 kernel/trace/trace_probe.h      |  230 ++++------------------
 kernel/trace/trace_probe_tmpl.h |  120 ++++++++++++
 kernel/trace/trace_uprobe.c     |  127 ++++++++----
 5 files changed, 491 insertions(+), 678 deletions(-)
 create mode 100644 kernel/trace/trace_probe_tmpl.h

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index a8f8cce066a9..1d1e37058f8a 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -24,6 +24,7 @@
 #include <linux/error-injection.h>
 
 #include "trace_probe.h"
+#include "trace_probe_tmpl.h"
 
 #define KPROBE_EVENT_SYSTEM "kprobes"
 #define KRETPROBE_MAXACTIVE_MAX 4096
@@ -121,160 +122,6 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs);
 static int kretprobe_dispatcher(struct kretprobe_instance *ri,
 				struct pt_regs *regs);
 
-/* Memory fetching by symbol */
-struct symbol_cache {
-	char		*symbol;
-	long		offset;
-	unsigned long	addr;
-};
-
-unsigned long update_symbol_cache(struct symbol_cache *sc)
-{
-	sc->addr = (unsigned long)kallsyms_lookup_name(sc->symbol);
-
-	if (sc->addr)
-		sc->addr += sc->offset;
-
-	return sc->addr;
-}
-
-void free_symbol_cache(struct symbol_cache *sc)
-{
-	kfree(sc->symbol);
-	kfree(sc);
-}
-
-struct symbol_cache *alloc_symbol_cache(const char *sym, long offset)
-{
-	struct symbol_cache *sc;
-
-	if (!sym || strlen(sym) == 0)
-		return NULL;
-
-	sc = kzalloc(sizeof(struct symbol_cache), GFP_KERNEL);
-	if (!sc)
-		return NULL;
-
-	sc->symbol = kstrdup(sym, GFP_KERNEL);
-	if (!sc->symbol) {
-		kfree(sc);
-		return NULL;
-	}
-	sc->offset = offset;
-	update_symbol_cache(sc);
-
-	return sc;
-}
-
-/*
- * Kprobes-specific fetch functions
- */
-#define DEFINE_FETCH_stack(type)					\
-static void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,		\
-					  void *offset, void *dest)	\
-{									\
-	*(type *)dest = (type)regs_get_kernel_stack_nth(regs,		\
-				(unsigned int)((unsigned long)offset));	\
-}									\
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(stack, type));
-
-DEFINE_BASIC_FETCH_FUNCS(stack)
-/* No string on the stack entry */
-#define fetch_stack_string	NULL
-#define fetch_stack_string_size	NULL
-
-#define DEFINE_FETCH_memory(type)					\
-static void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,		\
-					  void *addr, void *dest)	\
-{									\
-	type retval;							\
-	if (probe_kernel_address(addr, retval))				\
-		*(type *)dest = 0;					\
-	else								\
-		*(type *)dest = retval;					\
-}									\
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, type));
-
-DEFINE_BASIC_FETCH_FUNCS(memory)
-/*
- * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
- * length and relative data location.
- */
-static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
-					    void *addr, void *dest)
-{
-	int maxlen = get_rloc_len(*(u32 *)dest);
-	u8 *dst = get_rloc_data(dest);
-	long ret;
-
-	if (!maxlen)
-		return;
-
-	/*
-	 * Try to get string again, since the string can be changed while
-	 * probing.
-	 */
-	ret = strncpy_from_unsafe(dst, addr, maxlen);
-
-	if (ret < 0) {	/* Failed to fetch string */
-		dst[0] = '\0';
-		*(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
-	} else {
-		*(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest));
-	}
-}
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, string));
-
-/* Return the length of string -- including null terminal byte */
-static void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
-						 void *addr, void *dest)
-{
-	mm_segment_t old_fs;
-	int ret, len = 0;
-	u8 c;
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	pagefault_disable();
-
-	do {
-		ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1);
-		len++;
-	} while (c && ret == 0 && len < MAX_STRING_SIZE);
-
-	pagefault_enable();
-	set_fs(old_fs);
-
-	if (ret < 0)	/* Failed to check the length */
-		*(u32 *)dest = 0;
-	else
-		*(u32 *)dest = len;
-}
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, string_size));
-
-#define DEFINE_FETCH_symbol(type)					\
-void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs, void *data, void *dest)\
-{									\
-	struct symbol_cache *sc = data;					\
-	if (sc->addr)							\
-		fetch_memory_##type(regs, (void *)sc->addr, dest);	\
-	else								\
-		*(type *)dest = 0;					\
-}									\
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(symbol, type));
-
-DEFINE_BASIC_FETCH_FUNCS(symbol)
-DEFINE_FETCH_symbol(string)
-DEFINE_FETCH_symbol(string_size)
-
-/* kprobes don't support file_offset fetch methods */
-#define fetch_file_offset_u8		NULL
-#define fetch_file_offset_u16		NULL
-#define fetch_file_offset_u32		NULL
-#define fetch_file_offset_u64		NULL
-#define fetch_file_offset_string	NULL
-#define fetch_file_offset_string_size	NULL
-
 /* Fetch type information table */
 static const struct fetch_type kprobes_fetch_type_table[] = {
 	/* Special types */
@@ -490,14 +337,11 @@ disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 /* Internal register function - just handle k*probes and flags */
 static int __register_trace_kprobe(struct trace_kprobe *tk)
 {
-	int i, ret;
+	int ret;
 
 	if (trace_probe_is_registered(&tk->tp))
 		return -EINVAL;
 
-	for (i = 0; i < tk->tp.nr_args; i++)
-		traceprobe_update_arg(&tk->tp.args[i]);
-
 	/* Set/clear disabled flag according to tp->flag */
 	if (trace_probe_is_enabled(&tk->tp))
 		tk->rp.kp.flags &= ~KPROBE_FLAG_DISABLED;
@@ -830,8 +674,8 @@ static int create_trace_kprobe(int argc, char **argv)
 
 		/* Parse fetch argument */
 		ret = traceprobe_parse_probe_arg(arg, &tk->tp.size, parg,
-						is_return, true,
-						kprobes_fetch_type_table);
+						 is_return, true,
+						 kprobes_fetch_type_table);
 		if (ret) {
 			pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
 			goto error;
@@ -985,6 +829,133 @@ static const struct file_operations kprobe_profile_ops = {
 	.release        = seq_release,
 };
 
+/* Kprobe specific fetch functions */
+
+/* Return the length of string -- including null terminal byte */
+static nokprobe_inline void
+fetch_store_strlen(unsigned long addr, void *dest)
+{
+	mm_segment_t old_fs;
+	int ret, len = 0;
+	u8 c;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	pagefault_disable();
+
+	do {
+		ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1);
+		len++;
+	} while (c && ret == 0 && len < MAX_STRING_SIZE);
+
+	pagefault_enable();
+	set_fs(old_fs);
+
+	if (ret < 0)	/* Failed to check the length */
+		*(u32 *)dest = 0;
+	else
+		*(u32 *)dest = len;
+}
+
+/*
+ * Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max
+ * length and relative data location.
+ */
+static nokprobe_inline void
+fetch_store_string(unsigned long addr, void *dest)
+{
+	int maxlen = get_rloc_len(*(u32 *)dest);
+	u8 *dst = get_rloc_data(dest);
+	long ret;
+
+	if (!maxlen)
+		return;
+
+	/*
+	 * Try to get string again, since the string can be changed while
+	 * probing.
+	 */
+	ret = strncpy_from_unsafe(dst, (void *)addr, maxlen);
+
+	if (ret < 0) {	/* Failed to fetch string */
+		dst[0] = '\0';
+		*(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
+	} else {
+		*(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest));
+	}
+}
+
+/* Note that we don't verify it, since the code does not come from user space */
+static int
+process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
+		   bool pre)
+{
+	unsigned long val;
+	int ret;
+
+	/* 1st stage: get value from context */
+	switch (code->op) {
+	case FETCH_OP_REG:
+		val = regs_get_register(regs, code->param);
+		break;
+	case FETCH_OP_STACK:
+		val = regs_get_kernel_stack_nth(regs, code->param);
+		break;
+	case FETCH_OP_STACKP:
+		val = kernel_stack_pointer(regs);
+		break;
+	case FETCH_OP_RETVAL:
+		val = regs_return_value(regs);
+		break;
+	case FETCH_OP_IMM:
+		val = code->immediate;
+		break;
+	case FETCH_OP_COMM:
+		val = (unsigned long)current->comm;
+		break;
+	default:
+		return -EILSEQ;
+	}
+	code++;
+
+	/* 2nd stage: dereference memory if needed */
+	while (code->op == FETCH_OP_DEREF) {
+		ret = probe_kernel_read(&val, (void *)val + code->offset,
+					sizeof(val));
+		if (ret)
+			return ret;
+		code++;
+	}
+
+	/* 3rd stage: store value to buffer */
+	switch (code->op) {
+	case FETCH_OP_ST_RAW:
+		fetch_store_raw(val, code, dest);
+		break;
+	case FETCH_OP_ST_MEM:
+		probe_kernel_read(dest, (void *)val + code->offset, code->size);
+		break;
+	case FETCH_OP_ST_STRING:
+		if (pre)
+			fetch_store_strlen(val + code->offset, dest);
+		else
+			fetch_store_string(val + code->offset, dest);
+		break;
+	default:
+		return -EILSEQ;
+	}
+	code++;
+
+	/* 4th stage: modify stored value if needed */
+	if (code->op == FETCH_OP_MOD_BF) {
+		fetch_apply_bitfield(code, dest);
+		code++;
+	}
+
+	return code->op == FETCH_OP_END ? 0 : -EILSEQ;
+}
+NOKPROBE_SYMBOL(process_fetch_insn)
+
 /* Kprobe handler */
 static nokprobe_inline void
 __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs,
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 51ca8f751332..758968ac165d 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -73,174 +73,6 @@ int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent)
 
 const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\"";
 
-#define CHECK_FETCH_FUNCS(method, fn)			\
-	(((FETCH_FUNC_NAME(method, u8) == fn) ||	\
-	  (FETCH_FUNC_NAME(method, u16) == fn) ||	\
-	  (FETCH_FUNC_NAME(method, u32) == fn) ||	\
-	  (FETCH_FUNC_NAME(method, u64) == fn) ||	\
-	  (FETCH_FUNC_NAME(method, string) == fn) ||	\
-	  (FETCH_FUNC_NAME(method, string_size) == fn)) \
-	 && (fn != NULL))
-
-/* Data fetch function templates */
-#define DEFINE_FETCH_reg(type)						\
-void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, void *offset, void *dest)	\
-{									\
-	*(type *)dest = (type)regs_get_register(regs,			\
-				(unsigned int)((unsigned long)offset));	\
-}									\
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(reg, type));
-DEFINE_BASIC_FETCH_FUNCS(reg)
-/* No string on the register */
-#define fetch_reg_string	NULL
-#define fetch_reg_string_size	NULL
-
-#define DEFINE_FETCH_retval(type)					\
-void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs,		\
-				   void *dummy, void *dest)		\
-{									\
-	*(type *)dest = (type)regs_return_value(regs);			\
-}									\
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(retval, type));
-DEFINE_BASIC_FETCH_FUNCS(retval)
-/* No string on the retval */
-#define fetch_retval_string		NULL
-#define fetch_retval_string_size	NULL
-
-/* Dereference memory access function */
-struct deref_fetch_param {
-	struct fetch_param	orig;
-	long			offset;
-	fetch_func_t		fetch;
-	fetch_func_t		fetch_size;
-};
-
-#define DEFINE_FETCH_deref(type)					\
-void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs,			\
-				  void *data, void *dest)		\
-{									\
-	struct deref_fetch_param *dprm = data;				\
-	unsigned long addr;						\
-	call_fetch(&dprm->orig, regs, &addr);				\
-	if (addr) {							\
-		addr += dprm->offset;					\
-		dprm->fetch(regs, (void *)addr, dest);			\
-	} else								\
-		*(type *)dest = 0;					\
-}									\
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, type));
-DEFINE_BASIC_FETCH_FUNCS(deref)
-DEFINE_FETCH_deref(string)
-
-void FETCH_FUNC_NAME(deref, string_size)(struct pt_regs *regs,
-					 void *data, void *dest)
-{
-	struct deref_fetch_param *dprm = data;
-	unsigned long addr;
-
-	call_fetch(&dprm->orig, regs, &addr);
-	if (addr && dprm->fetch_size) {
-		addr += dprm->offset;
-		dprm->fetch_size(regs, (void *)addr, dest);
-	} else
-		*(string_size *)dest = 0;
-}
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, string_size));
-
-static void update_deref_fetch_param(struct deref_fetch_param *data)
-{
-	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
-		update_deref_fetch_param(data->orig.data);
-	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
-		update_symbol_cache(data->orig.data);
-}
-NOKPROBE_SYMBOL(update_deref_fetch_param);
-
-static void free_deref_fetch_param(struct deref_fetch_param *data)
-{
-	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
-		free_deref_fetch_param(data->orig.data);
-	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
-		free_symbol_cache(data->orig.data);
-	kfree(data);
-}
-NOKPROBE_SYMBOL(free_deref_fetch_param);
-
-/* Bitfield fetch function */
-struct bitfield_fetch_param {
-	struct fetch_param	orig;
-	unsigned char		hi_shift;
-	unsigned char		low_shift;
-};
-
-#define DEFINE_FETCH_bitfield(type)					\
-void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs,		\
-				     void *data, void *dest)		\
-{									\
-	struct bitfield_fetch_param *bprm = data;			\
-	type buf = 0;							\
-	call_fetch(&bprm->orig, regs, &buf);				\
-	if (buf) {							\
-		buf <<= bprm->hi_shift;					\
-		buf >>= bprm->low_shift;				\
-	}								\
-	*(type *)dest = buf;						\
-}									\
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(bitfield, type));
-DEFINE_BASIC_FETCH_FUNCS(bitfield)
-#define fetch_bitfield_string		NULL
-#define fetch_bitfield_string_size	NULL
-
-static void
-update_bitfield_fetch_param(struct bitfield_fetch_param *data)
-{
-	/*
-	 * Don't check the bitfield itself, because this must be the
-	 * last fetch function.
-	 */
-	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
-		update_deref_fetch_param(data->orig.data);
-	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
-		update_symbol_cache(data->orig.data);
-}
-
-static void
-free_bitfield_fetch_param(struct bitfield_fetch_param *data)
-{
-	/*
-	 * Don't check the bitfield itself, because this must be the
-	 * last fetch function.
-	 */
-	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
-		free_deref_fetch_param(data->orig.data);
-	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
-		free_symbol_cache(data->orig.data);
-
-	kfree(data);
-}
-
-void FETCH_FUNC_NAME(comm, string)(struct pt_regs *regs,
-					  void *data, void *dest)
-{
-	int maxlen = get_rloc_len(*(u32 *)dest);
-	u8 *dst = get_rloc_data(dest);
-	long ret;
-
-	if (!maxlen)
-		return;
-
-	ret = strlcpy(dst, current->comm, maxlen);
-	*(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest));
-}
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string));
-
-void FETCH_FUNC_NAME(comm, string_size)(struct pt_regs *regs,
-					       void *data, void *dest)
-{
-	*(u32 *)dest = strlen(current->comm) + 1;
-}
-NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string_size));
-
 static const struct fetch_type *find_fetch_type(const char *type,
 						const struct fetch_type *ftbl)
 {
@@ -284,37 +116,6 @@ static const struct fetch_type *find_fetch_type(const char *type,
 	return NULL;
 }
 
-/* Special function : only accept unsigned long */
-static void fetch_kernel_stack_address(struct pt_regs *regs, void *dummy, void *dest)
-{
-	*(unsigned long *)dest = kernel_stack_pointer(regs);
-}
-NOKPROBE_SYMBOL(fetch_kernel_stack_address);
-
-static void fetch_user_stack_address(struct pt_regs *regs, void *dummy, void *dest)
-{
-	*(unsigned long *)dest = user_stack_pointer(regs);
-}
-NOKPROBE_SYMBOL(fetch_user_stack_address);
-
-static fetch_func_t get_fetch_size_function(const struct fetch_type *type,
-					    fetch_func_t orig_fn,
-					    const struct fetch_type *ftbl)
-{
-	int i;
-
-	if (type != &ftbl[FETCH_TYPE_STRING])
-		return NULL;	/* Only string type needs size function */
-
-	for (i = 0; i < FETCH_MTD_END; i++)
-		if (type->fetch[i] == orig_fn)
-			return ftbl[FETCH_TYPE_STRSIZE].fetch[i];
-
-	WARN_ON(1);	/* This should not happen */
-
-	return NULL;
-}
-
 /* Split symbol and offset. */
 int traceprobe_split_symbol_offset(char *symbol, long *offset)
 {
@@ -339,7 +140,7 @@ int traceprobe_split_symbol_offset(char *symbol, long *offset)
 #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
 
 static int parse_probe_vars(char *arg, const struct fetch_type *t,
-			    struct fetch_param *f, bool is_return,
+			    struct fetch_insn *code, bool is_return,
 			    bool is_kprobe)
 {
 	int ret = 0;
@@ -347,33 +148,24 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
 
 	if (strcmp(arg, "retval") == 0) {
 		if (is_return)
-			f->fn = t->fetch[FETCH_MTD_retval];
+			code->op = FETCH_OP_RETVAL;
 		else
 			ret = -EINVAL;
 	} else if (strncmp(arg, "stack", 5) == 0) {
 		if (arg[5] == '\0') {
-			if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR))
-				return -EINVAL;
-
-			if (is_kprobe)
-				f->fn = fetch_kernel_stack_address;
-			else
-				f->fn = fetch_user_stack_address;
+			code->op = FETCH_OP_STACKP;
 		} else if (isdigit(arg[5])) {
 			ret = kstrtoul(arg + 5, 10, &param);
 			if (ret || (is_kprobe && param > PARAM_MAX_STACK))
 				ret = -EINVAL;
 			else {
-				f->fn = t->fetch[FETCH_MTD_stack];
-				f->data = (void *)param;
+				code->op = FETCH_OP_STACK;
+				code->param = (unsigned int)param;
 			}
 		} else
 			ret = -EINVAL;
 	} else if (strcmp(arg, "comm") == 0) {
-		if (strcmp(t->name, "string") != 0 &&
-		    strcmp(t->name, "string_size") != 0)
-			return -EINVAL;
-		f->fn = t->fetch[FETCH_MTD_comm];
+		code->op = FETCH_OP_COMM;
 	} else
 		ret = -EINVAL;
 
@@ -381,10 +173,13 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
 }
 
 /* Recursive argument parser */
-static int parse_probe_arg(char *arg, const struct fetch_type *t,
-		     struct fetch_param *f, bool is_return, bool is_kprobe,
-		     const struct fetch_type *ftbl)
+static int
+parse_probe_arg(char *arg, const struct fetch_type *type,
+		struct fetch_insn **pcode, struct fetch_insn *end,
+		bool is_return, bool is_kprobe,
+		const struct fetch_type *ftbl)
 {
+	struct fetch_insn *code = *pcode;
 	unsigned long param;
 	long offset;
 	char *tmp;
@@ -392,14 +187,15 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
 
 	switch (arg[0]) {
 	case '$':
-		ret = parse_probe_vars(arg + 1, t, f, is_return, is_kprobe);
+		ret = parse_probe_vars(arg + 1, type, code,
+					is_return, is_kprobe);
 		break;
 
 	case '%':	/* named register */
 		ret = regs_query_register_offset(arg + 1);
 		if (ret >= 0) {
-			f->fn = t->fetch[FETCH_MTD_reg];
-			f->data = (void *)(unsigned long)ret;
+			code->op = FETCH_OP_REG;
+			code->param = (unsigned int)ret;
 			ret = 0;
 		}
 		break;
@@ -409,9 +205,9 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
 			ret = kstrtoul(arg + 1, 0, &param);
 			if (ret)
 				break;
-
-			f->fn = t->fetch[FETCH_MTD_memory];
-			f->data = (void *)param;
+			/* load address */
+			code->op = FETCH_OP_IMM;
+			code->immediate = param;
 		} else if (arg[1] == '+') {
 			/* kprobes don't support file offsets */
 			if (is_kprobe)
@@ -421,8 +217,8 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
 			if (ret)
 				break;
 
-			f->fn = t->fetch[FETCH_MTD_file_offset];
-			f->data = (void *)offset;
+			code->op = FETCH_OP_FOFFS;
+			code->immediate = (unsigned long)offset;  // imm64?
 		} else {
 			/* uprobes don't support symbols */
 			if (!is_kprobe)
@@ -432,10 +228,19 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
 			if (ret)
 				break;
 
-			f->data = alloc_symbol_cache(arg + 1, offset);
-			if (f->data)
-				f->fn = t->fetch[FETCH_MTD_symbol];
+			code->op = FETCH_OP_IMM;
+			code->immediate =
+				(unsigned long)kallsyms_lookup_name(arg + 1);
+			if (!code->immediate)
+				return -ENOENT;
+			code->immediate += offset;
 		}
+		/* These are fetching from memory */
+		if (++code == end)
+			return -E2BIG;
+		*pcode = code;
+		code->op = FETCH_OP_DEREF;
+		code->offset = offset;
 		break;
 
 	case '+':	/* deref memory */
@@ -443,11 +248,10 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
 	case '-':
 		tmp = strchr(arg, '(');
 		if (!tmp)
-			break;
+			return -EINVAL;
 
 		*tmp = '\0';
 		ret = kstrtol(arg, 0, &offset);
-
 		if (ret)
 			break;
 
@@ -455,36 +259,29 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
 		tmp = strrchr(arg, ')');
 
 		if (tmp) {
-			struct deref_fetch_param	*dprm;
-			const struct fetch_type		*t2;
+			const struct fetch_type *t2;
 
 			t2 = find_fetch_type(NULL, ftbl);
 			*tmp = '\0';
-			dprm = kzalloc(sizeof(struct deref_fetch_param), GFP_KERNEL);
-
-			if (!dprm)
-				return -ENOMEM;
-
-			dprm->offset = offset;
-			dprm->fetch = t->fetch[FETCH_MTD_memory];
-			dprm->fetch_size = get_fetch_size_function(t,
-							dprm->fetch, ftbl);
-			ret = parse_probe_arg(arg, t2, &dprm->orig, is_return,
-							is_kprobe, ftbl);
+			ret = parse_probe_arg(arg, t2, &code, end, is_return,
+					      is_kprobe, ftbl);
 			if (ret)
-				kfree(dprm);
-			else {
-				f->fn = t->fetch[FETCH_MTD_deref];
-				f->data = (void *)dprm;
-			}
+				break;
+			if (code->op == FETCH_OP_COMM)
+				return -EINVAL;
+			if (++code == end)
+				return -E2BIG;
+			*pcode = code;
+
+			code->op = FETCH_OP_DEREF;
+			code->offset = offset;
 		}
 		break;
 	}
-	if (!ret && !f->fn) {	/* Parsed, but do not find fetch method */
-		pr_info("%s type has no corresponding fetch method.\n", t->name);
+	if (!ret && code->op == FETCH_OP_NOP) {
+		/* Parsed, but do not find fetch method */
 		ret = -EINVAL;
 	}
-
 	return ret;
 }
 
@@ -493,22 +290,15 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
 /* Bitfield type needs to be parsed into a fetch function */
 static int __parse_bitfield_probe_arg(const char *bf,
 				      const struct fetch_type *t,
-				      struct fetch_param *f)
+				      struct fetch_insn **pcode)
 {
-	struct bitfield_fetch_param *bprm;
+	struct fetch_insn *code = *pcode;
 	unsigned long bw, bo;
 	char *tail;
 
 	if (*bf != 'b')
 		return 0;
 
-	bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
-	if (!bprm)
-		return -ENOMEM;
-
-	bprm->orig = *f;
-	f->fn = t->fetch[FETCH_MTD_bitfield];
-	f->data = (void *)bprm;
 	bw = simple_strtoul(bf + 1, &tail, 0);	/* Use simple one */
 
 	if (bw == 0 || *tail != '@')
@@ -519,9 +309,15 @@ static int __parse_bitfield_probe_arg(const char *bf,
 
 	if (tail == bf || *tail != '/')
 		return -EINVAL;
+	code++;
+	if (code->op != FETCH_OP_NOP)
+		return -E2BIG;
+	*pcode = code;
 
-	bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo);
-	bprm->low_shift = bprm->hi_shift + bo;
+	code->op = FETCH_OP_MOD_BF;
+	code->lshift = BYTES_TO_BITS(t->size) - (bw + bo);
+	code->rshift = BYTES_TO_BITS(t->size) - bw;
+	code->basesize = t->size;
 
 	return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0;
 }
@@ -531,6 +327,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 		struct probe_arg *parg, bool is_return, bool is_kprobe,
 		const struct fetch_type *ftbl)
 {
+	struct fetch_insn *code, *tmp = NULL;
 	const char *t;
 	int ret;
 
@@ -561,18 +358,60 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 	}
 	parg->offset = *size;
 	*size += parg->type->size;
-	ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return,
-			      is_kprobe, ftbl);
-
-	if (ret >= 0 && t != NULL)
-		ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch);
 
-	if (ret >= 0) {
-		parg->fetch_size.fn = get_fetch_size_function(parg->type,
-							      parg->fetch.fn,
-							      ftbl);
-		parg->fetch_size.data = parg->fetch.data;
+	code = tmp = kzalloc(sizeof(*code) * FETCH_INSN_MAX, GFP_KERNEL);
+	if (!code)
+		return -ENOMEM;
+	code[FETCH_INSN_MAX - 1].op = FETCH_OP_END;
+
+	ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1],
+			      is_return, is_kprobe, ftbl);
+	if (ret)
+		goto fail;
+
+	/* Store operation */
+	if (!strcmp(parg->type->name, "string")) {
+		if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_IMM &&
+		    code->op != FETCH_OP_COMM) {
+			pr_info("string only accepts memory or address.\n");
+			ret = -EINVAL;
+			goto fail;
+		}
+		/* Since IMM or COMM must be the 1st insn, this is safe */
+		if (code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM)
+			code++;
+		code->op = FETCH_OP_ST_STRING;	/* In DEREF case, replace it */
+		parg->dynamic = true;
+	} else if (code->op == FETCH_OP_DEREF) {
+		code->op = FETCH_OP_ST_MEM;
+		code->size = parg->type->size;
+	} else {
+		code++;
+		if (code->op != FETCH_OP_NOP) {
+			ret = -E2BIG;
+			goto fail;
+		}
+		code->op = FETCH_OP_ST_RAW;
+		code->size = parg->type->size;
+	}
+	/* Modify operation */
+	if (t != NULL) {
+		ret = __parse_bitfield_probe_arg(t, parg->type, &code);
+		if (ret)
+			goto fail;
 	}
+	code++;
+	code->op = FETCH_OP_END;
+
+	/* Shrink down the code buffer */
+	parg->code = kzalloc(sizeof(*code) * (code - tmp + 1), GFP_KERNEL);
+	if (!parg->code)
+		ret = -ENOMEM;
+	else
+		memcpy(parg->code, tmp, sizeof(*code) * (code - tmp + 1));
+
+fail:
+	kfree(tmp);
 
 	return ret;
 }
@@ -594,25 +433,9 @@ int traceprobe_conflict_field_name(const char *name,
 	return 0;
 }
 
-void traceprobe_update_arg(struct probe_arg *arg)
-{
-	if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))
-		update_bitfield_fetch_param(arg->fetch.data);
-	else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
-		update_deref_fetch_param(arg->fetch.data);
-	else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))
-		update_symbol_cache(arg->fetch.data);
-}
-
 void traceprobe_free_probe_arg(struct probe_arg *arg)
 {
-	if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))
-		free_bitfield_fetch_param(arg->fetch.data);
-	else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
-		free_deref_fetch_param(arg->fetch.data);
-	else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))
-		free_symbol_cache(arg->fetch.data);
-
+	kfree(arg->code);
 	kfree(arg->name);
 	kfree(arg->comm);
 }
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index de928052926b..9d9de7535d06 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -91,25 +91,50 @@ static nokprobe_inline void *get_loc_data(u32 *dl, void *ent)
 	return (u8 *)ent + get_rloc_offs(*dl);
 }
 
-/* Data fetch function type */
-typedef	void (*fetch_func_t)(struct pt_regs *, void *, void *);
 /* Printing function type */
 typedef int (*print_type_func_t)(struct trace_seq *, void *, void *);
 
-/* Fetch types */
-enum {
-	FETCH_MTD_reg = 0,
-	FETCH_MTD_stack,
-	FETCH_MTD_retval,
-	FETCH_MTD_comm,
-	FETCH_MTD_memory,
-	FETCH_MTD_symbol,
-	FETCH_MTD_deref,
-	FETCH_MTD_bitfield,
-	FETCH_MTD_file_offset,
-	FETCH_MTD_END,
+enum fetch_op {
+	FETCH_OP_NOP = 0,
+	// Stage 1 (load) ops
+	FETCH_OP_REG,		/* Register : .param = offset */
+	FETCH_OP_STACK,		/* Stack : .param = index */
+	FETCH_OP_STACKP,	/* Stack pointer */
+	FETCH_OP_RETVAL,	/* Return value */
+	FETCH_OP_IMM,		/* Immediate : .immediate */
+	FETCH_OP_COMM,		/* Current comm */
+	FETCH_OP_FOFFS,		/* File offset: .immediate */
+	// Stage 2 (dereference) op
+	FETCH_OP_DEREF,		/* Dereference: .offset */
+	// Stage 3 (store) ops
+	FETCH_OP_ST_RAW,	/* Raw: .size */
+	FETCH_OP_ST_MEM,	/* Mem: .offset, .size */
+	FETCH_OP_ST_STRING,	/* String: .offset, .size */
+	// Stage 4 (modify) op
+	FETCH_OP_MOD_BF,	/* Bitfield: .basesize, .lshift, .rshift */
+	FETCH_OP_END,
 };
 
+struct fetch_insn {
+	enum fetch_op op;
+	union {
+		unsigned int param;
+		struct {
+			unsigned int size;
+			int offset;
+		};
+		struct {
+			unsigned char basesize;
+			unsigned char lshift;
+			unsigned char rshift;
+		};
+		unsigned long immediate;
+	};
+};
+
+/* fetch + deref*N + store + mod + end <= 16, this allows N=12, enough */
+#define FETCH_INSN_MAX	16
+
 /* Fetch type information table */
 struct fetch_type {
 	const char		*name;		/* Name of type */
@@ -118,13 +143,6 @@ struct fetch_type {
 	print_type_func_t	print;		/* Print functions */
 	const char		*fmt;		/* Fromat string */
 	const char		*fmttype;	/* Name in format file */
-	/* Fetch functions */
-	fetch_func_t		fetch[FETCH_MTD_END];
-};
-
-struct fetch_param {
-	fetch_func_t		fn;
-	void 			*data;
 };
 
 /* For defining macros, define string/string_size types */
@@ -154,66 +172,12 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(x64);
 
 DECLARE_BASIC_PRINT_TYPE_FUNC(string);
 
-#define FETCH_FUNC_NAME(method, type)	fetch_##method##_##type
-
-/* Declare macro for basic types */
-#define DECLARE_FETCH_FUNC(method, type)				\
-extern void FETCH_FUNC_NAME(method, type)(struct pt_regs *regs, 	\
-					  void *data, void *dest)
-
-#define DECLARE_BASIC_FETCH_FUNCS(method) 	\
-DECLARE_FETCH_FUNC(method, u8);			\
-DECLARE_FETCH_FUNC(method, u16);		\
-DECLARE_FETCH_FUNC(method, u32);		\
-DECLARE_FETCH_FUNC(method, u64)
-
-DECLARE_BASIC_FETCH_FUNCS(reg);
-#define fetch_reg_string			NULL
-#define fetch_reg_string_size			NULL
-
-DECLARE_BASIC_FETCH_FUNCS(retval);
-#define fetch_retval_string			NULL
-#define fetch_retval_string_size		NULL
-
-DECLARE_BASIC_FETCH_FUNCS(symbol);
-DECLARE_FETCH_FUNC(symbol, string);
-DECLARE_FETCH_FUNC(symbol, string_size);
-
-DECLARE_BASIC_FETCH_FUNCS(deref);
-DECLARE_FETCH_FUNC(deref, string);
-DECLARE_FETCH_FUNC(deref, string_size);
-
-DECLARE_BASIC_FETCH_FUNCS(bitfield);
-#define fetch_bitfield_string			NULL
-#define fetch_bitfield_string_size		NULL
-
-/* comm only makes sense as a string */
-#define fetch_comm_u8		NULL
-#define fetch_comm_u16		NULL
-#define fetch_comm_u32		NULL
-#define fetch_comm_u64		NULL
-DECLARE_FETCH_FUNC(comm, string);
-DECLARE_FETCH_FUNC(comm, string_size);
-
-/*
- * Define macro for basic types - we don't need to define s* types, because
- * we have to care only about bitwidth at recording time.
- */
-#define DEFINE_BASIC_FETCH_FUNCS(method) \
-DEFINE_FETCH_##method(u8)		\
-DEFINE_FETCH_##method(u16)		\
-DEFINE_FETCH_##method(u32)		\
-DEFINE_FETCH_##method(u64)
-
 /* Default (unsigned long) fetch type */
 #define __DEFAULT_FETCH_TYPE(t) x##t
 #define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t)
 #define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG)
 #define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE)
 
-#define ASSIGN_FETCH_FUNC(method, type)	\
-	[FETCH_MTD_##method] = FETCH_FUNC_NAME(method, type)
-
 #define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype)	\
 	{.name = _name,				\
 	 .size = _size,					\
@@ -221,17 +185,6 @@ DEFINE_FETCH_##method(u64)
 	 .print = PRINT_TYPE_FUNC_NAME(ptype),		\
 	 .fmt = PRINT_TYPE_FMT_NAME(ptype),		\
 	 .fmttype = _fmttype,				\
-	 .fetch = {					\
-ASSIGN_FETCH_FUNC(reg, ftype),				\
-ASSIGN_FETCH_FUNC(stack, ftype),			\
-ASSIGN_FETCH_FUNC(retval, ftype),			\
-ASSIGN_FETCH_FUNC(comm, ftype),				\
-ASSIGN_FETCH_FUNC(memory, ftype),			\
-ASSIGN_FETCH_FUNC(symbol, ftype),			\
-ASSIGN_FETCH_FUNC(deref, ftype),			\
-ASSIGN_FETCH_FUNC(bitfield, ftype),			\
-ASSIGN_FETCH_FUNC(file_offset, ftype),			\
-	  }						\
 	}
 
 #define ASSIGN_FETCH_TYPE(ptype, ftype, sign)			\
@@ -243,42 +196,13 @@ ASSIGN_FETCH_FUNC(file_offset, ftype),			\
 
 #define ASSIGN_FETCH_TYPE_END {}
 
-#define FETCH_TYPE_STRING	0
-#define FETCH_TYPE_STRSIZE	1
+#define FETCH_TYPE_STRING      0
+#define FETCH_TYPE_STRSIZE     1
 
 #ifdef CONFIG_KPROBE_EVENTS
-struct symbol_cache;
-unsigned long update_symbol_cache(struct symbol_cache *sc);
-void free_symbol_cache(struct symbol_cache *sc);
-struct symbol_cache *alloc_symbol_cache(const char *sym, long offset);
 bool trace_kprobe_on_func_entry(struct trace_event_call *call);
 bool trace_kprobe_error_injectable(struct trace_event_call *call);
 #else
-/* uprobes do not support symbol fetch methods */
-#define fetch_symbol_u8			NULL
-#define fetch_symbol_u16		NULL
-#define fetch_symbol_u32		NULL
-#define fetch_symbol_u64		NULL
-#define fetch_symbol_string		NULL
-#define fetch_symbol_string_size	NULL
-
-struct symbol_cache {
-};
-static inline unsigned long __used update_symbol_cache(struct symbol_cache *sc)
-{
-	return 0;
-}
-
-static inline void __used free_symbol_cache(struct symbol_cache *sc)
-{
-}
-
-static inline struct symbol_cache * __used
-alloc_symbol_cache(const char *sym, long offset)
-{
-	return NULL;
-}
-
 static inline bool trace_kprobe_on_func_entry(struct trace_event_call *call)
 {
 	return false;
@@ -291,8 +215,8 @@ static inline bool trace_kprobe_error_injectable(struct trace_event_call *call)
 #endif /* CONFIG_KPROBE_EVENTS */
 
 struct probe_arg {
-	struct fetch_param	fetch;
-	struct fetch_param	fetch_size;
+	struct fetch_insn	*code;
+	bool			dynamic;/* Dynamic array (string) is used */
 	unsigned int		offset;	/* Offset from argument entry */
 	const char		*name;	/* Name of this argument */
 	const char		*comm;	/* Command of this argument */
@@ -324,12 +248,6 @@ static inline bool trace_probe_is_registered(struct trace_probe *tp)
 	return !!(tp->flags & TP_FLAG_REGISTERED);
 }
 
-static nokprobe_inline void call_fetch(struct fetch_param *fprm,
-				 struct pt_regs *regs, void *dest)
-{
-	return fprm->fn(regs, fprm->data, dest);
-}
-
 /* Check the name is good for event/group/fields */
 static inline bool is_good_name(const char *name)
 {
@@ -366,68 +284,6 @@ extern void traceprobe_free_probe_arg(struct probe_arg *arg);
 
 extern int traceprobe_split_symbol_offset(char *symbol, long *offset);
 
-/* Sum up total data length for dynamic arraies (strings) */
-static nokprobe_inline int
-__get_data_size(struct trace_probe *tp, struct pt_regs *regs)
-{
-	int i, ret = 0;
-	u32 len;
-
-	for (i = 0; i < tp->nr_args; i++)
-		if (unlikely(tp->args[i].fetch_size.fn)) {
-			call_fetch(&tp->args[i].fetch_size, regs, &len);
-			ret += len;
-		}
-
-	return ret;
-}
-
-/* Store the value of each argument */
-static nokprobe_inline void
-store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs,
-		 u8 *data, int maxlen)
-{
-	int i;
-	u32 end = tp->size;
-	u32 *dl;	/* Data (relative) location */
-
-	for (i = 0; i < tp->nr_args; i++) {
-		if (unlikely(tp->args[i].fetch_size.fn)) {
-			/*
-			 * First, we set the relative location and
-			 * maximum data length to *dl
-			 */
-			dl = (u32 *)(data + tp->args[i].offset);
-			*dl = make_data_rloc(maxlen, end - tp->args[i].offset);
-			/* Then try to fetch string or dynamic array data */
-			call_fetch(&tp->args[i].fetch, regs, dl);
-			/* Reduce maximum length */
-			end += get_rloc_len(*dl);
-			maxlen -= get_rloc_len(*dl);
-			/* Trick here, convert data_rloc to data_loc */
-			*dl = convert_rloc_to_loc(*dl,
-				 ent_size + tp->args[i].offset);
-		} else
-			/* Just fetching data normally */
-			call_fetch(&tp->args[i].fetch, regs,
-				   data + tp->args[i].offset);
-	}
-}
-
-static inline int
-print_probe_args(struct trace_seq *s, struct probe_arg *args, int nr_args,
-		 u8 *data, void *field)
-{
-	int i;
-
-	for (i = 0; i < nr_args; i++) {
-		trace_seq_printf(s, " %s=", args[i].name);
-		if (!args[i].type->print(s, data + args[i].offset, field))
-			return -ENOMEM;
-	}
-	return 0;
-}
-
 extern int set_print_fmt(struct trace_probe *tp, bool is_return);
 
 #ifdef CONFIG_PERF_EVENTS
diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmpl.h
new file mode 100644
index 000000000000..c8a5272abf01
--- /dev/null
+++ b/kernel/trace/trace_probe_tmpl.h
@@ -0,0 +1,120 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Traceprobe fetch helper inlines
+ */
+
+static nokprobe_inline void
+fetch_store_raw(unsigned long val, struct fetch_insn *code, void *buf)
+{
+	switch (code->size) {
+	case 1:
+		*(u8 *)buf = (u8)val;
+		break;
+	case 2:
+		*(u16 *)buf = (u16)val;
+		break;
+	case 4:
+		*(u32 *)buf = (u32)val;
+		break;
+	case 8:
+		//TBD: 32bit signed
+		*(u64 *)buf = (u64)val;
+		break;
+	default:
+		*(unsigned long *)buf = val;
+	}
+}
+
+static nokprobe_inline void
+fetch_apply_bitfield(struct fetch_insn *code, void *buf)
+{
+	switch (code->basesize) {
+	case 1:
+		*(u8 *)buf <<= code->lshift;
+		*(u8 *)buf >>= code->rshift;
+		break;
+	case 2:
+		*(u16 *)buf <<= code->lshift;
+		*(u16 *)buf >>= code->rshift;
+		break;
+	case 4:
+		*(u32 *)buf <<= code->lshift;
+		*(u32 *)buf >>= code->rshift;
+		break;
+	case 8:
+		*(u64 *)buf <<= code->lshift;
+		*(u64 *)buf >>= code->rshift;
+		break;
+	}
+}
+
+/* Define this for each callsite */
+static int
+process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs,
+		   void *dest, bool pre);
+
+/* Sum up total data length for dynamic arraies (strings) */
+static nokprobe_inline int
+__get_data_size(struct trace_probe *tp, struct pt_regs *regs)
+{
+	struct probe_arg *arg;
+	int i, ret = 0;
+	u32 len;
+
+	for (i = 0; i < tp->nr_args; i++) {
+		arg = tp->args + i;
+		if (unlikely(arg->dynamic)) {
+			process_fetch_insn(arg->code, regs, &len, true);
+			ret += len;
+		}
+	}
+
+	return ret;
+}
+
+/* Store the value of each argument */
+static nokprobe_inline void
+store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs,
+		 u8 *data, int maxlen)
+{
+	struct probe_arg *arg;
+	u32 end = tp->size;
+	u32 *dl;	/* Data (relative) location */
+	int i;
+
+	for (i = 0; i < tp->nr_args; i++) {
+		arg = tp->args + i;
+		if (unlikely(arg->dynamic)) {
+			/*
+			 * First, we set the relative location and
+			 * maximum data length to *dl
+			 */
+			dl = (u32 *)(data + arg->offset);
+			*dl = make_data_rloc(maxlen, end - arg->offset);
+			/* Then try to fetch string or dynamic array data */
+			process_fetch_insn(arg->code, regs, dl, false);
+			/* Reduce maximum length */
+			end += get_rloc_len(*dl);
+			maxlen -= get_rloc_len(*dl);
+			/* Trick here, convert data_rloc to data_loc */
+			*dl = convert_rloc_to_loc(*dl, ent_size + arg->offset);
+		} else
+			/* Just fetching data normally */
+			process_fetch_insn(arg->code, regs, data + arg->offset,
+					   false);
+	}
+}
+
+static inline int
+print_probe_args(struct trace_seq *s, struct probe_arg *args, int nr_args,
+		 u8 *data, void *field)
+{
+	int i;
+
+	for (i = 0; i < nr_args; i++) {
+		trace_seq_printf(s, " %s=", args[i].name);
+		if (!args[i].type->print(s, data + args[i].offset, field))
+			return -ENOMEM;
+	}
+	return 0;
+}
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index c21c3783d055..ff408edd3a68 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -27,6 +27,7 @@
 #include <linux/rculist.h>
 
 #include "trace_probe.h"
+#include "trace_probe_tmpl.h"
 
 #define UPROBE_EVENT_SYSTEM	"uprobes"
 
@@ -109,37 +110,19 @@ static unsigned long get_user_stack_nth(struct pt_regs *regs, unsigned int n)
 /*
  * Uprobes-specific fetch functions
  */
-#define DEFINE_FETCH_stack(type)					\
-static void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,		\
-					 void *offset, void *dest)	\
-{									\
-	*(type *)dest = (type)get_user_stack_nth(regs,			\
-					      ((unsigned long)offset)); \
-}
-DEFINE_BASIC_FETCH_FUNCS(stack)
-/* No string on the stack entry */
-#define fetch_stack_string	NULL
-#define fetch_stack_string_size	NULL
-
-#define DEFINE_FETCH_memory(type)					\
-static void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,		\
-					  void *addr, void *dest)	\
-{									\
-	type retval;							\
-	void __user *vaddr = (void __force __user *) addr;		\
-									\
-	if (copy_from_user(&retval, vaddr, sizeof(type)))		\
-		*(type *)dest = 0;					\
-	else								\
-		*(type *) dest = retval;				\
+static nokprobe_inline int
+probe_user_read(void *dest, void *src, size_t size)
+{
+	void __user *vaddr = (void __force __user *)src;
+
+	return copy_from_user(dest, vaddr, size);
 }
-DEFINE_BASIC_FETCH_FUNCS(memory)
 /*
  * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
  * length and relative data location.
  */
-static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
-					    void *addr, void *dest)
+static nokprobe_inline void
+fetch_store_string(unsigned long addr, void *dest)
 {
 	long ret;
 	u32 rloc = *(u32 *)dest;
@@ -162,8 +145,9 @@ static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
 	}
 }
 
-static void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
-						 void *addr, void *dest)
+/* Return the length of string -- including null terminal byte */
+static nokprobe_inline void
+fetch_store_strlen(unsigned long addr, void *dest)
 {
 	int len;
 	void __user *vaddr = (void __force __user *) addr;
@@ -176,7 +160,7 @@ static void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
 		*(u32 *)dest = len;
 }
 
-static unsigned long translate_user_vaddr(void *file_offset)
+static unsigned long translate_user_vaddr(unsigned long file_offset)
 {
 	unsigned long base_addr;
 	struct uprobe_dispatch_data *udd;
@@ -184,21 +168,9 @@ static unsigned long translate_user_vaddr(void *file_offset)
 	udd = (void *) current->utask->vaddr;
 
 	base_addr = udd->bp_addr - udd->tu->offset;
-	return base_addr + (unsigned long)file_offset;
+	return base_addr + file_offset;
 }
 
-#define DEFINE_FETCH_file_offset(type)					\
-static void FETCH_FUNC_NAME(file_offset, type)(struct pt_regs *regs,	\
-					       void *offset, void *dest)\
-{									\
-	void *vaddr = (void *)translate_user_vaddr(offset);		\
-									\
-	FETCH_FUNC_NAME(memory, type)(regs, vaddr, dest);		\
-}
-DEFINE_BASIC_FETCH_FUNCS(file_offset)
-DEFINE_FETCH_file_offset(string)
-DEFINE_FETCH_file_offset(string_size)
-
 /* Fetch type information table */
 static const struct fetch_type uprobes_fetch_type_table[] = {
 	/* Special types */
@@ -223,6 +195,77 @@ static const struct fetch_type uprobes_fetch_type_table[] = {
 	ASSIGN_FETCH_TYPE_END
 };
 
+/* Note that we don't verify it, since the code does not come from user space */
+static int
+process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
+		   bool pre)
+{
+	unsigned long val;
+	int ret;
+
+	/* 1st stage: get value from context */
+	switch (code->op) {
+	case FETCH_OP_REG:
+		val = regs_get_register(regs, code->param);
+		break;
+	case FETCH_OP_STACK:
+		val = get_user_stack_nth(regs, code->param);
+		break;
+	case FETCH_OP_STACKP:
+		val = user_stack_pointer(regs);
+		break;
+	case FETCH_OP_RETVAL:
+		val = regs_return_value(regs);
+		break;
+	case FETCH_OP_IMM:
+		val = code->immediate;
+		break;
+	case FETCH_OP_FOFFS:
+		val = translate_user_vaddr(code->immediate);
+		break;
+	default:
+		return -EILSEQ;
+	}
+	code++;
+
+	/* 2nd stage: dereference memory if needed */
+	while (code->op == FETCH_OP_DEREF) {
+		ret = probe_user_read(&val, (void *)val + code->offset,
+				      sizeof(val));
+		if (ret)
+			return ret;
+		code++;
+	}
+
+	/* 3rd stage: store value to buffer */
+	switch (code->op) {
+	case FETCH_OP_ST_RAW:
+		fetch_store_raw(val, code, dest);
+		break;
+	case FETCH_OP_ST_MEM:
+		probe_user_read(dest, (void *)val + code->offset, code->size);
+		break;
+	case FETCH_OP_ST_STRING:
+		if (pre)
+			fetch_store_strlen(val + code->offset, dest);
+		else
+			fetch_store_string(val + code->offset, dest);
+		break;
+	default:
+		return -EILSEQ;
+	}
+	code++;
+
+	/* 4th stage: modify stored value if needed */
+	if (code->op == FETCH_OP_MOD_BF) {
+		fetch_apply_bitfield(code, dest);
+		code++;
+	}
+
+	return code->op == FETCH_OP_END ? 0 : -EILSEQ;
+}
+NOKPROBE_SYMBOL(process_fetch_insn)
+
 static inline void init_trace_uprobe_filter(struct trace_uprobe_filter *filter)
 {
 	rwlock_init(&filter->rwlock);

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 05/16] tracing: probeevent: Unify fetch type tables
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
                   ` (4 preceding siblings ...)
  2018-04-25 12:18 ` [PATCH v7 04/16] tracing: probeevent: Introduce new argument fetching code mhiramat
@ 2018-04-25 12:18 ` mhiramat
  2018-04-25 12:18   ` Masami Hiramatsu
  2018-04-25 12:19 ` [PATCH v7 06/16] tracing: probeevent: Return consumed bytes of dynamic area mhiramat
                   ` (13 subsequent siblings)
  19 siblings, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-04-25 12:18 UTC (permalink / raw)


Unify {k,u}probe_fetch_type_table to probe_fetch_type_table
because the main difference of those type tables (fetcharg
methods) are gone. Now we can consolidate it.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 kernel/trace/trace_kprobe.c |   27 +---------------------
 kernel/trace/trace_probe.c  |   54 +++++++++++++++++++++++++++++--------------
 kernel/trace/trace_probe.h  |    6 +----
 kernel/trace/trace_uprobe.c |   27 +---------------------
 4 files changed, 39 insertions(+), 75 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 1d1e37058f8a..0b73b1ee82c8 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -122,30 +122,6 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs);
 static int kretprobe_dispatcher(struct kretprobe_instance *ri,
 				struct pt_regs *regs);
 
-/* Fetch type information table */
-static const struct fetch_type kprobes_fetch_type_table[] = {
-	/* Special types */
-	[FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string,
-					sizeof(u32), 1, "__data_loc char[]"),
-	[FETCH_TYPE_STRSIZE] = __ASSIGN_FETCH_TYPE("string_size", u32,
-					string_size, sizeof(u32), 0, "u32"),
-	/* Basic types */
-	ASSIGN_FETCH_TYPE(u8,  u8,  0),
-	ASSIGN_FETCH_TYPE(u16, u16, 0),
-	ASSIGN_FETCH_TYPE(u32, u32, 0),
-	ASSIGN_FETCH_TYPE(u64, u64, 0),
-	ASSIGN_FETCH_TYPE(s8,  u8,  1),
-	ASSIGN_FETCH_TYPE(s16, u16, 1),
-	ASSIGN_FETCH_TYPE(s32, u32, 1),
-	ASSIGN_FETCH_TYPE(s64, u64, 1),
-	ASSIGN_FETCH_TYPE_ALIAS(x8,  u8,  u8,  0),
-	ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0),
-	ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0),
-	ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0),
-
-	ASSIGN_FETCH_TYPE_END
-};
-
 /*
  * Allocate new trace_probe and initialize it (including kprobes).
  */
@@ -674,8 +650,7 @@ static int create_trace_kprobe(int argc, char **argv)
 
 		/* Parse fetch argument */
 		ret = traceprobe_parse_probe_arg(arg, &tk->tp.size, parg,
-						 is_return, true,
-						 kprobes_fetch_type_table);
+						 is_return, true);
 		if (ret) {
 			pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
 			goto error;
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 758968ac165d..ed3766fb290d 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -73,8 +73,29 @@ int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent)
 
 const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\"";
 
-static const struct fetch_type *find_fetch_type(const char *type,
-						const struct fetch_type *ftbl)
+/* Fetch type information table */
+static const struct fetch_type probe_fetch_types[] = {
+	/* Special types */
+	__ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1,
+			    "__data_loc char[]"),
+	/* Basic types */
+	ASSIGN_FETCH_TYPE(u8,  u8,  0),
+	ASSIGN_FETCH_TYPE(u16, u16, 0),
+	ASSIGN_FETCH_TYPE(u32, u32, 0),
+	ASSIGN_FETCH_TYPE(u64, u64, 0),
+	ASSIGN_FETCH_TYPE(s8,  u8,  1),
+	ASSIGN_FETCH_TYPE(s16, u16, 1),
+	ASSIGN_FETCH_TYPE(s32, u32, 1),
+	ASSIGN_FETCH_TYPE(s64, u64, 1),
+	ASSIGN_FETCH_TYPE_ALIAS(x8,  u8,  u8,  0),
+	ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0),
+	ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0),
+	ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0),
+
+	ASSIGN_FETCH_TYPE_END
+};
+
+static const struct fetch_type *find_fetch_type(const char *type)
 {
 	int i;
 
@@ -95,21 +116,21 @@ static const struct fetch_type *find_fetch_type(const char *type,
 
 		switch (bs) {
 		case 8:
-			return find_fetch_type("u8", ftbl);
+			return find_fetch_type("u8");
 		case 16:
-			return find_fetch_type("u16", ftbl);
+			return find_fetch_type("u16");
 		case 32:
-			return find_fetch_type("u32", ftbl);
+			return find_fetch_type("u32");
 		case 64:
-			return find_fetch_type("u64", ftbl);
+			return find_fetch_type("u64");
 		default:
 			goto fail;
 		}
 	}
 
-	for (i = 0; ftbl[i].name; i++) {
-		if (strcmp(type, ftbl[i].name) == 0)
-			return &ftbl[i];
+	for (i = 0; probe_fetch_types[i].name; i++) {
+		if (strcmp(type, probe_fetch_types[i].name) == 0)
+			return &probe_fetch_types[i];
 	}
 
 fail:
@@ -176,8 +197,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
 static int
 parse_probe_arg(char *arg, const struct fetch_type *type,
 		struct fetch_insn **pcode, struct fetch_insn *end,
-		bool is_return, bool is_kprobe,
-		const struct fetch_type *ftbl)
+		bool is_return, bool is_kprobe)
 {
 	struct fetch_insn *code = *pcode;
 	unsigned long param;
@@ -259,12 +279,11 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 		tmp = strrchr(arg, ')');
 
 		if (tmp) {
-			const struct fetch_type *t2;
+			const struct fetch_type *t2 = find_fetch_type(NULL);
 
-			t2 = find_fetch_type(NULL, ftbl);
 			*tmp = '\0';
 			ret = parse_probe_arg(arg, t2, &code, end, is_return,
-					      is_kprobe, ftbl);
+					      is_kprobe);
 			if (ret)
 				break;
 			if (code->op == FETCH_OP_COMM)
@@ -324,8 +343,7 @@ static int __parse_bitfield_probe_arg(const char *bf,
 
 /* String length checking wrapper */
 int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
-		struct probe_arg *parg, bool is_return, bool is_kprobe,
-		const struct fetch_type *ftbl)
+		struct probe_arg *parg, bool is_return, bool is_kprobe)
 {
 	struct fetch_insn *code, *tmp = NULL;
 	const char *t;
@@ -351,7 +369,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 	 */
 	if (!t && strcmp(arg, "$comm") == 0)
 		t = "string";
-	parg->type = find_fetch_type(t, ftbl);
+	parg->type = find_fetch_type(t);
 	if (!parg->type) {
 		pr_info("Unsupported type: %s\n", t);
 		return -EINVAL;
@@ -365,7 +383,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 	code[FETCH_INSN_MAX - 1].op = FETCH_OP_END;
 
 	ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1],
-			      is_return, is_kprobe, ftbl);
+			      is_return, is_kprobe);
 	if (ret)
 		goto fail;
 
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 9d9de7535d06..89d853ef5174 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -196,9 +196,6 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(string);
 
 #define ASSIGN_FETCH_TYPE_END {}
 
-#define FETCH_TYPE_STRING      0
-#define FETCH_TYPE_STRSIZE     1
-
 #ifdef CONFIG_KPROBE_EVENTS
 bool trace_kprobe_on_func_entry(struct trace_event_call *call);
 bool trace_kprobe_error_injectable(struct trace_event_call *call);
@@ -273,8 +270,7 @@ find_event_file_link(struct trace_probe *tp, struct trace_event_file *file)
 }
 
 extern int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
-		   struct probe_arg *parg, bool is_return, bool is_kprobe,
-		   const struct fetch_type *ftbl);
+		   struct probe_arg *parg, bool is_return, bool is_kprobe);
 
 extern int traceprobe_conflict_field_name(const char *name,
 			       struct probe_arg *args, int narg);
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index ff408edd3a68..e56925e77781 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -171,30 +171,6 @@ static unsigned long translate_user_vaddr(unsigned long file_offset)
 	return base_addr + file_offset;
 }
 
-/* Fetch type information table */
-static const struct fetch_type uprobes_fetch_type_table[] = {
-	/* Special types */
-	[FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string,
-					sizeof(u32), 1, "__data_loc char[]"),
-	[FETCH_TYPE_STRSIZE] = __ASSIGN_FETCH_TYPE("string_size", u32,
-					string_size, sizeof(u32), 0, "u32"),
-	/* Basic types */
-	ASSIGN_FETCH_TYPE(u8,  u8,  0),
-	ASSIGN_FETCH_TYPE(u16, u16, 0),
-	ASSIGN_FETCH_TYPE(u32, u32, 0),
-	ASSIGN_FETCH_TYPE(u64, u64, 0),
-	ASSIGN_FETCH_TYPE(s8,  u8,  1),
-	ASSIGN_FETCH_TYPE(s16, u16, 1),
-	ASSIGN_FETCH_TYPE(s32, u32, 1),
-	ASSIGN_FETCH_TYPE(s64, u64, 1),
-	ASSIGN_FETCH_TYPE_ALIAS(x8,  u8,  u8,  0),
-	ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0),
-	ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0),
-	ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0),
-
-	ASSIGN_FETCH_TYPE_END
-};
-
 /* Note that we don't verify it, since the code does not come from user space */
 static int
 process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
@@ -583,8 +559,7 @@ static int create_trace_uprobe(int argc, char **argv)
 
 		/* Parse fetch argument */
 		ret = traceprobe_parse_probe_arg(arg, &tu->tp.size, parg,
-						 is_return, false,
-						 uprobes_fetch_type_table);
+						 is_return, false);
 		if (ret) {
 			pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
 			goto error;

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 05/16] tracing: probeevent: Unify fetch type tables
  2018-04-25 12:18 ` [PATCH v7 05/16] tracing: probeevent: Unify fetch type tables mhiramat
@ 2018-04-25 12:18   ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-04-25 12:18 UTC (permalink / raw)


Unify {k,u}probe_fetch_type_table to probe_fetch_type_table
because the main difference of those type tables (fetcharg
methods) are gone. Now we can consolidate it.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 kernel/trace/trace_kprobe.c |   27 +---------------------
 kernel/trace/trace_probe.c  |   54 +++++++++++++++++++++++++++++--------------
 kernel/trace/trace_probe.h  |    6 +----
 kernel/trace/trace_uprobe.c |   27 +---------------------
 4 files changed, 39 insertions(+), 75 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 1d1e37058f8a..0b73b1ee82c8 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -122,30 +122,6 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs);
 static int kretprobe_dispatcher(struct kretprobe_instance *ri,
 				struct pt_regs *regs);
 
-/* Fetch type information table */
-static const struct fetch_type kprobes_fetch_type_table[] = {
-	/* Special types */
-	[FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string,
-					sizeof(u32), 1, "__data_loc char[]"),
-	[FETCH_TYPE_STRSIZE] = __ASSIGN_FETCH_TYPE("string_size", u32,
-					string_size, sizeof(u32), 0, "u32"),
-	/* Basic types */
-	ASSIGN_FETCH_TYPE(u8,  u8,  0),
-	ASSIGN_FETCH_TYPE(u16, u16, 0),
-	ASSIGN_FETCH_TYPE(u32, u32, 0),
-	ASSIGN_FETCH_TYPE(u64, u64, 0),
-	ASSIGN_FETCH_TYPE(s8,  u8,  1),
-	ASSIGN_FETCH_TYPE(s16, u16, 1),
-	ASSIGN_FETCH_TYPE(s32, u32, 1),
-	ASSIGN_FETCH_TYPE(s64, u64, 1),
-	ASSIGN_FETCH_TYPE_ALIAS(x8,  u8,  u8,  0),
-	ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0),
-	ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0),
-	ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0),
-
-	ASSIGN_FETCH_TYPE_END
-};
-
 /*
  * Allocate new trace_probe and initialize it (including kprobes).
  */
@@ -674,8 +650,7 @@ static int create_trace_kprobe(int argc, char **argv)
 
 		/* Parse fetch argument */
 		ret = traceprobe_parse_probe_arg(arg, &tk->tp.size, parg,
-						 is_return, true,
-						 kprobes_fetch_type_table);
+						 is_return, true);
 		if (ret) {
 			pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
 			goto error;
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 758968ac165d..ed3766fb290d 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -73,8 +73,29 @@ int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent)
 
 const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\"";
 
-static const struct fetch_type *find_fetch_type(const char *type,
-						const struct fetch_type *ftbl)
+/* Fetch type information table */
+static const struct fetch_type probe_fetch_types[] = {
+	/* Special types */
+	__ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1,
+			    "__data_loc char[]"),
+	/* Basic types */
+	ASSIGN_FETCH_TYPE(u8,  u8,  0),
+	ASSIGN_FETCH_TYPE(u16, u16, 0),
+	ASSIGN_FETCH_TYPE(u32, u32, 0),
+	ASSIGN_FETCH_TYPE(u64, u64, 0),
+	ASSIGN_FETCH_TYPE(s8,  u8,  1),
+	ASSIGN_FETCH_TYPE(s16, u16, 1),
+	ASSIGN_FETCH_TYPE(s32, u32, 1),
+	ASSIGN_FETCH_TYPE(s64, u64, 1),
+	ASSIGN_FETCH_TYPE_ALIAS(x8,  u8,  u8,  0),
+	ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0),
+	ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0),
+	ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0),
+
+	ASSIGN_FETCH_TYPE_END
+};
+
+static const struct fetch_type *find_fetch_type(const char *type)
 {
 	int i;
 
@@ -95,21 +116,21 @@ static const struct fetch_type *find_fetch_type(const char *type,
 
 		switch (bs) {
 		case 8:
-			return find_fetch_type("u8", ftbl);
+			return find_fetch_type("u8");
 		case 16:
-			return find_fetch_type("u16", ftbl);
+			return find_fetch_type("u16");
 		case 32:
-			return find_fetch_type("u32", ftbl);
+			return find_fetch_type("u32");
 		case 64:
-			return find_fetch_type("u64", ftbl);
+			return find_fetch_type("u64");
 		default:
 			goto fail;
 		}
 	}
 
-	for (i = 0; ftbl[i].name; i++) {
-		if (strcmp(type, ftbl[i].name) == 0)
-			return &ftbl[i];
+	for (i = 0; probe_fetch_types[i].name; i++) {
+		if (strcmp(type, probe_fetch_types[i].name) == 0)
+			return &probe_fetch_types[i];
 	}
 
 fail:
@@ -176,8 +197,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
 static int
 parse_probe_arg(char *arg, const struct fetch_type *type,
 		struct fetch_insn **pcode, struct fetch_insn *end,
-		bool is_return, bool is_kprobe,
-		const struct fetch_type *ftbl)
+		bool is_return, bool is_kprobe)
 {
 	struct fetch_insn *code = *pcode;
 	unsigned long param;
@@ -259,12 +279,11 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 		tmp = strrchr(arg, ')');
 
 		if (tmp) {
-			const struct fetch_type *t2;
+			const struct fetch_type *t2 = find_fetch_type(NULL);
 
-			t2 = find_fetch_type(NULL, ftbl);
 			*tmp = '\0';
 			ret = parse_probe_arg(arg, t2, &code, end, is_return,
-					      is_kprobe, ftbl);
+					      is_kprobe);
 			if (ret)
 				break;
 			if (code->op == FETCH_OP_COMM)
@@ -324,8 +343,7 @@ static int __parse_bitfield_probe_arg(const char *bf,
 
 /* String length checking wrapper */
 int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
-		struct probe_arg *parg, bool is_return, bool is_kprobe,
-		const struct fetch_type *ftbl)
+		struct probe_arg *parg, bool is_return, bool is_kprobe)
 {
 	struct fetch_insn *code, *tmp = NULL;
 	const char *t;
@@ -351,7 +369,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 	 */
 	if (!t && strcmp(arg, "$comm") == 0)
 		t = "string";
-	parg->type = find_fetch_type(t, ftbl);
+	parg->type = find_fetch_type(t);
 	if (!parg->type) {
 		pr_info("Unsupported type: %s\n", t);
 		return -EINVAL;
@@ -365,7 +383,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 	code[FETCH_INSN_MAX - 1].op = FETCH_OP_END;
 
 	ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1],
-			      is_return, is_kprobe, ftbl);
+			      is_return, is_kprobe);
 	if (ret)
 		goto fail;
 
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 9d9de7535d06..89d853ef5174 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -196,9 +196,6 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(string);
 
 #define ASSIGN_FETCH_TYPE_END {}
 
-#define FETCH_TYPE_STRING      0
-#define FETCH_TYPE_STRSIZE     1
-
 #ifdef CONFIG_KPROBE_EVENTS
 bool trace_kprobe_on_func_entry(struct trace_event_call *call);
 bool trace_kprobe_error_injectable(struct trace_event_call *call);
@@ -273,8 +270,7 @@ find_event_file_link(struct trace_probe *tp, struct trace_event_file *file)
 }
 
 extern int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
-		   struct probe_arg *parg, bool is_return, bool is_kprobe,
-		   const struct fetch_type *ftbl);
+		   struct probe_arg *parg, bool is_return, bool is_kprobe);
 
 extern int traceprobe_conflict_field_name(const char *name,
 			       struct probe_arg *args, int narg);
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index ff408edd3a68..e56925e77781 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -171,30 +171,6 @@ static unsigned long translate_user_vaddr(unsigned long file_offset)
 	return base_addr + file_offset;
 }
 
-/* Fetch type information table */
-static const struct fetch_type uprobes_fetch_type_table[] = {
-	/* Special types */
-	[FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string,
-					sizeof(u32), 1, "__data_loc char[]"),
-	[FETCH_TYPE_STRSIZE] = __ASSIGN_FETCH_TYPE("string_size", u32,
-					string_size, sizeof(u32), 0, "u32"),
-	/* Basic types */
-	ASSIGN_FETCH_TYPE(u8,  u8,  0),
-	ASSIGN_FETCH_TYPE(u16, u16, 0),
-	ASSIGN_FETCH_TYPE(u32, u32, 0),
-	ASSIGN_FETCH_TYPE(u64, u64, 0),
-	ASSIGN_FETCH_TYPE(s8,  u8,  1),
-	ASSIGN_FETCH_TYPE(s16, u16, 1),
-	ASSIGN_FETCH_TYPE(s32, u32, 1),
-	ASSIGN_FETCH_TYPE(s64, u64, 1),
-	ASSIGN_FETCH_TYPE_ALIAS(x8,  u8,  u8,  0),
-	ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0),
-	ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0),
-	ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0),
-
-	ASSIGN_FETCH_TYPE_END
-};
-
 /* Note that we don't verify it, since the code does not come from user space */
 static int
 process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
@@ -583,8 +559,7 @@ static int create_trace_uprobe(int argc, char **argv)
 
 		/* Parse fetch argument */
 		ret = traceprobe_parse_probe_arg(arg, &tu->tp.size, parg,
-						 is_return, false,
-						 uprobes_fetch_type_table);
+						 is_return, false);
 		if (ret) {
 			pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
 			goto error;

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 06/16] tracing: probeevent: Return consumed bytes of dynamic area
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
                   ` (5 preceding siblings ...)
  2018-04-25 12:18 ` [PATCH v7 05/16] tracing: probeevent: Unify fetch type tables mhiramat
@ 2018-04-25 12:19 ` mhiramat
  2018-04-25 12:19   ` Masami Hiramatsu
  2018-04-25 12:19 ` [PATCH v7 07/16] tracing: probeevent: Append traceprobe_ for exported function mhiramat
                   ` (12 subsequent siblings)
  19 siblings, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-04-25 12:19 UTC (permalink / raw)


Cleanup string fetching routine so that returns the consumed
bytes of dynamic area and store the string information as
data_loc format instead of data_rloc.
This simplifies the fetcharg loop.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v7:
  - Fix to return an error if failed to fetch string and
    fill zero-length data_loc in error case.
---
 kernel/trace/trace_kprobe.c     |   57 +++++++++++++++++-------------------
 kernel/trace/trace_probe.h      |   26 ++++-------------
 kernel/trace/trace_probe_tmpl.h |   54 ++++++++++++++++-------------------
 kernel/trace/trace_uprobe.c     |   61 +++++++++++++++++++--------------------
 4 files changed, 88 insertions(+), 110 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 0b73b1ee82c8..fab796d55d70 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -807,8 +807,8 @@ static const struct file_operations kprobe_profile_ops = {
 /* Kprobe specific fetch functions */
 
 /* Return the length of string -- including null terminal byte */
-static nokprobe_inline void
-fetch_store_strlen(unsigned long addr, void *dest)
+static nokprobe_inline int
+fetch_store_strlen(unsigned long addr)
 {
 	mm_segment_t old_fs;
 	int ret, len = 0;
@@ -826,47 +826,40 @@ fetch_store_strlen(unsigned long addr, void *dest)
 	pagefault_enable();
 	set_fs(old_fs);
 
-	if (ret < 0)	/* Failed to check the length */
-		*(u32 *)dest = 0;
-	else
-		*(u32 *)dest = len;
+	return (ret < 0) ? ret : len;
 }
 
 /*
  * Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max
  * length and relative data location.
  */
-static nokprobe_inline void
-fetch_store_string(unsigned long addr, void *dest)
+static nokprobe_inline int
+fetch_store_string(unsigned long addr, void *dest, void *base)
 {
-	int maxlen = get_rloc_len(*(u32 *)dest);
-	u8 *dst = get_rloc_data(dest);
+	int maxlen = get_loc_len(*(u32 *)dest);
+	u8 *dst = get_loc_data(dest, base);
 	long ret;
 
-	if (!maxlen)
-		return;
-
+	if (unlikely(!maxlen))
+		return -ENOMEM;
 	/*
 	 * Try to get string again, since the string can be changed while
 	 * probing.
 	 */
 	ret = strncpy_from_unsafe(dst, (void *)addr, maxlen);
 
-	if (ret < 0) {	/* Failed to fetch string */
-		dst[0] = '\0';
-		*(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
-	} else {
-		*(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest));
-	}
+	if (ret >= 0)
+		*(u32 *)dest = make_data_loc(ret, (void *)dst - base);
+	return ret;
 }
 
 /* Note that we don't verify it, since the code does not come from user space */
 static int
 process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
-		   bool pre)
+		   void *base)
 {
 	unsigned long val;
-	int ret;
+	int ret = 0;
 
 	/* 1st stage: get value from context */
 	switch (code->op) {
@@ -903,6 +896,13 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 	}
 
 	/* 3rd stage: store value to buffer */
+	if (unlikely(!dest)) {
+		if (code->op == FETCH_OP_ST_STRING)
+			return fetch_store_strlen(val + code->offset);
+		else
+			return -EILSEQ;
+	}
+
 	switch (code->op) {
 	case FETCH_OP_ST_RAW:
 		fetch_store_raw(val, code, dest);
@@ -911,10 +911,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 		probe_kernel_read(dest, (void *)val + code->offset, code->size);
 		break;
 	case FETCH_OP_ST_STRING:
-		if (pre)
-			fetch_store_strlen(val + code->offset, dest);
-		else
-			fetch_store_string(val + code->offset, dest);
+		ret = fetch_store_string(val + code->offset, dest, base);
 		break;
 	default:
 		return -EILSEQ;
@@ -927,7 +924,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 		code++;
 	}
 
-	return code->op == FETCH_OP_END ? 0 : -EILSEQ;
+	return code->op == FETCH_OP_END ? ret : -EILSEQ;
 }
 NOKPROBE_SYMBOL(process_fetch_insn)
 
@@ -962,7 +959,7 @@ __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs,
 
 	entry = ring_buffer_event_data(event);
 	entry->ip = (unsigned long)tk->rp.kp.addr;
-	store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize);
+	store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
 
 	event_trigger_unlock_commit_regs(trace_file, buffer, event,
 					 entry, irq_flags, pc, regs);
@@ -1011,7 +1008,7 @@ __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
 	entry = ring_buffer_event_data(event);
 	entry->func = (unsigned long)tk->rp.kp.addr;
 	entry->ret_ip = (unsigned long)ri->ret_addr;
-	store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize);
+	store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
 
 	event_trigger_unlock_commit_regs(trace_file, buffer, event,
 					 entry, irq_flags, pc, regs);
@@ -1162,7 +1159,7 @@ kprobe_perf_func(struct trace_kprobe *tk, struct pt_regs *regs)
 
 	entry->ip = (unsigned long)tk->rp.kp.addr;
 	memset(&entry[1], 0, dsize);
-	store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize);
+	store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
 	perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
 			      head, NULL);
 	return 0;
@@ -1198,7 +1195,7 @@ kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
 
 	entry->func = (unsigned long)tk->rp.kp.addr;
 	entry->ret_ip = (unsigned long)ri->ret_addr;
-	store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize);
+	store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
 	perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
 			      head, NULL);
 }
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 89d853ef5174..d1b8bd74bf56 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -66,29 +66,15 @@
 #define TP_FLAG_PROFILE		2
 #define TP_FLAG_REGISTERED	4
 
+/* data_loc: data location, compatible with u32 */
+#define make_data_loc(len, offs)	\
+	(((u32)(len) << 16) | ((u32)(offs) & 0xffff))
+#define get_loc_len(dl)		((u32)(dl) >> 16)
+#define get_loc_offs(dl)	((u32)(dl) & 0xffff)
 
-/* data_rloc: data relative location, compatible with u32 */
-#define make_data_rloc(len, roffs)	\
-	(((u32)(len) << 16) | ((u32)(roffs) & 0xffff))
-#define get_rloc_len(dl)		((u32)(dl) >> 16)
-#define get_rloc_offs(dl)		((u32)(dl) & 0xffff)
-
-/*
- * Convert data_rloc to data_loc:
- *  data_rloc stores the offset from data_rloc itself, but data_loc
- *  stores the offset from event entry.
- */
-#define convert_rloc_to_loc(dl, offs)	((u32)(dl) + (offs))
-
-static nokprobe_inline void *get_rloc_data(u32 *dl)
-{
-	return (u8 *)dl + get_rloc_offs(*dl);
-}
-
-/* For data_loc conversion */
 static nokprobe_inline void *get_loc_data(u32 *dl, void *ent)
 {
-	return (u8 *)ent + get_rloc_offs(*dl);
+	return (u8 *)ent + get_loc_offs(*dl);
 }
 
 /* Printing function type */
diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmpl.h
index c8a5272abf01..3b4aba6f84cc 100644
--- a/kernel/trace/trace_probe_tmpl.h
+++ b/kernel/trace/trace_probe_tmpl.h
@@ -48,24 +48,28 @@ fetch_apply_bitfield(struct fetch_insn *code, void *buf)
 	}
 }
 
-/* Define this for each callsite */
+/*
+ * This must be defined for each callsite.
+ * Return consumed dynamic data size (>= 0), or error (< 0).
+ * If dest is NULL, don't store result and return required dynamic data size.
+ */
 static int
 process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs,
-		   void *dest, bool pre);
+		   void *dest, void *base);
 
 /* Sum up total data length for dynamic arraies (strings) */
 static nokprobe_inline int
 __get_data_size(struct trace_probe *tp, struct pt_regs *regs)
 {
 	struct probe_arg *arg;
-	int i, ret = 0;
-	u32 len;
+	int i, len, ret = 0;
 
 	for (i = 0; i < tp->nr_args; i++) {
 		arg = tp->args + i;
 		if (unlikely(arg->dynamic)) {
-			process_fetch_insn(arg->code, regs, &len, true);
-			ret += len;
+			len = process_fetch_insn(arg->code, regs, NULL, NULL);
+			if (len > 0)
+				ret += len;
 		}
 	}
 
@@ -74,34 +78,26 @@ __get_data_size(struct trace_probe *tp, struct pt_regs *regs)
 
 /* Store the value of each argument */
 static nokprobe_inline void
-store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs,
-		 u8 *data, int maxlen)
+store_trace_args(void *data, struct trace_probe *tp, struct pt_regs *regs,
+		 int header_size, int maxlen)
 {
 	struct probe_arg *arg;
-	u32 end = tp->size;
-	u32 *dl;	/* Data (relative) location */
-	int i;
+	void *base = data - header_size;
+	void *dyndata = data + tp->size;
+	u32 *dl;	/* Data location */
+	int ret, i;
 
 	for (i = 0; i < tp->nr_args; i++) {
 		arg = tp->args + i;
-		if (unlikely(arg->dynamic)) {
-			/*
-			 * First, we set the relative location and
-			 * maximum data length to *dl
-			 */
-			dl = (u32 *)(data + arg->offset);
-			*dl = make_data_rloc(maxlen, end - arg->offset);
-			/* Then try to fetch string or dynamic array data */
-			process_fetch_insn(arg->code, regs, dl, false);
-			/* Reduce maximum length */
-			end += get_rloc_len(*dl);
-			maxlen -= get_rloc_len(*dl);
-			/* Trick here, convert data_rloc to data_loc */
-			*dl = convert_rloc_to_loc(*dl, ent_size + arg->offset);
-		} else
-			/* Just fetching data normally */
-			process_fetch_insn(arg->code, regs, data + arg->offset,
-					   false);
+		dl = data + arg->offset;
+		/* Point the dynamic data area if needed */
+		if (unlikely(arg->dynamic))
+			*dl = make_data_loc(maxlen, dyndata - base);
+		ret = process_fetch_insn(arg->code, regs, dl, base);
+		if (unlikely(ret < 0 && arg->dynamic))
+			*dl = make_data_loc(0, dyndata - base);
+		else
+			dyndata += ret;
 	}
 }
 
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index e56925e77781..9961bee490fd 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -121,43 +121,38 @@ probe_user_read(void *dest, void *src, size_t size)
  * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
  * length and relative data location.
  */
-static nokprobe_inline void
-fetch_store_string(unsigned long addr, void *dest)
+static nokprobe_inline int
+fetch_store_string(unsigned long addr, void *dest, void *base)
 {
 	long ret;
-	u32 rloc = *(u32 *)dest;
-	int maxlen  = get_rloc_len(rloc);
-	u8 *dst = get_rloc_data(dest);
+	u32 loc = *(u32 *)dest;
+	int maxlen  = get_loc_len(loc);
+	u8 *dst = get_loc_data(dest, base);
 	void __user *src = (void __force __user *) addr;
 
-	if (!maxlen)
-		return;
+	if (unlikely(!maxlen))
+		return -ENOMEM;
 
 	ret = strncpy_from_user(dst, src, maxlen);
-	if (ret == maxlen)
-		dst[--ret] = '\0';
-
-	if (ret < 0) {	/* Failed to fetch string */
-		((u8 *)get_rloc_data(dest))[0] = '\0';
-		*(u32 *)dest = make_data_rloc(0, get_rloc_offs(rloc));
-	} else {
-		*(u32 *)dest = make_data_rloc(ret, get_rloc_offs(rloc));
+	if (ret >= 0) {
+		if (ret == maxlen)
+			dst[ret - 1] = '\0';
+		*(u32 *)dest = make_data_loc(ret, (void *)dst - base);
 	}
+
+	return ret;
 }
 
 /* Return the length of string -- including null terminal byte */
-static nokprobe_inline void
-fetch_store_strlen(unsigned long addr, void *dest)
+static nokprobe_inline int
+fetch_store_strlen(unsigned long addr)
 {
 	int len;
 	void __user *vaddr = (void __force __user *) addr;
 
 	len = strnlen_user(vaddr, MAX_STRING_SIZE);
 
-	if (len == 0 || len > MAX_STRING_SIZE)  /* Failed to check length */
-		*(u32 *)dest = 0;
-	else
-		*(u32 *)dest = len;
+	return (len > MAX_STRING_SIZE) ? 0 : len;
 }
 
 static unsigned long translate_user_vaddr(unsigned long file_offset)
@@ -174,10 +169,10 @@ static unsigned long translate_user_vaddr(unsigned long file_offset)
 /* Note that we don't verify it, since the code does not come from user space */
 static int
 process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
-		   bool pre)
+		   void *base)
 {
 	unsigned long val;
-	int ret;
+	int ret = 0;
 
 	/* 1st stage: get value from context */
 	switch (code->op) {
@@ -214,18 +209,22 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 	}
 
 	/* 3rd stage: store value to buffer */
+	if (unlikely(!dest)) {
+		if (code->op == FETCH_OP_ST_STRING)
+			return fetch_store_strlen(val + code->offset);
+		else
+			return -EILSEQ;
+	}
+
 	switch (code->op) {
 	case FETCH_OP_ST_RAW:
 		fetch_store_raw(val, code, dest);
 		break;
 	case FETCH_OP_ST_MEM:
-		probe_user_read(dest, (void *)val + code->offset, code->size);
+		probe_kernel_read(dest, (void *)val + code->offset, code->size);
 		break;
 	case FETCH_OP_ST_STRING:
-		if (pre)
-			fetch_store_strlen(val + code->offset, dest);
-		else
-			fetch_store_string(val + code->offset, dest);
+		ret = fetch_store_string(val + code->offset, dest, base);
 		break;
 	default:
 		return -EILSEQ;
@@ -238,7 +237,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 		code++;
 	}
 
-	return code->op == FETCH_OP_END ? 0 : -EILSEQ;
+	return code->op == FETCH_OP_END ? ret : -EILSEQ;
 }
 NOKPROBE_SYMBOL(process_fetch_insn)
 
@@ -1229,7 +1228,7 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs)
 	esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
 
 	ucb = uprobe_buffer_get();
-	store_trace_args(esize, &tu->tp, regs, ucb->buf, dsize);
+	store_trace_args(ucb->buf, &tu->tp, regs, esize, dsize);
 
 	if (tu->tp.flags & TP_FLAG_TRACE)
 		ret |= uprobe_trace_func(tu, regs, ucb, dsize);
@@ -1264,7 +1263,7 @@ static int uretprobe_dispatcher(struct uprobe_consumer *con,
 	esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
 
 	ucb = uprobe_buffer_get();
-	store_trace_args(esize, &tu->tp, regs, ucb->buf, dsize);
+	store_trace_args(ucb->buf, &tu->tp, regs, esize, dsize);
 
 	if (tu->tp.flags & TP_FLAG_TRACE)
 		uretprobe_trace_func(tu, func, regs, ucb, dsize);

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 06/16] tracing: probeevent: Return consumed bytes of dynamic area
  2018-04-25 12:19 ` [PATCH v7 06/16] tracing: probeevent: Return consumed bytes of dynamic area mhiramat
@ 2018-04-25 12:19   ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-04-25 12:19 UTC (permalink / raw)


Cleanup string fetching routine so that returns the consumed
bytes of dynamic area and store the string information as
data_loc format instead of data_rloc.
This simplifies the fetcharg loop.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v7:
  - Fix to return an error if failed to fetch string and
    fill zero-length data_loc in error case.
---
 kernel/trace/trace_kprobe.c     |   57 +++++++++++++++++-------------------
 kernel/trace/trace_probe.h      |   26 ++++-------------
 kernel/trace/trace_probe_tmpl.h |   54 ++++++++++++++++-------------------
 kernel/trace/trace_uprobe.c     |   61 +++++++++++++++++++--------------------
 4 files changed, 88 insertions(+), 110 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 0b73b1ee82c8..fab796d55d70 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -807,8 +807,8 @@ static const struct file_operations kprobe_profile_ops = {
 /* Kprobe specific fetch functions */
 
 /* Return the length of string -- including null terminal byte */
-static nokprobe_inline void
-fetch_store_strlen(unsigned long addr, void *dest)
+static nokprobe_inline int
+fetch_store_strlen(unsigned long addr)
 {
 	mm_segment_t old_fs;
 	int ret, len = 0;
@@ -826,47 +826,40 @@ fetch_store_strlen(unsigned long addr, void *dest)
 	pagefault_enable();
 	set_fs(old_fs);
 
-	if (ret < 0)	/* Failed to check the length */
-		*(u32 *)dest = 0;
-	else
-		*(u32 *)dest = len;
+	return (ret < 0) ? ret : len;
 }
 
 /*
  * Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max
  * length and relative data location.
  */
-static nokprobe_inline void
-fetch_store_string(unsigned long addr, void *dest)
+static nokprobe_inline int
+fetch_store_string(unsigned long addr, void *dest, void *base)
 {
-	int maxlen = get_rloc_len(*(u32 *)dest);
-	u8 *dst = get_rloc_data(dest);
+	int maxlen = get_loc_len(*(u32 *)dest);
+	u8 *dst = get_loc_data(dest, base);
 	long ret;
 
-	if (!maxlen)
-		return;
-
+	if (unlikely(!maxlen))
+		return -ENOMEM;
 	/*
 	 * Try to get string again, since the string can be changed while
 	 * probing.
 	 */
 	ret = strncpy_from_unsafe(dst, (void *)addr, maxlen);
 
-	if (ret < 0) {	/* Failed to fetch string */
-		dst[0] = '\0';
-		*(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
-	} else {
-		*(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest));
-	}
+	if (ret >= 0)
+		*(u32 *)dest = make_data_loc(ret, (void *)dst - base);
+	return ret;
 }
 
 /* Note that we don't verify it, since the code does not come from user space */
 static int
 process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
-		   bool pre)
+		   void *base)
 {
 	unsigned long val;
-	int ret;
+	int ret = 0;
 
 	/* 1st stage: get value from context */
 	switch (code->op) {
@@ -903,6 +896,13 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 	}
 
 	/* 3rd stage: store value to buffer */
+	if (unlikely(!dest)) {
+		if (code->op == FETCH_OP_ST_STRING)
+			return fetch_store_strlen(val + code->offset);
+		else
+			return -EILSEQ;
+	}
+
 	switch (code->op) {
 	case FETCH_OP_ST_RAW:
 		fetch_store_raw(val, code, dest);
@@ -911,10 +911,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 		probe_kernel_read(dest, (void *)val + code->offset, code->size);
 		break;
 	case FETCH_OP_ST_STRING:
-		if (pre)
-			fetch_store_strlen(val + code->offset, dest);
-		else
-			fetch_store_string(val + code->offset, dest);
+		ret = fetch_store_string(val + code->offset, dest, base);
 		break;
 	default:
 		return -EILSEQ;
@@ -927,7 +924,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 		code++;
 	}
 
-	return code->op == FETCH_OP_END ? 0 : -EILSEQ;
+	return code->op == FETCH_OP_END ? ret : -EILSEQ;
 }
 NOKPROBE_SYMBOL(process_fetch_insn)
 
@@ -962,7 +959,7 @@ __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs,
 
 	entry = ring_buffer_event_data(event);
 	entry->ip = (unsigned long)tk->rp.kp.addr;
-	store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize);
+	store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
 
 	event_trigger_unlock_commit_regs(trace_file, buffer, event,
 					 entry, irq_flags, pc, regs);
@@ -1011,7 +1008,7 @@ __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
 	entry = ring_buffer_event_data(event);
 	entry->func = (unsigned long)tk->rp.kp.addr;
 	entry->ret_ip = (unsigned long)ri->ret_addr;
-	store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize);
+	store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
 
 	event_trigger_unlock_commit_regs(trace_file, buffer, event,
 					 entry, irq_flags, pc, regs);
@@ -1162,7 +1159,7 @@ kprobe_perf_func(struct trace_kprobe *tk, struct pt_regs *regs)
 
 	entry->ip = (unsigned long)tk->rp.kp.addr;
 	memset(&entry[1], 0, dsize);
-	store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize);
+	store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
 	perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
 			      head, NULL);
 	return 0;
@@ -1198,7 +1195,7 @@ kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
 
 	entry->func = (unsigned long)tk->rp.kp.addr;
 	entry->ret_ip = (unsigned long)ri->ret_addr;
-	store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize);
+	store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
 	perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
 			      head, NULL);
 }
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 89d853ef5174..d1b8bd74bf56 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -66,29 +66,15 @@
 #define TP_FLAG_PROFILE		2
 #define TP_FLAG_REGISTERED	4
 
+/* data_loc: data location, compatible with u32 */
+#define make_data_loc(len, offs)	\
+	(((u32)(len) << 16) | ((u32)(offs) & 0xffff))
+#define get_loc_len(dl)		((u32)(dl) >> 16)
+#define get_loc_offs(dl)	((u32)(dl) & 0xffff)
 
-/* data_rloc: data relative location, compatible with u32 */
-#define make_data_rloc(len, roffs)	\
-	(((u32)(len) << 16) | ((u32)(roffs) & 0xffff))
-#define get_rloc_len(dl)		((u32)(dl) >> 16)
-#define get_rloc_offs(dl)		((u32)(dl) & 0xffff)
-
-/*
- * Convert data_rloc to data_loc:
- *  data_rloc stores the offset from data_rloc itself, but data_loc
- *  stores the offset from event entry.
- */
-#define convert_rloc_to_loc(dl, offs)	((u32)(dl) + (offs))
-
-static nokprobe_inline void *get_rloc_data(u32 *dl)
-{
-	return (u8 *)dl + get_rloc_offs(*dl);
-}
-
-/* For data_loc conversion */
 static nokprobe_inline void *get_loc_data(u32 *dl, void *ent)
 {
-	return (u8 *)ent + get_rloc_offs(*dl);
+	return (u8 *)ent + get_loc_offs(*dl);
 }
 
 /* Printing function type */
diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmpl.h
index c8a5272abf01..3b4aba6f84cc 100644
--- a/kernel/trace/trace_probe_tmpl.h
+++ b/kernel/trace/trace_probe_tmpl.h
@@ -48,24 +48,28 @@ fetch_apply_bitfield(struct fetch_insn *code, void *buf)
 	}
 }
 
-/* Define this for each callsite */
+/*
+ * This must be defined for each callsite.
+ * Return consumed dynamic data size (>= 0), or error (< 0).
+ * If dest is NULL, don't store result and return required dynamic data size.
+ */
 static int
 process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs,
-		   void *dest, bool pre);
+		   void *dest, void *base);
 
 /* Sum up total data length for dynamic arraies (strings) */
 static nokprobe_inline int
 __get_data_size(struct trace_probe *tp, struct pt_regs *regs)
 {
 	struct probe_arg *arg;
-	int i, ret = 0;
-	u32 len;
+	int i, len, ret = 0;
 
 	for (i = 0; i < tp->nr_args; i++) {
 		arg = tp->args + i;
 		if (unlikely(arg->dynamic)) {
-			process_fetch_insn(arg->code, regs, &len, true);
-			ret += len;
+			len = process_fetch_insn(arg->code, regs, NULL, NULL);
+			if (len > 0)
+				ret += len;
 		}
 	}
 
@@ -74,34 +78,26 @@ __get_data_size(struct trace_probe *tp, struct pt_regs *regs)
 
 /* Store the value of each argument */
 static nokprobe_inline void
-store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs,
-		 u8 *data, int maxlen)
+store_trace_args(void *data, struct trace_probe *tp, struct pt_regs *regs,
+		 int header_size, int maxlen)
 {
 	struct probe_arg *arg;
-	u32 end = tp->size;
-	u32 *dl;	/* Data (relative) location */
-	int i;
+	void *base = data - header_size;
+	void *dyndata = data + tp->size;
+	u32 *dl;	/* Data location */
+	int ret, i;
 
 	for (i = 0; i < tp->nr_args; i++) {
 		arg = tp->args + i;
-		if (unlikely(arg->dynamic)) {
-			/*
-			 * First, we set the relative location and
-			 * maximum data length to *dl
-			 */
-			dl = (u32 *)(data + arg->offset);
-			*dl = make_data_rloc(maxlen, end - arg->offset);
-			/* Then try to fetch string or dynamic array data */
-			process_fetch_insn(arg->code, regs, dl, false);
-			/* Reduce maximum length */
-			end += get_rloc_len(*dl);
-			maxlen -= get_rloc_len(*dl);
-			/* Trick here, convert data_rloc to data_loc */
-			*dl = convert_rloc_to_loc(*dl, ent_size + arg->offset);
-		} else
-			/* Just fetching data normally */
-			process_fetch_insn(arg->code, regs, data + arg->offset,
-					   false);
+		dl = data + arg->offset;
+		/* Point the dynamic data area if needed */
+		if (unlikely(arg->dynamic))
+			*dl = make_data_loc(maxlen, dyndata - base);
+		ret = process_fetch_insn(arg->code, regs, dl, base);
+		if (unlikely(ret < 0 && arg->dynamic))
+			*dl = make_data_loc(0, dyndata - base);
+		else
+			dyndata += ret;
 	}
 }
 
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index e56925e77781..9961bee490fd 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -121,43 +121,38 @@ probe_user_read(void *dest, void *src, size_t size)
  * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
  * length and relative data location.
  */
-static nokprobe_inline void
-fetch_store_string(unsigned long addr, void *dest)
+static nokprobe_inline int
+fetch_store_string(unsigned long addr, void *dest, void *base)
 {
 	long ret;
-	u32 rloc = *(u32 *)dest;
-	int maxlen  = get_rloc_len(rloc);
-	u8 *dst = get_rloc_data(dest);
+	u32 loc = *(u32 *)dest;
+	int maxlen  = get_loc_len(loc);
+	u8 *dst = get_loc_data(dest, base);
 	void __user *src = (void __force __user *) addr;
 
-	if (!maxlen)
-		return;
+	if (unlikely(!maxlen))
+		return -ENOMEM;
 
 	ret = strncpy_from_user(dst, src, maxlen);
-	if (ret == maxlen)
-		dst[--ret] = '\0';
-
-	if (ret < 0) {	/* Failed to fetch string */
-		((u8 *)get_rloc_data(dest))[0] = '\0';
-		*(u32 *)dest = make_data_rloc(0, get_rloc_offs(rloc));
-	} else {
-		*(u32 *)dest = make_data_rloc(ret, get_rloc_offs(rloc));
+	if (ret >= 0) {
+		if (ret == maxlen)
+			dst[ret - 1] = '\0';
+		*(u32 *)dest = make_data_loc(ret, (void *)dst - base);
 	}
+
+	return ret;
 }
 
 /* Return the length of string -- including null terminal byte */
-static nokprobe_inline void
-fetch_store_strlen(unsigned long addr, void *dest)
+static nokprobe_inline int
+fetch_store_strlen(unsigned long addr)
 {
 	int len;
 	void __user *vaddr = (void __force __user *) addr;
 
 	len = strnlen_user(vaddr, MAX_STRING_SIZE);
 
-	if (len == 0 || len > MAX_STRING_SIZE)  /* Failed to check length */
-		*(u32 *)dest = 0;
-	else
-		*(u32 *)dest = len;
+	return (len > MAX_STRING_SIZE) ? 0 : len;
 }
 
 static unsigned long translate_user_vaddr(unsigned long file_offset)
@@ -174,10 +169,10 @@ static unsigned long translate_user_vaddr(unsigned long file_offset)
 /* Note that we don't verify it, since the code does not come from user space */
 static int
 process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
-		   bool pre)
+		   void *base)
 {
 	unsigned long val;
-	int ret;
+	int ret = 0;
 
 	/* 1st stage: get value from context */
 	switch (code->op) {
@@ -214,18 +209,22 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 	}
 
 	/* 3rd stage: store value to buffer */
+	if (unlikely(!dest)) {
+		if (code->op == FETCH_OP_ST_STRING)
+			return fetch_store_strlen(val + code->offset);
+		else
+			return -EILSEQ;
+	}
+
 	switch (code->op) {
 	case FETCH_OP_ST_RAW:
 		fetch_store_raw(val, code, dest);
 		break;
 	case FETCH_OP_ST_MEM:
-		probe_user_read(dest, (void *)val + code->offset, code->size);
+		probe_kernel_read(dest, (void *)val + code->offset, code->size);
 		break;
 	case FETCH_OP_ST_STRING:
-		if (pre)
-			fetch_store_strlen(val + code->offset, dest);
-		else
-			fetch_store_string(val + code->offset, dest);
+		ret = fetch_store_string(val + code->offset, dest, base);
 		break;
 	default:
 		return -EILSEQ;
@@ -238,7 +237,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 		code++;
 	}
 
-	return code->op == FETCH_OP_END ? 0 : -EILSEQ;
+	return code->op == FETCH_OP_END ? ret : -EILSEQ;
 }
 NOKPROBE_SYMBOL(process_fetch_insn)
 
@@ -1229,7 +1228,7 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs)
 	esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
 
 	ucb = uprobe_buffer_get();
-	store_trace_args(esize, &tu->tp, regs, ucb->buf, dsize);
+	store_trace_args(ucb->buf, &tu->tp, regs, esize, dsize);
 
 	if (tu->tp.flags & TP_FLAG_TRACE)
 		ret |= uprobe_trace_func(tu, regs, ucb, dsize);
@@ -1264,7 +1263,7 @@ static int uretprobe_dispatcher(struct uprobe_consumer *con,
 	esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
 
 	ucb = uprobe_buffer_get();
-	store_trace_args(esize, &tu->tp, regs, ucb->buf, dsize);
+	store_trace_args(ucb->buf, &tu->tp, regs, esize, dsize);
 
 	if (tu->tp.flags & TP_FLAG_TRACE)
 		uretprobe_trace_func(tu, func, regs, ucb, dsize);

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 07/16] tracing: probeevent: Append traceprobe_ for exported function
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
                   ` (6 preceding siblings ...)
  2018-04-25 12:19 ` [PATCH v7 06/16] tracing: probeevent: Return consumed bytes of dynamic area mhiramat
@ 2018-04-25 12:19 ` mhiramat
  2018-04-25 12:19   ` Masami Hiramatsu
  2018-04-25 12:19 ` [PATCH v7 08/16] tracing: probeevent: Unify fetch_insn processing common part mhiramat
                   ` (11 subsequent siblings)
  19 siblings, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-04-25 12:19 UTC (permalink / raw)


Append traceprobe_ for exported function set_print_fmt() as
same as other functions.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 kernel/trace/trace_kprobe.c |    4 ++--
 kernel/trace/trace_probe.c  |    2 +-
 kernel/trace/trace_probe.h  |    2 +-
 kernel/trace/trace_uprobe.c |    4 ++--
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index fab796d55d70..4102020411c8 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -1301,7 +1301,7 @@ static int register_kprobe_event(struct trace_kprobe *tk)
 
 	init_trace_event_call(tk, call);
 
-	if (set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0)
+	if (traceprobe_set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0)
 		return -ENOMEM;
 	ret = register_trace_event(&call->event);
 	if (!ret) {
@@ -1358,7 +1358,7 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
 
 	init_trace_event_call(tk, &tk->tp.call);
 
-	if (set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0) {
+	if (traceprobe_set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0) {
 		ret = -ENOMEM;
 		goto error;
 	}
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index ed3766fb290d..fff3ccfcdbb6 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -502,7 +502,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
 	return pos;
 }
 
-int set_print_fmt(struct trace_probe *tp, bool is_return)
+int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return)
 {
 	int len;
 	char *print_fmt;
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index d1b8bd74bf56..3bc43c1ce628 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -266,7 +266,7 @@ extern void traceprobe_free_probe_arg(struct probe_arg *arg);
 
 extern int traceprobe_split_symbol_offset(char *symbol, long *offset);
 
-extern int set_print_fmt(struct trace_probe *tp, bool is_return);
+extern int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return);
 
 #ifdef CONFIG_PERF_EVENTS
 extern struct trace_event_call *
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 9961bee490fd..173588ffe55a 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -1299,7 +1299,7 @@ static int register_uprobe_event(struct trace_uprobe *tu)
 
 	init_trace_event_call(tu, call);
 
-	if (set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0)
+	if (traceprobe_set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0)
 		return -ENOMEM;
 
 	ret = register_trace_event(&call->event);
@@ -1373,7 +1373,7 @@ create_local_trace_uprobe(char *name, unsigned long offs, bool is_return)
 	tu->filename = kstrdup(name, GFP_KERNEL);
 	init_trace_event_call(tu, &tu->tp.call);
 
-	if (set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0) {
+	if (traceprobe_set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0) {
 		ret = -ENOMEM;
 		goto error;
 	}

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 07/16] tracing: probeevent: Append traceprobe_ for exported function
  2018-04-25 12:19 ` [PATCH v7 07/16] tracing: probeevent: Append traceprobe_ for exported function mhiramat
@ 2018-04-25 12:19   ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-04-25 12:19 UTC (permalink / raw)


Append traceprobe_ for exported function set_print_fmt() as
same as other functions.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 kernel/trace/trace_kprobe.c |    4 ++--
 kernel/trace/trace_probe.c  |    2 +-
 kernel/trace/trace_probe.h  |    2 +-
 kernel/trace/trace_uprobe.c |    4 ++--
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index fab796d55d70..4102020411c8 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -1301,7 +1301,7 @@ static int register_kprobe_event(struct trace_kprobe *tk)
 
 	init_trace_event_call(tk, call);
 
-	if (set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0)
+	if (traceprobe_set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0)
 		return -ENOMEM;
 	ret = register_trace_event(&call->event);
 	if (!ret) {
@@ -1358,7 +1358,7 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
 
 	init_trace_event_call(tk, &tk->tp.call);
 
-	if (set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0) {
+	if (traceprobe_set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0) {
 		ret = -ENOMEM;
 		goto error;
 	}
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index ed3766fb290d..fff3ccfcdbb6 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -502,7 +502,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
 	return pos;
 }
 
-int set_print_fmt(struct trace_probe *tp, bool is_return)
+int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return)
 {
 	int len;
 	char *print_fmt;
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index d1b8bd74bf56..3bc43c1ce628 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -266,7 +266,7 @@ extern void traceprobe_free_probe_arg(struct probe_arg *arg);
 
 extern int traceprobe_split_symbol_offset(char *symbol, long *offset);
 
-extern int set_print_fmt(struct trace_probe *tp, bool is_return);
+extern int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return);
 
 #ifdef CONFIG_PERF_EVENTS
 extern struct trace_event_call *
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 9961bee490fd..173588ffe55a 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -1299,7 +1299,7 @@ static int register_uprobe_event(struct trace_uprobe *tu)
 
 	init_trace_event_call(tu, call);
 
-	if (set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0)
+	if (traceprobe_set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0)
 		return -ENOMEM;
 
 	ret = register_trace_event(&call->event);
@@ -1373,7 +1373,7 @@ create_local_trace_uprobe(char *name, unsigned long offs, bool is_return)
 	tu->filename = kstrdup(name, GFP_KERNEL);
 	init_trace_event_call(tu, &tu->tp.call);
 
-	if (set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0) {
+	if (traceprobe_set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0) {
 		ret = -ENOMEM;
 		goto error;
 	}

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 08/16] tracing: probeevent: Unify fetch_insn processing common part
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
                   ` (7 preceding siblings ...)
  2018-04-25 12:19 ` [PATCH v7 07/16] tracing: probeevent: Append traceprobe_ for exported function mhiramat
@ 2018-04-25 12:19 ` mhiramat
  2018-04-25 12:19   ` Masami Hiramatsu
  2018-04-25 12:20 ` [PATCH v7 09/16] tracing: probeevent: Add symbol type mhiramat
                   ` (10 subsequent siblings)
  19 siblings, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-04-25 12:19 UTC (permalink / raw)


Unify the fetch_insn bottom process (from stage 2: dereference
indirect data) from kprobe and uprobe events, since those are
mostly same.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 kernel/trace/trace_kprobe.c     |   47 +++++----------------------------
 kernel/trace/trace_probe_tmpl.h |   55 ++++++++++++++++++++++++++++++++++++++-
 kernel/trace/trace_uprobe.c     |   43 +-----------------------------
 3 files changed, 63 insertions(+), 82 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 4102020411c8..673d4b06edd4 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -853,13 +853,18 @@ fetch_store_string(unsigned long addr, void *dest, void *base)
 	return ret;
 }
 
+static nokprobe_inline int
+probe_mem_read(void *dest, void *src, size_t size)
+{
+	return probe_kernel_read(dest, src, size);
+}
+
 /* Note that we don't verify it, since the code does not come from user space */
 static int
 process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 		   void *base)
 {
 	unsigned long val;
-	int ret = 0;
 
 	/* 1st stage: get value from context */
 	switch (code->op) {
@@ -886,45 +891,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 	}
 	code++;
 
-	/* 2nd stage: dereference memory if needed */
-	while (code->op == FETCH_OP_DEREF) {
-		ret = probe_kernel_read(&val, (void *)val + code->offset,
-					sizeof(val));
-		if (ret)
-			return ret;
-		code++;
-	}
-
-	/* 3rd stage: store value to buffer */
-	if (unlikely(!dest)) {
-		if (code->op == FETCH_OP_ST_STRING)
-			return fetch_store_strlen(val + code->offset);
-		else
-			return -EILSEQ;
-	}
-
-	switch (code->op) {
-	case FETCH_OP_ST_RAW:
-		fetch_store_raw(val, code, dest);
-		break;
-	case FETCH_OP_ST_MEM:
-		probe_kernel_read(dest, (void *)val + code->offset, code->size);
-		break;
-	case FETCH_OP_ST_STRING:
-		ret = fetch_store_string(val + code->offset, dest, base);
-		break;
-	default:
-		return -EILSEQ;
-	}
-	code++;
-
-	/* 4th stage: modify stored value if needed */
-	if (code->op == FETCH_OP_MOD_BF) {
-		fetch_apply_bitfield(code, dest);
-		code++;
-	}
-
-	return code->op == FETCH_OP_END ? ret : -EILSEQ;
+	return process_fetch_insn_bottom(code, val, dest, base);
 }
 NOKPROBE_SYMBOL(process_fetch_insn)
 
diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmpl.h
index 3b4aba6f84cc..b4075f3e3a29 100644
--- a/kernel/trace/trace_probe_tmpl.h
+++ b/kernel/trace/trace_probe_tmpl.h
@@ -49,13 +49,66 @@ fetch_apply_bitfield(struct fetch_insn *code, void *buf)
 }
 
 /*
- * This must be defined for each callsite.
+ * These functions must be defined for each callsite.
  * Return consumed dynamic data size (>= 0), or error (< 0).
  * If dest is NULL, don't store result and return required dynamic data size.
  */
 static int
 process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs,
 		   void *dest, void *base);
+static nokprobe_inline int fetch_store_strlen(unsigned long addr);
+static nokprobe_inline int
+fetch_store_string(unsigned long addr, void *dest, void *base);
+static nokprobe_inline int
+probe_mem_read(void *dest, void *src, size_t size);
+
+/* From the 2nd stage, routine is same */
+static nokprobe_inline int
+process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
+			   void *dest, void *base)
+{
+	int ret = 0;
+
+	/* 2nd stage: dereference memory if needed */
+	while (code->op == FETCH_OP_DEREF) {
+		ret = probe_mem_read(&val, (void *)val + code->offset,
+					sizeof(val));
+		if (ret)
+			return ret;
+		code++;
+	}
+
+	/* 3rd stage: store value to buffer */
+	if (unlikely(!dest)) {
+		if (code->op == FETCH_OP_ST_STRING)
+			return fetch_store_strlen(val + code->offset);
+		else
+			return -EILSEQ;
+	}
+
+	switch (code->op) {
+	case FETCH_OP_ST_RAW:
+		fetch_store_raw(val, code, dest);
+		break;
+	case FETCH_OP_ST_MEM:
+		probe_mem_read(dest, (void *)val + code->offset, code->size);
+		break;
+	case FETCH_OP_ST_STRING:
+		ret = fetch_store_string(val + code->offset, dest, base);
+		break;
+	default:
+		return -EILSEQ;
+	}
+	code++;
+
+	/* 4th stage: modify stored value if needed */
+	if (code->op == FETCH_OP_MOD_BF) {
+		fetch_apply_bitfield(code, dest);
+		code++;
+	}
+
+	return code->op == FETCH_OP_END ? ret : -EILSEQ;
+}
 
 /* Sum up total data length for dynamic arraies (strings) */
 static nokprobe_inline int
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 173588ffe55a..2cf8faeb5b72 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -111,7 +111,7 @@ static unsigned long get_user_stack_nth(struct pt_regs *regs, unsigned int n)
  * Uprobes-specific fetch functions
  */
 static nokprobe_inline int
-probe_user_read(void *dest, void *src, size_t size)
+probe_mem_read(void *dest, void *src, size_t size)
 {
 	void __user *vaddr = (void __force __user *)src;
 
@@ -172,7 +172,6 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 		   void *base)
 {
 	unsigned long val;
-	int ret = 0;
 
 	/* 1st stage: get value from context */
 	switch (code->op) {
@@ -199,45 +198,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 	}
 	code++;
 
-	/* 2nd stage: dereference memory if needed */
-	while (code->op == FETCH_OP_DEREF) {
-		ret = probe_user_read(&val, (void *)val + code->offset,
-				      sizeof(val));
-		if (ret)
-			return ret;
-		code++;
-	}
-
-	/* 3rd stage: store value to buffer */
-	if (unlikely(!dest)) {
-		if (code->op == FETCH_OP_ST_STRING)
-			return fetch_store_strlen(val + code->offset);
-		else
-			return -EILSEQ;
-	}
-
-	switch (code->op) {
-	case FETCH_OP_ST_RAW:
-		fetch_store_raw(val, code, dest);
-		break;
-	case FETCH_OP_ST_MEM:
-		probe_kernel_read(dest, (void *)val + code->offset, code->size);
-		break;
-	case FETCH_OP_ST_STRING:
-		ret = fetch_store_string(val + code->offset, dest, base);
-		break;
-	default:
-		return -EILSEQ;
-	}
-	code++;
-
-	/* 4th stage: modify stored value if needed */
-	if (code->op == FETCH_OP_MOD_BF) {
-		fetch_apply_bitfield(code, dest);
-		code++;
-	}
-
-	return code->op == FETCH_OP_END ? ret : -EILSEQ;
+	return process_fetch_insn_bottom(code, val, dest, base);
 }
 NOKPROBE_SYMBOL(process_fetch_insn)
 

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 08/16] tracing: probeevent: Unify fetch_insn processing common part
  2018-04-25 12:19 ` [PATCH v7 08/16] tracing: probeevent: Unify fetch_insn processing common part mhiramat
@ 2018-04-25 12:19   ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-04-25 12:19 UTC (permalink / raw)


Unify the fetch_insn bottom process (from stage 2: dereference
indirect data) from kprobe and uprobe events, since those are
mostly same.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 kernel/trace/trace_kprobe.c     |   47 +++++----------------------------
 kernel/trace/trace_probe_tmpl.h |   55 ++++++++++++++++++++++++++++++++++++++-
 kernel/trace/trace_uprobe.c     |   43 +-----------------------------
 3 files changed, 63 insertions(+), 82 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 4102020411c8..673d4b06edd4 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -853,13 +853,18 @@ fetch_store_string(unsigned long addr, void *dest, void *base)
 	return ret;
 }
 
+static nokprobe_inline int
+probe_mem_read(void *dest, void *src, size_t size)
+{
+	return probe_kernel_read(dest, src, size);
+}
+
 /* Note that we don't verify it, since the code does not come from user space */
 static int
 process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 		   void *base)
 {
 	unsigned long val;
-	int ret = 0;
 
 	/* 1st stage: get value from context */
 	switch (code->op) {
@@ -886,45 +891,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 	}
 	code++;
 
-	/* 2nd stage: dereference memory if needed */
-	while (code->op == FETCH_OP_DEREF) {
-		ret = probe_kernel_read(&val, (void *)val + code->offset,
-					sizeof(val));
-		if (ret)
-			return ret;
-		code++;
-	}
-
-	/* 3rd stage: store value to buffer */
-	if (unlikely(!dest)) {
-		if (code->op == FETCH_OP_ST_STRING)
-			return fetch_store_strlen(val + code->offset);
-		else
-			return -EILSEQ;
-	}
-
-	switch (code->op) {
-	case FETCH_OP_ST_RAW:
-		fetch_store_raw(val, code, dest);
-		break;
-	case FETCH_OP_ST_MEM:
-		probe_kernel_read(dest, (void *)val + code->offset, code->size);
-		break;
-	case FETCH_OP_ST_STRING:
-		ret = fetch_store_string(val + code->offset, dest, base);
-		break;
-	default:
-		return -EILSEQ;
-	}
-	code++;
-
-	/* 4th stage: modify stored value if needed */
-	if (code->op == FETCH_OP_MOD_BF) {
-		fetch_apply_bitfield(code, dest);
-		code++;
-	}
-
-	return code->op == FETCH_OP_END ? ret : -EILSEQ;
+	return process_fetch_insn_bottom(code, val, dest, base);
 }
 NOKPROBE_SYMBOL(process_fetch_insn)
 
diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmpl.h
index 3b4aba6f84cc..b4075f3e3a29 100644
--- a/kernel/trace/trace_probe_tmpl.h
+++ b/kernel/trace/trace_probe_tmpl.h
@@ -49,13 +49,66 @@ fetch_apply_bitfield(struct fetch_insn *code, void *buf)
 }
 
 /*
- * This must be defined for each callsite.
+ * These functions must be defined for each callsite.
  * Return consumed dynamic data size (>= 0), or error (< 0).
  * If dest is NULL, don't store result and return required dynamic data size.
  */
 static int
 process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs,
 		   void *dest, void *base);
+static nokprobe_inline int fetch_store_strlen(unsigned long addr);
+static nokprobe_inline int
+fetch_store_string(unsigned long addr, void *dest, void *base);
+static nokprobe_inline int
+probe_mem_read(void *dest, void *src, size_t size);
+
+/* From the 2nd stage, routine is same */
+static nokprobe_inline int
+process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
+			   void *dest, void *base)
+{
+	int ret = 0;
+
+	/* 2nd stage: dereference memory if needed */
+	while (code->op == FETCH_OP_DEREF) {
+		ret = probe_mem_read(&val, (void *)val + code->offset,
+					sizeof(val));
+		if (ret)
+			return ret;
+		code++;
+	}
+
+	/* 3rd stage: store value to buffer */
+	if (unlikely(!dest)) {
+		if (code->op == FETCH_OP_ST_STRING)
+			return fetch_store_strlen(val + code->offset);
+		else
+			return -EILSEQ;
+	}
+
+	switch (code->op) {
+	case FETCH_OP_ST_RAW:
+		fetch_store_raw(val, code, dest);
+		break;
+	case FETCH_OP_ST_MEM:
+		probe_mem_read(dest, (void *)val + code->offset, code->size);
+		break;
+	case FETCH_OP_ST_STRING:
+		ret = fetch_store_string(val + code->offset, dest, base);
+		break;
+	default:
+		return -EILSEQ;
+	}
+	code++;
+
+	/* 4th stage: modify stored value if needed */
+	if (code->op == FETCH_OP_MOD_BF) {
+		fetch_apply_bitfield(code, dest);
+		code++;
+	}
+
+	return code->op == FETCH_OP_END ? ret : -EILSEQ;
+}
 
 /* Sum up total data length for dynamic arraies (strings) */
 static nokprobe_inline int
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 173588ffe55a..2cf8faeb5b72 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -111,7 +111,7 @@ static unsigned long get_user_stack_nth(struct pt_regs *regs, unsigned int n)
  * Uprobes-specific fetch functions
  */
 static nokprobe_inline int
-probe_user_read(void *dest, void *src, size_t size)
+probe_mem_read(void *dest, void *src, size_t size)
 {
 	void __user *vaddr = (void __force __user *)src;
 
@@ -172,7 +172,6 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 		   void *base)
 {
 	unsigned long val;
-	int ret = 0;
 
 	/* 1st stage: get value from context */
 	switch (code->op) {
@@ -199,45 +198,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 	}
 	code++;
 
-	/* 2nd stage: dereference memory if needed */
-	while (code->op == FETCH_OP_DEREF) {
-		ret = probe_user_read(&val, (void *)val + code->offset,
-				      sizeof(val));
-		if (ret)
-			return ret;
-		code++;
-	}
-
-	/* 3rd stage: store value to buffer */
-	if (unlikely(!dest)) {
-		if (code->op == FETCH_OP_ST_STRING)
-			return fetch_store_strlen(val + code->offset);
-		else
-			return -EILSEQ;
-	}
-
-	switch (code->op) {
-	case FETCH_OP_ST_RAW:
-		fetch_store_raw(val, code, dest);
-		break;
-	case FETCH_OP_ST_MEM:
-		probe_kernel_read(dest, (void *)val + code->offset, code->size);
-		break;
-	case FETCH_OP_ST_STRING:
-		ret = fetch_store_string(val + code->offset, dest, base);
-		break;
-	default:
-		return -EILSEQ;
-	}
-	code++;
-
-	/* 4th stage: modify stored value if needed */
-	if (code->op == FETCH_OP_MOD_BF) {
-		fetch_apply_bitfield(code, dest);
-		code++;
-	}
-
-	return code->op == FETCH_OP_END ? ret : -EILSEQ;
+	return process_fetch_insn_bottom(code, val, dest, base);
 }
 NOKPROBE_SYMBOL(process_fetch_insn)
 

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 09/16] tracing: probeevent: Add symbol type
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
                   ` (8 preceding siblings ...)
  2018-04-25 12:19 ` [PATCH v7 08/16] tracing: probeevent: Unify fetch_insn processing common part mhiramat
@ 2018-04-25 12:20 ` mhiramat
  2018-04-25 12:20   ` Masami Hiramatsu
  2018-04-25 12:20 ` [PATCH v7 10/16] x86: ptrace: Add function argument access API mhiramat
                   ` (9 subsequent siblings)
  19 siblings, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-04-25 12:20 UTC (permalink / raw)


Add "symbol" type to probeevent, which is an alias of u32 or u64
(depends on BITS_PER_LONG). This shows the result value in
symbol+offset style. This type is only available with kprobe
events.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v2:
  - Add symbol type to README file.
---
 Documentation/trace/kprobetrace.rst |    2 ++
 kernel/trace/trace.c                |    2 +-
 kernel/trace/trace_probe.c          |    8 ++++++++
 kernel/trace/trace_probe.h          |   12 +++++++++---
 4 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/Documentation/trace/kprobetrace.rst b/Documentation/trace/kprobetrace.rst
index 3e0f971b12de..c920c9be221a 100644
--- a/Documentation/trace/kprobetrace.rst
+++ b/Documentation/trace/kprobetrace.rst
@@ -72,6 +72,8 @@ offset, and container-size (usually 32). The syntax is::
 
  b<bit-width>@<bit-offset>/<container-size>
 
+Symbol type('symbol') is an alias of u32 or u64 type (depends on BITS_PER_LONG)
+which shows given pointer in "symbol+offset" style.
 For $comm, the default type is "string"; any other type is invalid.
 
 
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index dfbcf9ee1447..4812ae046f43 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4621,7 +4621,7 @@ static const char readme_msg[] =
 	"\t     args: <name>=fetcharg[:type]\n"
 	"\t fetcharg: %<register>, @<address>, @<symbol>[+|-<offset>],\n"
 	"\t           $stack<index>, $stack, $retval, $comm\n"
-	"\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string,\n"
+	"\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
 	"\t           b<bit-width>@<bit-offset>/<container-size>\n"
 #endif
 	"  events/\t\t- Directory containing all trace event subsystems:\n"
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index fff3ccfcdbb6..e2a31087f1f8 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -58,6 +58,13 @@ DEFINE_BASIC_PRINT_TYPE_FUNC(x16, u16, "0x%x")
 DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x")
 DEFINE_BASIC_PRINT_TYPE_FUNC(x64, u64, "0x%Lx")
 
+int PRINT_TYPE_FUNC_NAME(symbol)(struct trace_seq *s, void *data, void *ent)
+{
+	trace_seq_printf(s, "%pS", (void *)*(unsigned long *)data);
+	return !trace_seq_has_overflowed(s);
+}
+const char PRINT_TYPE_FMT_NAME(symbol)[] = "%pS";
+
 /* Print type function for string type */
 int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent)
 {
@@ -91,6 +98,7 @@ static const struct fetch_type probe_fetch_types[] = {
 	ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0),
 	ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0),
 	ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0),
+	ASSIGN_FETCH_TYPE_ALIAS(symbol, ADDR_FETCH_TYPE, ADDR_FETCH_TYPE, 0),
 
 	ASSIGN_FETCH_TYPE_END
 };
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 3bc43c1ce628..ef477bd8468a 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -157,6 +157,7 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(x32);
 DECLARE_BASIC_PRINT_TYPE_FUNC(x64);
 
 DECLARE_BASIC_PRINT_TYPE_FUNC(string);
+DECLARE_BASIC_PRINT_TYPE_FUNC(symbol);
 
 /* Default (unsigned long) fetch type */
 #define __DEFAULT_FETCH_TYPE(t) x##t
@@ -164,6 +165,10 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(string);
 #define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG)
 #define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE)
 
+#define __ADDR_FETCH_TYPE(t) u##t
+#define _ADDR_FETCH_TYPE(t) __ADDR_FETCH_TYPE(t)
+#define ADDR_FETCH_TYPE _ADDR_FETCH_TYPE(BITS_PER_LONG)
+
 #define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype)	\
 	{.name = _name,				\
 	 .size = _size,					\
@@ -172,13 +177,14 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(string);
 	 .fmt = PRINT_TYPE_FMT_NAME(ptype),		\
 	 .fmttype = _fmttype,				\
 	}
-
+#define _ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype)	\
+	__ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, #_fmttype)
 #define ASSIGN_FETCH_TYPE(ptype, ftype, sign)			\
-	__ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, #ptype)
+	_ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, ptype)
 
 /* If ptype is an alias of atype, use this macro (show atype in format) */
 #define ASSIGN_FETCH_TYPE_ALIAS(ptype, atype, ftype, sign)		\
-	__ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, #atype)
+	_ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, atype)
 
 #define ASSIGN_FETCH_TYPE_END {}
 

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 09/16] tracing: probeevent: Add symbol type
  2018-04-25 12:20 ` [PATCH v7 09/16] tracing: probeevent: Add symbol type mhiramat
@ 2018-04-25 12:20   ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-04-25 12:20 UTC (permalink / raw)


Add "symbol" type to probeevent, which is an alias of u32 or u64
(depends on BITS_PER_LONG). This shows the result value in
symbol+offset style. This type is only available with kprobe
events.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v2:
  - Add symbol type to README file.
---
 Documentation/trace/kprobetrace.rst |    2 ++
 kernel/trace/trace.c                |    2 +-
 kernel/trace/trace_probe.c          |    8 ++++++++
 kernel/trace/trace_probe.h          |   12 +++++++++---
 4 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/Documentation/trace/kprobetrace.rst b/Documentation/trace/kprobetrace.rst
index 3e0f971b12de..c920c9be221a 100644
--- a/Documentation/trace/kprobetrace.rst
+++ b/Documentation/trace/kprobetrace.rst
@@ -72,6 +72,8 @@ offset, and container-size (usually 32). The syntax is::
 
  b<bit-width>@<bit-offset>/<container-size>
 
+Symbol type('symbol') is an alias of u32 or u64 type (depends on BITS_PER_LONG)
+which shows given pointer in "symbol+offset" style.
 For $comm, the default type is "string"; any other type is invalid.
 
 
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index dfbcf9ee1447..4812ae046f43 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4621,7 +4621,7 @@ static const char readme_msg[] =
 	"\t     args: <name>=fetcharg[:type]\n"
 	"\t fetcharg: %<register>, @<address>, @<symbol>[+|-<offset>],\n"
 	"\t           $stack<index>, $stack, $retval, $comm\n"
-	"\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string,\n"
+	"\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
 	"\t           b<bit-width>@<bit-offset>/<container-size>\n"
 #endif
 	"  events/\t\t- Directory containing all trace event subsystems:\n"
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index fff3ccfcdbb6..e2a31087f1f8 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -58,6 +58,13 @@ DEFINE_BASIC_PRINT_TYPE_FUNC(x16, u16, "0x%x")
 DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x")
 DEFINE_BASIC_PRINT_TYPE_FUNC(x64, u64, "0x%Lx")
 
+int PRINT_TYPE_FUNC_NAME(symbol)(struct trace_seq *s, void *data, void *ent)
+{
+	trace_seq_printf(s, "%pS", (void *)*(unsigned long *)data);
+	return !trace_seq_has_overflowed(s);
+}
+const char PRINT_TYPE_FMT_NAME(symbol)[] = "%pS";
+
 /* Print type function for string type */
 int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent)
 {
@@ -91,6 +98,7 @@ static const struct fetch_type probe_fetch_types[] = {
 	ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0),
 	ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0),
 	ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0),
+	ASSIGN_FETCH_TYPE_ALIAS(symbol, ADDR_FETCH_TYPE, ADDR_FETCH_TYPE, 0),
 
 	ASSIGN_FETCH_TYPE_END
 };
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 3bc43c1ce628..ef477bd8468a 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -157,6 +157,7 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(x32);
 DECLARE_BASIC_PRINT_TYPE_FUNC(x64);
 
 DECLARE_BASIC_PRINT_TYPE_FUNC(string);
+DECLARE_BASIC_PRINT_TYPE_FUNC(symbol);
 
 /* Default (unsigned long) fetch type */
 #define __DEFAULT_FETCH_TYPE(t) x##t
@@ -164,6 +165,10 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(string);
 #define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG)
 #define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE)
 
+#define __ADDR_FETCH_TYPE(t) u##t
+#define _ADDR_FETCH_TYPE(t) __ADDR_FETCH_TYPE(t)
+#define ADDR_FETCH_TYPE _ADDR_FETCH_TYPE(BITS_PER_LONG)
+
 #define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype)	\
 	{.name = _name,				\
 	 .size = _size,					\
@@ -172,13 +177,14 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(string);
 	 .fmt = PRINT_TYPE_FMT_NAME(ptype),		\
 	 .fmttype = _fmttype,				\
 	}
-
+#define _ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype)	\
+	__ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, #_fmttype)
 #define ASSIGN_FETCH_TYPE(ptype, ftype, sign)			\
-	__ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, #ptype)
+	_ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, ptype)
 
 /* If ptype is an alias of atype, use this macro (show atype in format) */
 #define ASSIGN_FETCH_TYPE_ALIAS(ptype, atype, ftype, sign)		\
-	__ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, #atype)
+	_ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, atype)
 
 #define ASSIGN_FETCH_TYPE_END {}
 

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 10/16] x86: ptrace: Add function argument access API
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
                   ` (9 preceding siblings ...)
  2018-04-25 12:20 ` [PATCH v7 09/16] tracing: probeevent: Add symbol type mhiramat
@ 2018-04-25 12:20 ` mhiramat
  2018-04-25 12:20   ` Masami Hiramatsu
  2018-04-25 12:21 ` [PATCH v7 11/16] tracing: probeevent: Add $argN for accessing function args mhiramat
                   ` (8 subsequent siblings)
  19 siblings, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-04-25 12:20 UTC (permalink / raw)


Add regs_get_argument() which returns N th argument of the
function call.
Note that this chooses most probably assignment, in some case
it can be incorrect (e.g. passing data structure or floating
point etc.)

This is expected to be called from kprobes or ftrace with regs
where the top of stack is the return address.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 arch/Kconfig                  |    7 +++++++
 arch/x86/Kconfig              |    1 +
 arch/x86/include/asm/ptrace.h |   38 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 46 insertions(+)

diff --git a/arch/Kconfig b/arch/Kconfig
index 8e0d665c8d53..e20c3781b3ca 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -272,6 +272,13 @@ config HAVE_REGS_AND_STACK_ACCESS_API
 	  declared in asm/ptrace.h
 	  For example the kprobes-based event tracer needs this API.
 
+config HAVE_FUNCTION_ARG_ACCESS_API
+	bool
+	help
+	  This symbol should be selected by an architecure if it supports
+	  the API needed to access function arguments from pt_regs,
+	  declared in asm/ptrace.h
+
 config HAVE_CLK
 	bool
 	help
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 00fcf81f2c56..2d8aaee91694 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -177,6 +177,7 @@ config X86
 	select HAVE_PERF_USER_STACK_DUMP
 	select HAVE_RCU_TABLE_FREE
 	select HAVE_REGS_AND_STACK_ACCESS_API
+	select HAVE_FUNCTION_ARG_ACCESS_API
 	select HAVE_RELIABLE_STACKTRACE		if X86_64 && UNWINDER_FRAME_POINTER && STACK_VALIDATION
 	select HAVE_STACK_VALIDATION		if X86_64
 	select HAVE_SYSCALL_TRACEPOINTS
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
index 6de1fd3d0097..c2304b25e2fd 100644
--- a/arch/x86/include/asm/ptrace.h
+++ b/arch/x86/include/asm/ptrace.h
@@ -256,6 +256,44 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
 		return 0;
 }
 
+/**
+ * regs_get_kernel_argument() - get Nth function argument in kernel
+ * @regs:	pt_regs of that context
+ * @n:		function argument number (start from 0)
+ *
+ * regs_get_argument() returns @n th argument of the function call.
+ * Note that this chooses most probably assignment, in some case
+ * it can be incorrect.
+ * This is expected to be called from kprobes or ftrace with regs
+ * where the top of stack is the return address.
+ */
+static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
+						     unsigned int n)
+{
+	static const unsigned int argument_offs[] = {
+#ifdef __i386__
+		offsetof(struct pt_regs, ax),
+		offsetof(struct pt_regs, cx),
+		offsetof(struct pt_regs, dx),
+#define NR_REG_ARGUMENTS 3
+#else
+		offsetof(struct pt_regs, di),
+		offsetof(struct pt_regs, si),
+		offsetof(struct pt_regs, dx),
+		offsetof(struct pt_regs, cx),
+		offsetof(struct pt_regs, r8),
+		offsetof(struct pt_regs, r9),
+#define NR_REG_ARGUMENTS 6
+#endif
+	};
+
+	if (n >= NR_REG_ARGUMENTS) {
+		n -= NR_REG_ARGUMENTS - 1;
+		return regs_get_kernel_stack_nth(regs, n);
+	} else
+		return regs_get_register(regs, argument_offs[n]);
+}
+
 #define arch_has_single_step()	(1)
 #ifdef CONFIG_X86_DEBUGCTLMSR
 #define arch_has_block_step()	(1)

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 10/16] x86: ptrace: Add function argument access API
  2018-04-25 12:20 ` [PATCH v7 10/16] x86: ptrace: Add function argument access API mhiramat
@ 2018-04-25 12:20   ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-04-25 12:20 UTC (permalink / raw)


Add regs_get_argument() which returns N th argument of the
function call.
Note that this chooses most probably assignment, in some case
it can be incorrect (e.g. passing data structure or floating
point etc.)

This is expected to be called from kprobes or ftrace with regs
where the top of stack is the return address.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 arch/Kconfig                  |    7 +++++++
 arch/x86/Kconfig              |    1 +
 arch/x86/include/asm/ptrace.h |   38 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 46 insertions(+)

diff --git a/arch/Kconfig b/arch/Kconfig
index 8e0d665c8d53..e20c3781b3ca 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -272,6 +272,13 @@ config HAVE_REGS_AND_STACK_ACCESS_API
 	  declared in asm/ptrace.h
 	  For example the kprobes-based event tracer needs this API.
 
+config HAVE_FUNCTION_ARG_ACCESS_API
+	bool
+	help
+	  This symbol should be selected by an architecure if it supports
+	  the API needed to access function arguments from pt_regs,
+	  declared in asm/ptrace.h
+
 config HAVE_CLK
 	bool
 	help
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 00fcf81f2c56..2d8aaee91694 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -177,6 +177,7 @@ config X86
 	select HAVE_PERF_USER_STACK_DUMP
 	select HAVE_RCU_TABLE_FREE
 	select HAVE_REGS_AND_STACK_ACCESS_API
+	select HAVE_FUNCTION_ARG_ACCESS_API
 	select HAVE_RELIABLE_STACKTRACE		if X86_64 && UNWINDER_FRAME_POINTER && STACK_VALIDATION
 	select HAVE_STACK_VALIDATION		if X86_64
 	select HAVE_SYSCALL_TRACEPOINTS
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
index 6de1fd3d0097..c2304b25e2fd 100644
--- a/arch/x86/include/asm/ptrace.h
+++ b/arch/x86/include/asm/ptrace.h
@@ -256,6 +256,44 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
 		return 0;
 }
 
+/**
+ * regs_get_kernel_argument() - get Nth function argument in kernel
+ * @regs:	pt_regs of that context
+ * @n:		function argument number (start from 0)
+ *
+ * regs_get_argument() returns @n th argument of the function call.
+ * Note that this chooses most probably assignment, in some case
+ * it can be incorrect.
+ * This is expected to be called from kprobes or ftrace with regs
+ * where the top of stack is the return address.
+ */
+static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
+						     unsigned int n)
+{
+	static const unsigned int argument_offs[] = {
+#ifdef __i386__
+		offsetof(struct pt_regs, ax),
+		offsetof(struct pt_regs, cx),
+		offsetof(struct pt_regs, dx),
+#define NR_REG_ARGUMENTS 3
+#else
+		offsetof(struct pt_regs, di),
+		offsetof(struct pt_regs, si),
+		offsetof(struct pt_regs, dx),
+		offsetof(struct pt_regs, cx),
+		offsetof(struct pt_regs, r8),
+		offsetof(struct pt_regs, r9),
+#define NR_REG_ARGUMENTS 6
+#endif
+	};
+
+	if (n >= NR_REG_ARGUMENTS) {
+		n -= NR_REG_ARGUMENTS - 1;
+		return regs_get_kernel_stack_nth(regs, n);
+	} else
+		return regs_get_register(regs, argument_offs[n]);
+}
+
 #define arch_has_single_step()	(1)
 #ifdef CONFIG_X86_DEBUGCTLMSR
 #define arch_has_block_step()	(1)

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 11/16] tracing: probeevent: Add $argN for accessing function args
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
                   ` (10 preceding siblings ...)
  2018-04-25 12:20 ` [PATCH v7 10/16] x86: ptrace: Add function argument access API mhiramat
@ 2018-04-25 12:21 ` mhiramat
  2018-04-25 12:21   ` Masami Hiramatsu
  2018-04-25 12:21 ` [PATCH v7 12/16] tracing: probeevent: Add array type support mhiramat
                   ` (7 subsequent siblings)
  19 siblings, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-04-25 12:21 UTC (permalink / raw)


Add $argN special fetch variable for accessing function
arguments. This allows user to trace the Nth argument easily
at the function entry.

Note that this returns most probably assignment of registers
and stacks. In some case, it may not work well. If you need
to access correct registers or stacks you should use perf-probe.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v2:
  - Add $argN in README file
  - Make N start from 1 as same as auto-generate event argument
    names.
 Changes in v3:
  - Show $arg<N> in README only when this feature is supported.
 Changes in v7:
  - Update document for restructured text.
---
 Documentation/trace/kprobetrace.rst |   10 ++++++----
 kernel/trace/trace.c                |    4 ++++
 kernel/trace/trace_kprobe.c         |   18 +++++++++++++-----
 kernel/trace/trace_probe.c          |   36 ++++++++++++++++++++++-------------
 kernel/trace/trace_probe.h          |    9 ++++++++-
 kernel/trace/trace_uprobe.c         |    2 +-
 6 files changed, 55 insertions(+), 24 deletions(-)

diff --git a/Documentation/trace/kprobetrace.rst b/Documentation/trace/kprobetrace.rst
index c920c9be221a..30eb37391064 100644
--- a/Documentation/trace/kprobetrace.rst
+++ b/Documentation/trace/kprobetrace.rst
@@ -45,16 +45,18 @@ Synopsis of kprobe_events
   @SYM[+|-offs]	: Fetch memory at SYM +|- offs (SYM should be a data symbol)
   $stackN	: Fetch Nth entry of stack (N >= 0)
   $stack	: Fetch stack address.
-  $retval	: Fetch return value.(*)
+  $argN		: Fetch the Nth function argument. (N >= 1) (\*1)
+  $retval	: Fetch return value.(\*2)
   $comm		: Fetch current task comm.
-  +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**)
+  +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(\*3)
   NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
   FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
 		  (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
 		  (x8/x16/x32/x64), "string" and bitfield are supported.
 
-  (*) only for return probe.
-  (**) this is useful for fetching a field of data structures.
+  (\*1) only for the probe on function entry (offs == 0).
+  (\*2) only for return probe.
+  (\*3) this is useful for fetching a field of data structures.
 
 Types
 -----
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 4812ae046f43..7add9bfdff76 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4620,7 +4620,11 @@ static const char readme_msg[] =
 #endif
 	"\t     args: <name>=fetcharg[:type]\n"
 	"\t fetcharg: %<register>, @<address>, @<symbol>[+|-<offset>],\n"
+#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
+	"\t           $stack<index>, $stack, $retval, $comm, $arg<N>\n"
+#else
 	"\t           $stack<index>, $stack, $retval, $comm\n"
+#endif
 	"\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
 	"\t           b<bit-width>@<bit-offset>/<container-size>\n"
 #endif
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 673d4b06edd4..b6d33401b629 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -490,13 +490,15 @@ static int create_trace_kprobe(int argc, char **argv)
 	long offset = 0;
 	void *addr = NULL;
 	char buf[MAX_EVENT_NAME_LEN];
+	unsigned int flags = TPARG_FL_KERNEL;
 
 	/* argc must be >= 1 */
 	if (argv[0][0] == 'p')
 		is_return = false;
-	else if (argv[0][0] == 'r')
+	else if (argv[0][0] == 'r') {
 		is_return = true;
-	else if (argv[0][0] == '-')
+		flags |= TPARG_FL_RETURN;
+	} else if (argv[0][0] == '-')
 		is_delete = true;
 	else {
 		pr_info("Probe definition must be started with 'p', 'r' or"
@@ -579,8 +581,9 @@ static int create_trace_kprobe(int argc, char **argv)
 			pr_info("Failed to parse either an address or a symbol.\n");
 			return ret;
 		}
-		if (offset && is_return &&
-		    !kprobe_on_func_entry(NULL, symbol, offset)) {
+		if (kprobe_on_func_entry(NULL, symbol, offset))
+			flags |= TPARG_FL_FENTRY;
+		if (offset && is_return && !(flags & TPARG_FL_FENTRY)) {
 			pr_info("Given offset is not valid for return probe.\n");
 			return -EINVAL;
 		}
@@ -650,7 +653,7 @@ static int create_trace_kprobe(int argc, char **argv)
 
 		/* Parse fetch argument */
 		ret = traceprobe_parse_probe_arg(arg, &tk->tp.size, parg,
-						 is_return, true);
+						 flags);
 		if (ret) {
 			pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
 			goto error;
@@ -886,6 +889,11 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 	case FETCH_OP_COMM:
 		val = (unsigned long)current->comm;
 		break;
+#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
+	case FETCH_OP_ARG:
+		val = regs_get_kernel_argument(regs, code->param);
+		break;
+#endif
 	default:
 		return -EILSEQ;
 	}
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index e2a31087f1f8..9458800f394a 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -169,14 +169,13 @@ int traceprobe_split_symbol_offset(char *symbol, long *offset)
 #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
 
 static int parse_probe_vars(char *arg, const struct fetch_type *t,
-			    struct fetch_insn *code, bool is_return,
-			    bool is_kprobe)
+			    struct fetch_insn *code, unsigned int flags)
 {
 	int ret = 0;
 	unsigned long param;
 
 	if (strcmp(arg, "retval") == 0) {
-		if (is_return)
+		if (flags & TPARG_FL_RETURN)
 			code->op = FETCH_OP_RETVAL;
 		else
 			ret = -EINVAL;
@@ -185,7 +184,8 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
 			code->op = FETCH_OP_STACKP;
 		} else if (isdigit(arg[5])) {
 			ret = kstrtoul(arg + 5, 10, &param);
-			if (ret || (is_kprobe && param > PARAM_MAX_STACK))
+			if (ret || ((flags & TPARG_FL_KERNEL) &&
+				    param > PARAM_MAX_STACK))
 				ret = -EINVAL;
 			else {
 				code->op = FETCH_OP_STACK;
@@ -195,6 +195,18 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
 			ret = -EINVAL;
 	} else if (strcmp(arg, "comm") == 0) {
 		code->op = FETCH_OP_COMM;
+#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
+	} else if (((flags & TPARG_FL_MASK) ==
+		    (TPARG_FL_KERNEL | TPARG_FL_FENTRY)) &&
+		   strncmp(arg, "arg", 3) == 0) {
+		if (!isdigit(arg[3]))
+			return -EINVAL;
+		ret = kstrtoul(arg + 3, 10, &param);
+		if (ret || !param || param > PARAM_MAX_STACK)
+			return -EINVAL;
+		code->op = FETCH_OP_ARG;
+		code->param = (unsigned int)param - 1;
+#endif
 	} else
 		ret = -EINVAL;
 
@@ -205,7 +217,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
 static int
 parse_probe_arg(char *arg, const struct fetch_type *type,
 		struct fetch_insn **pcode, struct fetch_insn *end,
-		bool is_return, bool is_kprobe)
+		unsigned int flags)
 {
 	struct fetch_insn *code = *pcode;
 	unsigned long param;
@@ -215,8 +227,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 
 	switch (arg[0]) {
 	case '$':
-		ret = parse_probe_vars(arg + 1, type, code,
-					is_return, is_kprobe);
+		ret = parse_probe_vars(arg + 1, type, code, flags);
 		break;
 
 	case '%':	/* named register */
@@ -238,7 +249,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 			code->immediate = param;
 		} else if (arg[1] == '+') {
 			/* kprobes don't support file offsets */
-			if (is_kprobe)
+			if (flags & TPARG_FL_KERNEL)
 				return -EINVAL;
 
 			ret = kstrtol(arg + 2, 0, &offset);
@@ -249,7 +260,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 			code->immediate = (unsigned long)offset;  // imm64?
 		} else {
 			/* uprobes don't support symbols */
-			if (!is_kprobe)
+			if (!(flags & TPARG_FL_KERNEL))
 				return -EINVAL;
 
 			ret = traceprobe_split_symbol_offset(arg + 1, &offset);
@@ -290,8 +301,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 			const struct fetch_type *t2 = find_fetch_type(NULL);
 
 			*tmp = '\0';
-			ret = parse_probe_arg(arg, t2, &code, end, is_return,
-					      is_kprobe);
+			ret = parse_probe_arg(arg, t2, &code, end, flags);
 			if (ret)
 				break;
 			if (code->op == FETCH_OP_COMM)
@@ -351,7 +361,7 @@ static int __parse_bitfield_probe_arg(const char *bf,
 
 /* String length checking wrapper */
 int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
-		struct probe_arg *parg, bool is_return, bool is_kprobe)
+		struct probe_arg *parg, unsigned int flags)
 {
 	struct fetch_insn *code, *tmp = NULL;
 	const char *t;
@@ -391,7 +401,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 	code[FETCH_INSN_MAX - 1].op = FETCH_OP_END;
 
 	ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1],
-			      is_return, is_kprobe);
+			      flags);
 	if (ret)
 		goto fail;
 
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index ef477bd8468a..ff91faf70887 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -35,6 +35,7 @@
 #include <linux/stringify.h>
 #include <linux/limits.h>
 #include <linux/uaccess.h>
+#include <linux/bitops.h>
 #include <asm/bitsperlong.h>
 
 #include "trace.h"
@@ -89,6 +90,7 @@ enum fetch_op {
 	FETCH_OP_RETVAL,	/* Return value */
 	FETCH_OP_IMM,		/* Immediate : .immediate */
 	FETCH_OP_COMM,		/* Current comm */
+	FETCH_OP_ARG,		/* Function argument : .param */
 	FETCH_OP_FOFFS,		/* File offset: .immediate */
 	// Stage 2 (dereference) op
 	FETCH_OP_DEREF,		/* Dereference: .offset */
@@ -261,8 +263,13 @@ find_event_file_link(struct trace_probe *tp, struct trace_event_file *file)
 	return NULL;
 }
 
+#define TPARG_FL_RETURN BIT(0)
+#define TPARG_FL_KERNEL BIT(1)
+#define TPARG_FL_FENTRY BIT(2)
+#define TPARG_FL_MASK	GENMASK(2, 0)
+
 extern int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
-		   struct probe_arg *parg, bool is_return, bool is_kprobe);
+		   struct probe_arg *parg, unsigned int flags);
 
 extern int traceprobe_conflict_field_name(const char *name,
 			       struct probe_arg *args, int narg);
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 2cf8faeb5b72..bb68e6af1ef5 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -519,7 +519,7 @@ static int create_trace_uprobe(int argc, char **argv)
 
 		/* Parse fetch argument */
 		ret = traceprobe_parse_probe_arg(arg, &tu->tp.size, parg,
-						 is_return, false);
+					is_return ? TPARG_FL_RETURN : 0);
 		if (ret) {
 			pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
 			goto error;

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 11/16] tracing: probeevent: Add $argN for accessing function args
  2018-04-25 12:21 ` [PATCH v7 11/16] tracing: probeevent: Add $argN for accessing function args mhiramat
@ 2018-04-25 12:21   ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-04-25 12:21 UTC (permalink / raw)


Add $argN special fetch variable for accessing function
arguments. This allows user to trace the Nth argument easily
at the function entry.

Note that this returns most probably assignment of registers
and stacks. In some case, it may not work well. If you need
to access correct registers or stacks you should use perf-probe.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v2:
  - Add $argN in README file
  - Make N start from 1 as same as auto-generate event argument
    names.
 Changes in v3:
  - Show $arg<N> in README only when this feature is supported.
 Changes in v7:
  - Update document for restructured text.
---
 Documentation/trace/kprobetrace.rst |   10 ++++++----
 kernel/trace/trace.c                |    4 ++++
 kernel/trace/trace_kprobe.c         |   18 +++++++++++++-----
 kernel/trace/trace_probe.c          |   36 ++++++++++++++++++++++-------------
 kernel/trace/trace_probe.h          |    9 ++++++++-
 kernel/trace/trace_uprobe.c         |    2 +-
 6 files changed, 55 insertions(+), 24 deletions(-)

diff --git a/Documentation/trace/kprobetrace.rst b/Documentation/trace/kprobetrace.rst
index c920c9be221a..30eb37391064 100644
--- a/Documentation/trace/kprobetrace.rst
+++ b/Documentation/trace/kprobetrace.rst
@@ -45,16 +45,18 @@ Synopsis of kprobe_events
   @SYM[+|-offs]	: Fetch memory at SYM +|- offs (SYM should be a data symbol)
   $stackN	: Fetch Nth entry of stack (N >= 0)
   $stack	: Fetch stack address.
-  $retval	: Fetch return value.(*)
+  $argN		: Fetch the Nth function argument. (N >= 1) (\*1)
+  $retval	: Fetch return value.(\*2)
   $comm		: Fetch current task comm.
-  +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**)
+  +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(\*3)
   NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
   FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
 		  (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
 		  (x8/x16/x32/x64), "string" and bitfield are supported.
 
-  (*) only for return probe.
-  (**) this is useful for fetching a field of data structures.
+  (\*1) only for the probe on function entry (offs == 0).
+  (\*2) only for return probe.
+  (\*3) this is useful for fetching a field of data structures.
 
 Types
 -----
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 4812ae046f43..7add9bfdff76 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4620,7 +4620,11 @@ static const char readme_msg[] =
 #endif
 	"\t     args: <name>=fetcharg[:type]\n"
 	"\t fetcharg: %<register>, @<address>, @<symbol>[+|-<offset>],\n"
+#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
+	"\t           $stack<index>, $stack, $retval, $comm, $arg<N>\n"
+#else
 	"\t           $stack<index>, $stack, $retval, $comm\n"
+#endif
 	"\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
 	"\t           b<bit-width>@<bit-offset>/<container-size>\n"
 #endif
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 673d4b06edd4..b6d33401b629 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -490,13 +490,15 @@ static int create_trace_kprobe(int argc, char **argv)
 	long offset = 0;
 	void *addr = NULL;
 	char buf[MAX_EVENT_NAME_LEN];
+	unsigned int flags = TPARG_FL_KERNEL;
 
 	/* argc must be >= 1 */
 	if (argv[0][0] == 'p')
 		is_return = false;
-	else if (argv[0][0] == 'r')
+	else if (argv[0][0] == 'r') {
 		is_return = true;
-	else if (argv[0][0] == '-')
+		flags |= TPARG_FL_RETURN;
+	} else if (argv[0][0] == '-')
 		is_delete = true;
 	else {
 		pr_info("Probe definition must be started with 'p', 'r' or"
@@ -579,8 +581,9 @@ static int create_trace_kprobe(int argc, char **argv)
 			pr_info("Failed to parse either an address or a symbol.\n");
 			return ret;
 		}
-		if (offset && is_return &&
-		    !kprobe_on_func_entry(NULL, symbol, offset)) {
+		if (kprobe_on_func_entry(NULL, symbol, offset))
+			flags |= TPARG_FL_FENTRY;
+		if (offset && is_return && !(flags & TPARG_FL_FENTRY)) {
 			pr_info("Given offset is not valid for return probe.\n");
 			return -EINVAL;
 		}
@@ -650,7 +653,7 @@ static int create_trace_kprobe(int argc, char **argv)
 
 		/* Parse fetch argument */
 		ret = traceprobe_parse_probe_arg(arg, &tk->tp.size, parg,
-						 is_return, true);
+						 flags);
 		if (ret) {
 			pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
 			goto error;
@@ -886,6 +889,11 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 	case FETCH_OP_COMM:
 		val = (unsigned long)current->comm;
 		break;
+#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
+	case FETCH_OP_ARG:
+		val = regs_get_kernel_argument(regs, code->param);
+		break;
+#endif
 	default:
 		return -EILSEQ;
 	}
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index e2a31087f1f8..9458800f394a 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -169,14 +169,13 @@ int traceprobe_split_symbol_offset(char *symbol, long *offset)
 #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
 
 static int parse_probe_vars(char *arg, const struct fetch_type *t,
-			    struct fetch_insn *code, bool is_return,
-			    bool is_kprobe)
+			    struct fetch_insn *code, unsigned int flags)
 {
 	int ret = 0;
 	unsigned long param;
 
 	if (strcmp(arg, "retval") == 0) {
-		if (is_return)
+		if (flags & TPARG_FL_RETURN)
 			code->op = FETCH_OP_RETVAL;
 		else
 			ret = -EINVAL;
@@ -185,7 +184,8 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
 			code->op = FETCH_OP_STACKP;
 		} else if (isdigit(arg[5])) {
 			ret = kstrtoul(arg + 5, 10, &param);
-			if (ret || (is_kprobe && param > PARAM_MAX_STACK))
+			if (ret || ((flags & TPARG_FL_KERNEL) &&
+				    param > PARAM_MAX_STACK))
 				ret = -EINVAL;
 			else {
 				code->op = FETCH_OP_STACK;
@@ -195,6 +195,18 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
 			ret = -EINVAL;
 	} else if (strcmp(arg, "comm") == 0) {
 		code->op = FETCH_OP_COMM;
+#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
+	} else if (((flags & TPARG_FL_MASK) ==
+		    (TPARG_FL_KERNEL | TPARG_FL_FENTRY)) &&
+		   strncmp(arg, "arg", 3) == 0) {
+		if (!isdigit(arg[3]))
+			return -EINVAL;
+		ret = kstrtoul(arg + 3, 10, &param);
+		if (ret || !param || param > PARAM_MAX_STACK)
+			return -EINVAL;
+		code->op = FETCH_OP_ARG;
+		code->param = (unsigned int)param - 1;
+#endif
 	} else
 		ret = -EINVAL;
 
@@ -205,7 +217,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
 static int
 parse_probe_arg(char *arg, const struct fetch_type *type,
 		struct fetch_insn **pcode, struct fetch_insn *end,
-		bool is_return, bool is_kprobe)
+		unsigned int flags)
 {
 	struct fetch_insn *code = *pcode;
 	unsigned long param;
@@ -215,8 +227,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 
 	switch (arg[0]) {
 	case '$':
-		ret = parse_probe_vars(arg + 1, type, code,
-					is_return, is_kprobe);
+		ret = parse_probe_vars(arg + 1, type, code, flags);
 		break;
 
 	case '%':	/* named register */
@@ -238,7 +249,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 			code->immediate = param;
 		} else if (arg[1] == '+') {
 			/* kprobes don't support file offsets */
-			if (is_kprobe)
+			if (flags & TPARG_FL_KERNEL)
 				return -EINVAL;
 
 			ret = kstrtol(arg + 2, 0, &offset);
@@ -249,7 +260,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 			code->immediate = (unsigned long)offset;  // imm64?
 		} else {
 			/* uprobes don't support symbols */
-			if (!is_kprobe)
+			if (!(flags & TPARG_FL_KERNEL))
 				return -EINVAL;
 
 			ret = traceprobe_split_symbol_offset(arg + 1, &offset);
@@ -290,8 +301,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 			const struct fetch_type *t2 = find_fetch_type(NULL);
 
 			*tmp = '\0';
-			ret = parse_probe_arg(arg, t2, &code, end, is_return,
-					      is_kprobe);
+			ret = parse_probe_arg(arg, t2, &code, end, flags);
 			if (ret)
 				break;
 			if (code->op == FETCH_OP_COMM)
@@ -351,7 +361,7 @@ static int __parse_bitfield_probe_arg(const char *bf,
 
 /* String length checking wrapper */
 int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
-		struct probe_arg *parg, bool is_return, bool is_kprobe)
+		struct probe_arg *parg, unsigned int flags)
 {
 	struct fetch_insn *code, *tmp = NULL;
 	const char *t;
@@ -391,7 +401,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 	code[FETCH_INSN_MAX - 1].op = FETCH_OP_END;
 
 	ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1],
-			      is_return, is_kprobe);
+			      flags);
 	if (ret)
 		goto fail;
 
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index ef477bd8468a..ff91faf70887 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -35,6 +35,7 @@
 #include <linux/stringify.h>
 #include <linux/limits.h>
 #include <linux/uaccess.h>
+#include <linux/bitops.h>
 #include <asm/bitsperlong.h>
 
 #include "trace.h"
@@ -89,6 +90,7 @@ enum fetch_op {
 	FETCH_OP_RETVAL,	/* Return value */
 	FETCH_OP_IMM,		/* Immediate : .immediate */
 	FETCH_OP_COMM,		/* Current comm */
+	FETCH_OP_ARG,		/* Function argument : .param */
 	FETCH_OP_FOFFS,		/* File offset: .immediate */
 	// Stage 2 (dereference) op
 	FETCH_OP_DEREF,		/* Dereference: .offset */
@@ -261,8 +263,13 @@ find_event_file_link(struct trace_probe *tp, struct trace_event_file *file)
 	return NULL;
 }
 
+#define TPARG_FL_RETURN BIT(0)
+#define TPARG_FL_KERNEL BIT(1)
+#define TPARG_FL_FENTRY BIT(2)
+#define TPARG_FL_MASK	GENMASK(2, 0)
+
 extern int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
-		   struct probe_arg *parg, bool is_return, bool is_kprobe);
+		   struct probe_arg *parg, unsigned int flags);
 
 extern int traceprobe_conflict_field_name(const char *name,
 			       struct probe_arg *args, int narg);
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 2cf8faeb5b72..bb68e6af1ef5 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -519,7 +519,7 @@ static int create_trace_uprobe(int argc, char **argv)
 
 		/* Parse fetch argument */
 		ret = traceprobe_parse_probe_arg(arg, &tu->tp.size, parg,
-						 is_return, false);
+					is_return ? TPARG_FL_RETURN : 0);
 		if (ret) {
 			pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
 			goto error;

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 12/16] tracing: probeevent: Add array type support
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
                   ` (11 preceding siblings ...)
  2018-04-25 12:21 ` [PATCH v7 11/16] tracing: probeevent: Add $argN for accessing function args mhiramat
@ 2018-04-25 12:21 ` mhiramat
  2018-04-25 12:21   ` Masami Hiramatsu
  2018-04-25 12:22 ` [PATCH v7 13/16] selftests: ftrace: Add a testcase for symbol type mhiramat
                   ` (6 subsequent siblings)
  19 siblings, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-04-25 12:21 UTC (permalink / raw)


Add array type support for probe events.
This allows user to get arraied types from memory address.
The array type syntax is

	TYPE[N]

Where TYPE is one of types (u8/16/32/64,s8/16/32/64,
x8/16/32/64, symbol, string) and N is a fixed value less
than 64.

The string array type is a bit different from other types. For
other base types, <base-type>[1] is equal to <base-type>
(e.g. +0(%di):x32[1] is same as +0(%di):x32.) But string[1] is not
equal to string. The string type itself represents "char array",
but string array type represents "char * array". So, for example,
+0(%di):string[1] is equal to +0(+0(%di)):string.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v6:
  - Fix to add escaping backslash to a brace for syntax
    in README file.
 Changes in v4:
  - Fix to use calculated size correctly for field definition.
    (Thank you Namhyung!)
 Changes in v2:
  - Add array description in README file
  - Fix to init s3 code out of loop.
  - Fix to proceed code when the last code is OP_ARRAY.
  - Add string array type and bitfield array type.
---
 Documentation/trace/kprobetrace.rst |   11 +++
 kernel/trace/trace.c                |    3 +
 kernel/trace/trace_probe.c          |  130 +++++++++++++++++++++++++++--------
 kernel/trace/trace_probe.h          |   14 ++++
 kernel/trace/trace_probe_tmpl.h     |   63 +++++++++++++++--
 5 files changed, 181 insertions(+), 40 deletions(-)

diff --git a/Documentation/trace/kprobetrace.rst b/Documentation/trace/kprobetrace.rst
index 30eb37391064..b9e9198ea95d 100644
--- a/Documentation/trace/kprobetrace.rst
+++ b/Documentation/trace/kprobetrace.rst
@@ -66,9 +66,20 @@ respectively. 'x' prefix implies it is unsigned. Traced arguments are shown
 in decimal ('s' and 'u') or hexadecimal ('x'). Without type casting, 'x32'
 or 'x64' is used depends on the architecture (e.g. x86-32 uses x32, and
 x86-64 uses x64).
+These value types can be an array. To record array data, you can add '[N]'
+(where N is a fixed number, less than 64) to the base type.
+E.g. 'x16[4]' means an array of x16 (2bytes hex) with 4 elements.
+Note that the array can be applied to memory type fetchargs, you can not
+apply it to registers/stack-entries etc. (for example, '$stack1:x8[8]' is
+wrong, but '+8($stack):x8[8]' is OK.)
 String type is a special type, which fetches a "null-terminated" string from
 kernel space. This means it will fail and store NULL if the string container
 has been paged out.
+The string array type is a bit different from other types. For other base
+types, <base-type>[1] is equal to <base-type> (e.g. +0(%di):x32[1] is same
+as +0(%di):x32.) But string[1] is not equal to string. The string type itself
+represents "char array", but string array type represents "char * array".
+So, for example, +0(%di):string[1] is equal to +0(+0(%di)):string.
 Bitfield is another special type, which takes 3 parameters, bit-width, bit-
 offset, and container-size (usually 32). The syntax is::
 
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 7add9bfdff76..f34d026689c7 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4626,7 +4626,8 @@ static const char readme_msg[] =
 	"\t           $stack<index>, $stack, $retval, $comm\n"
 #endif
 	"\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
-	"\t           b<bit-width>@<bit-offset>/<container-size>\n"
+	"\t           b<bit-width>@<bit-offset>/<container-size>,\n"
+	"\t           <type>\\[<array-size>\\]\n"
 #endif
 	"  events/\t\t- Directory containing all trace event subsystems:\n"
 	"      enable\t\t- Write 0/1 to enable/disable tracing of all events\n"
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 9458800f394a..0e185050e492 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -363,9 +363,9 @@ static int __parse_bitfield_probe_arg(const char *bf,
 int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 		struct probe_arg *parg, unsigned int flags)
 {
-	struct fetch_insn *code, *tmp = NULL;
-	const char *t;
-	int ret;
+	struct fetch_insn *code, *scode, *tmp = NULL;
+	char *t, *t2;
+	int ret, len;
 
 	if (strlen(arg) > MAX_ARGSTR_LEN) {
 		pr_info("Argument is too long.: %s\n",  arg);
@@ -376,24 +376,42 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 		pr_info("Failed to allocate memory for command '%s'.\n", arg);
 		return -ENOMEM;
 	}
-	t = strchr(parg->comm, ':');
+	t = strchr(arg, ':');
 	if (t) {
-		arg[t - parg->comm] = '\0';
-		t++;
+		*t = '\0';
+		t2 = strchr(++t, '[');
+		if (t2) {
+			*t2 = '\0';
+			parg->count = simple_strtoul(t2 + 1, &t2, 0);
+			if (strcmp(t2, "]") || parg->count == 0)
+				return -EINVAL;
+			if (parg->count > MAX_ARRAY_LEN)
+				return -E2BIG;
+		}
 	}
 	/*
 	 * The default type of $comm should be "string", and it can't be
 	 * dereferenced.
 	 */
 	if (!t && strcmp(arg, "$comm") == 0)
-		t = "string";
-	parg->type = find_fetch_type(t);
+		parg->type = find_fetch_type("string");
+	else
+		parg->type = find_fetch_type(t);
 	if (!parg->type) {
 		pr_info("Unsupported type: %s\n", t);
 		return -EINVAL;
 	}
 	parg->offset = *size;
-	*size += parg->type->size;
+	*size += parg->type->size * (parg->count ?: 1);
+
+	if (parg->count) {
+		len = strlen(parg->type->fmttype) + 6;
+		parg->fmt = kmalloc(len, GFP_KERNEL);
+		if (!parg->fmt)
+			return -ENOMEM;
+		snprintf(parg->fmt, len, "%s[%d]", parg->type->fmttype,
+			 parg->count);
+	}
 
 	code = tmp = kzalloc(sizeof(*code) * FETCH_INSN_MAX, GFP_KERNEL);
 	if (!code)
@@ -413,10 +431,20 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 			ret = -EINVAL;
 			goto fail;
 		}
-		/* Since IMM or COMM must be the 1st insn, this is safe */
-		if (code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM)
+		if (code->op != FETCH_OP_DEREF || parg->count) {
+			/*
+			 * IMM and COMM is pointing actual address, those must
+			 * be kept, and if parg->count != 0, this is an array
+			 * of string pointers instead of string address itself.
+			 */
 			code++;
+			if (code->op != FETCH_OP_NOP) {
+				ret = -E2BIG;
+				goto fail;
+			}
+		}
 		code->op = FETCH_OP_ST_STRING;	/* In DEREF case, replace it */
+		code->size = parg->type->size;
 		parg->dynamic = true;
 	} else if (code->op == FETCH_OP_DEREF) {
 		code->op = FETCH_OP_ST_MEM;
@@ -430,12 +458,29 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 		code->op = FETCH_OP_ST_RAW;
 		code->size = parg->type->size;
 	}
+	scode = code;
 	/* Modify operation */
 	if (t != NULL) {
 		ret = __parse_bitfield_probe_arg(t, parg->type, &code);
 		if (ret)
 			goto fail;
 	}
+	/* Loop(Array) operation */
+	if (parg->count) {
+		if (scode->op != FETCH_OP_ST_MEM &&
+		    scode->op != FETCH_OP_ST_STRING) {
+			pr_info("array only accepts memory or address\n");
+			ret = -EINVAL;
+			goto fail;
+		}
+		code++;
+		if (code->op != FETCH_OP_NOP) {
+			ret = -E2BIG;
+			goto fail;
+		}
+		code->op = FETCH_OP_LP_ARRAY;
+		code->param = parg->count;
+	}
 	code++;
 	code->op = FETCH_OP_END;
 
@@ -474,14 +519,17 @@ void traceprobe_free_probe_arg(struct probe_arg *arg)
 	kfree(arg->code);
 	kfree(arg->name);
 	kfree(arg->comm);
+	kfree(arg->fmt);
 }
 
+/* When len=0, we just calculate the needed length */
+#define LEN_OR_ZERO (len ? len - pos : 0)
 static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
 			   bool is_return)
 {
-	int i;
+	struct probe_arg *parg;
+	int i, j;
 	int pos = 0;
-
 	const char *fmt, *arg;
 
 	if (!is_return) {
@@ -492,33 +540,49 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
 		arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP;
 	}
 
-	/* When len=0, we just calculate the needed length */
-#define LEN_OR_ZERO (len ? len - pos : 0)
-
 	pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt);
 
 	for (i = 0; i < tp->nr_args; i++) {
-		pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%s",
-				tp->args[i].name, tp->args[i].type->fmt);
+		parg = tp->args + i;
+		pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=", parg->name);
+		if (parg->count) {
+			pos += snprintf(buf + pos, LEN_OR_ZERO, "{%s",
+					parg->type->fmt);
+			for (j = 1; j < parg->count; j++)
+				pos += snprintf(buf + pos, LEN_OR_ZERO, ",%s",
+						parg->type->fmt);
+			pos += snprintf(buf + pos, LEN_OR_ZERO, "}");
+		} else
+			pos += snprintf(buf + pos, LEN_OR_ZERO, "%s",
+					parg->type->fmt);
 	}
 
 	pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg);
 
 	for (i = 0; i < tp->nr_args; i++) {
-		if (strcmp(tp->args[i].type->name, "string") == 0)
+		parg = tp->args + i;
+		if (parg->count) {
+			if (strcmp(parg->type->name, "string") == 0)
+				fmt = ", __get_str(%s[%d])";
+			else
+				fmt = ", REC->%s[%d]";
+			for (j = 0; j < parg->count; j++)
+				pos += snprintf(buf + pos, LEN_OR_ZERO,
+						fmt, parg->name, j);
+		} else {
+			if (strcmp(parg->type->name, "string") == 0)
+				fmt = ", __get_str(%s)";
+			else
+				fmt = ", REC->%s";
 			pos += snprintf(buf + pos, LEN_OR_ZERO,
-					", __get_str(%s)",
-					tp->args[i].name);
-		else
-			pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s",
-					tp->args[i].name);
+					fmt, parg->name);
+		}
 	}
 
-#undef LEN_OR_ZERO
-
 	/* return the length of print_fmt */
 	return pos;
 }
+#undef LEN_OR_ZERO
 
 int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return)
 {
@@ -546,11 +610,15 @@ int traceprobe_define_arg_fields(struct trace_event_call *event_call,
 	/* Set argument names as fields */
 	for (i = 0; i < tp->nr_args; i++) {
 		struct probe_arg *parg = &tp->args[i];
-
-		ret = trace_define_field(event_call, parg->type->fmttype,
-					 parg->name,
-					 offset + parg->offset,
-					 parg->type->size,
+		const char *fmt = parg->type->fmttype;
+		int size = parg->type->size;
+
+		if (parg->fmt)
+			fmt = parg->fmt;
+		if (parg->count)
+			size *= parg->count;
+		ret = trace_define_field(event_call, fmt, parg->name,
+					 offset + parg->offset, size,
 					 parg->type->is_signed,
 					 FILTER_OTHER);
 		if (ret)
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index ff91faf70887..d256a19ee6d1 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -43,6 +43,7 @@
 
 #define MAX_TRACE_ARGS		128
 #define MAX_ARGSTR_LEN		63
+#define MAX_ARRAY_LEN		64
 #define MAX_STRING_SIZE		PATH_MAX
 
 /* Reserved field names */
@@ -78,6 +79,14 @@ static nokprobe_inline void *get_loc_data(u32 *dl, void *ent)
 	return (u8 *)ent + get_loc_offs(*dl);
 }
 
+static nokprobe_inline u32 update_data_loc(u32 loc, int consumed)
+{
+	u32 maxlen = get_loc_len(loc);
+	u32 offset = get_loc_offs(loc);
+
+	return make_data_loc(maxlen - consumed, offset + consumed);
+}
+
 /* Printing function type */
 typedef int (*print_type_func_t)(struct trace_seq *, void *, void *);
 
@@ -100,6 +109,8 @@ enum fetch_op {
 	FETCH_OP_ST_STRING,	/* String: .offset, .size */
 	// Stage 4 (modify) op
 	FETCH_OP_MOD_BF,	/* Bitfield: .basesize, .lshift, .rshift */
+	// Stage 5 (loop) op
+	FETCH_OP_LP_ARRAY,	/* Array: .param = loop count */
 	FETCH_OP_END,
 };
 
@@ -189,6 +200,7 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(symbol);
 	_ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, atype)
 
 #define ASSIGN_FETCH_TYPE_END {}
+#define MAX_ARRAY_LEN	64
 
 #ifdef CONFIG_KPROBE_EVENTS
 bool trace_kprobe_on_func_entry(struct trace_event_call *call);
@@ -209,8 +221,10 @@ struct probe_arg {
 	struct fetch_insn	*code;
 	bool			dynamic;/* Dynamic array (string) is used */
 	unsigned int		offset;	/* Offset from argument entry */
+	unsigned int		count;	/* Array count */
 	const char		*name;	/* Name of this argument */
 	const char		*comm;	/* Command of this argument */
+	char			*fmt;	/* Format string if needed */
 	const struct fetch_type	*type;	/* Type of this argument */
 };
 
diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmpl.h
index b4075f3e3a29..5c56afc17cf8 100644
--- a/kernel/trace/trace_probe_tmpl.h
+++ b/kernel/trace/trace_probe_tmpl.h
@@ -67,10 +67,15 @@ static nokprobe_inline int
 process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
 			   void *dest, void *base)
 {
-	int ret = 0;
+	struct fetch_insn *s3 = NULL;
+	int total = 0, ret = 0, i = 0;
+	u32 loc = 0;
+	unsigned long lval = val;
 
+stage2:
 	/* 2nd stage: dereference memory if needed */
 	while (code->op == FETCH_OP_DEREF) {
+		lval = val;
 		ret = probe_mem_read(&val, (void *)val + code->offset,
 					sizeof(val));
 		if (ret)
@@ -78,11 +83,15 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
 		code++;
 	}
 
+	s3 = code;
+stage3:
 	/* 3rd stage: store value to buffer */
 	if (unlikely(!dest)) {
-		if (code->op == FETCH_OP_ST_STRING)
-			return fetch_store_strlen(val + code->offset);
-		else
+		if (code->op == FETCH_OP_ST_STRING) {
+			ret += fetch_store_strlen(val + code->offset);
+			code++;
+			goto array;
+		} else
 			return -EILSEQ;
 	}
 
@@ -94,6 +103,7 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
 		probe_mem_read(dest, (void *)val + code->offset, code->size);
 		break;
 	case FETCH_OP_ST_STRING:
+		loc = *(u32 *)dest;
 		ret = fetch_store_string(val + code->offset, dest, base);
 		break;
 	default:
@@ -107,6 +117,29 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
 		code++;
 	}
 
+array:
+	/* the last stage: Loop on array */
+	if (code->op == FETCH_OP_LP_ARRAY) {
+		total += ret;
+		if (++i < code->param) {
+			code = s3;
+			if (s3->op != FETCH_OP_ST_STRING) {
+				dest += s3->size;
+				val += s3->size;
+				goto stage3;
+			}
+			code--;
+			val = lval + sizeof(char *);
+			if (dest) {
+				dest += sizeof(u32);
+				*(u32 *)dest = update_data_loc(loc, ret);
+			}
+			goto stage2;
+		}
+		code++;
+		ret = total;
+	}
+
 	return code->op == FETCH_OP_END ? ret : -EILSEQ;
 }
 
@@ -158,12 +191,26 @@ static inline int
 print_probe_args(struct trace_seq *s, struct probe_arg *args, int nr_args,
 		 u8 *data, void *field)
 {
-	int i;
+	void *p;
+	int i, j;
 
 	for (i = 0; i < nr_args; i++) {
-		trace_seq_printf(s, " %s=", args[i].name);
-		if (!args[i].type->print(s, data + args[i].offset, field))
-			return -ENOMEM;
+		struct probe_arg *a = args + i;
+
+		trace_seq_printf(s, " %s=", a->name);
+		if (likely(!a->count)) {
+			if (!a->type->print(s, data + a->offset, field))
+				return -ENOMEM;
+			continue;
+		}
+		trace_seq_putc(s, '{');
+		p = data + a->offset;
+		for (j = 0; j < a->count; j++) {
+			if (!a->type->print(s, p, field))
+				return -ENOMEM;
+			trace_seq_putc(s, j == a->count - 1 ? '}' : ',');
+			p += a->type->size;
+		}
 	}
 	return 0;
 }

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 12/16] tracing: probeevent: Add array type support
  2018-04-25 12:21 ` [PATCH v7 12/16] tracing: probeevent: Add array type support mhiramat
@ 2018-04-25 12:21   ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-04-25 12:21 UTC (permalink / raw)


Add array type support for probe events.
This allows user to get arraied types from memory address.
The array type syntax is

	TYPE[N]

Where TYPE is one of types (u8/16/32/64,s8/16/32/64,
x8/16/32/64, symbol, string) and N is a fixed value less
than 64.

The string array type is a bit different from other types. For
other base types, <base-type>[1] is equal to <base-type>
(e.g. +0(%di):x32[1] is same as +0(%di):x32.) But string[1] is not
equal to string. The string type itself represents "char array",
but string array type represents "char * array". So, for example,
+0(%di):string[1] is equal to +0(+0(%di)):string.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v6:
  - Fix to add escaping backslash to a brace for syntax
    in README file.
 Changes in v4:
  - Fix to use calculated size correctly for field definition.
    (Thank you Namhyung!)
 Changes in v2:
  - Add array description in README file
  - Fix to init s3 code out of loop.
  - Fix to proceed code when the last code is OP_ARRAY.
  - Add string array type and bitfield array type.
---
 Documentation/trace/kprobetrace.rst |   11 +++
 kernel/trace/trace.c                |    3 +
 kernel/trace/trace_probe.c          |  130 +++++++++++++++++++++++++++--------
 kernel/trace/trace_probe.h          |   14 ++++
 kernel/trace/trace_probe_tmpl.h     |   63 +++++++++++++++--
 5 files changed, 181 insertions(+), 40 deletions(-)

diff --git a/Documentation/trace/kprobetrace.rst b/Documentation/trace/kprobetrace.rst
index 30eb37391064..b9e9198ea95d 100644
--- a/Documentation/trace/kprobetrace.rst
+++ b/Documentation/trace/kprobetrace.rst
@@ -66,9 +66,20 @@ respectively. 'x' prefix implies it is unsigned. Traced arguments are shown
 in decimal ('s' and 'u') or hexadecimal ('x'). Without type casting, 'x32'
 or 'x64' is used depends on the architecture (e.g. x86-32 uses x32, and
 x86-64 uses x64).
+These value types can be an array. To record array data, you can add '[N]'
+(where N is a fixed number, less than 64) to the base type.
+E.g. 'x16[4]' means an array of x16 (2bytes hex) with 4 elements.
+Note that the array can be applied to memory type fetchargs, you can not
+apply it to registers/stack-entries etc. (for example, '$stack1:x8[8]' is
+wrong, but '+8($stack):x8[8]' is OK.)
 String type is a special type, which fetches a "null-terminated" string from
 kernel space. This means it will fail and store NULL if the string container
 has been paged out.
+The string array type is a bit different from other types. For other base
+types, <base-type>[1] is equal to <base-type> (e.g. +0(%di):x32[1] is same
+as +0(%di):x32.) But string[1] is not equal to string. The string type itself
+represents "char array", but string array type represents "char * array".
+So, for example, +0(%di):string[1] is equal to +0(+0(%di)):string.
 Bitfield is another special type, which takes 3 parameters, bit-width, bit-
 offset, and container-size (usually 32). The syntax is::
 
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 7add9bfdff76..f34d026689c7 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4626,7 +4626,8 @@ static const char readme_msg[] =
 	"\t           $stack<index>, $stack, $retval, $comm\n"
 #endif
 	"\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
-	"\t           b<bit-width>@<bit-offset>/<container-size>\n"
+	"\t           b<bit-width>@<bit-offset>/<container-size>,\n"
+	"\t           <type>\\[<array-size>\\]\n"
 #endif
 	"  events/\t\t- Directory containing all trace event subsystems:\n"
 	"      enable\t\t- Write 0/1 to enable/disable tracing of all events\n"
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 9458800f394a..0e185050e492 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -363,9 +363,9 @@ static int __parse_bitfield_probe_arg(const char *bf,
 int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 		struct probe_arg *parg, unsigned int flags)
 {
-	struct fetch_insn *code, *tmp = NULL;
-	const char *t;
-	int ret;
+	struct fetch_insn *code, *scode, *tmp = NULL;
+	char *t, *t2;
+	int ret, len;
 
 	if (strlen(arg) > MAX_ARGSTR_LEN) {
 		pr_info("Argument is too long.: %s\n",  arg);
@@ -376,24 +376,42 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 		pr_info("Failed to allocate memory for command '%s'.\n", arg);
 		return -ENOMEM;
 	}
-	t = strchr(parg->comm, ':');
+	t = strchr(arg, ':');
 	if (t) {
-		arg[t - parg->comm] = '\0';
-		t++;
+		*t = '\0';
+		t2 = strchr(++t, '[');
+		if (t2) {
+			*t2 = '\0';
+			parg->count = simple_strtoul(t2 + 1, &t2, 0);
+			if (strcmp(t2, "]") || parg->count == 0)
+				return -EINVAL;
+			if (parg->count > MAX_ARRAY_LEN)
+				return -E2BIG;
+		}
 	}
 	/*
 	 * The default type of $comm should be "string", and it can't be
 	 * dereferenced.
 	 */
 	if (!t && strcmp(arg, "$comm") == 0)
-		t = "string";
-	parg->type = find_fetch_type(t);
+		parg->type = find_fetch_type("string");
+	else
+		parg->type = find_fetch_type(t);
 	if (!parg->type) {
 		pr_info("Unsupported type: %s\n", t);
 		return -EINVAL;
 	}
 	parg->offset = *size;
-	*size += parg->type->size;
+	*size += parg->type->size * (parg->count ?: 1);
+
+	if (parg->count) {
+		len = strlen(parg->type->fmttype) + 6;
+		parg->fmt = kmalloc(len, GFP_KERNEL);
+		if (!parg->fmt)
+			return -ENOMEM;
+		snprintf(parg->fmt, len, "%s[%d]", parg->type->fmttype,
+			 parg->count);
+	}
 
 	code = tmp = kzalloc(sizeof(*code) * FETCH_INSN_MAX, GFP_KERNEL);
 	if (!code)
@@ -413,10 +431,20 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 			ret = -EINVAL;
 			goto fail;
 		}
-		/* Since IMM or COMM must be the 1st insn, this is safe */
-		if (code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM)
+		if (code->op != FETCH_OP_DEREF || parg->count) {
+			/*
+			 * IMM and COMM is pointing actual address, those must
+			 * be kept, and if parg->count != 0, this is an array
+			 * of string pointers instead of string address itself.
+			 */
 			code++;
+			if (code->op != FETCH_OP_NOP) {
+				ret = -E2BIG;
+				goto fail;
+			}
+		}
 		code->op = FETCH_OP_ST_STRING;	/* In DEREF case, replace it */
+		code->size = parg->type->size;
 		parg->dynamic = true;
 	} else if (code->op == FETCH_OP_DEREF) {
 		code->op = FETCH_OP_ST_MEM;
@@ -430,12 +458,29 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
 		code->op = FETCH_OP_ST_RAW;
 		code->size = parg->type->size;
 	}
+	scode = code;
 	/* Modify operation */
 	if (t != NULL) {
 		ret = __parse_bitfield_probe_arg(t, parg->type, &code);
 		if (ret)
 			goto fail;
 	}
+	/* Loop(Array) operation */
+	if (parg->count) {
+		if (scode->op != FETCH_OP_ST_MEM &&
+		    scode->op != FETCH_OP_ST_STRING) {
+			pr_info("array only accepts memory or address\n");
+			ret = -EINVAL;
+			goto fail;
+		}
+		code++;
+		if (code->op != FETCH_OP_NOP) {
+			ret = -E2BIG;
+			goto fail;
+		}
+		code->op = FETCH_OP_LP_ARRAY;
+		code->param = parg->count;
+	}
 	code++;
 	code->op = FETCH_OP_END;
 
@@ -474,14 +519,17 @@ void traceprobe_free_probe_arg(struct probe_arg *arg)
 	kfree(arg->code);
 	kfree(arg->name);
 	kfree(arg->comm);
+	kfree(arg->fmt);
 }
 
+/* When len=0, we just calculate the needed length */
+#define LEN_OR_ZERO (len ? len - pos : 0)
 static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
 			   bool is_return)
 {
-	int i;
+	struct probe_arg *parg;
+	int i, j;
 	int pos = 0;
-
 	const char *fmt, *arg;
 
 	if (!is_return) {
@@ -492,33 +540,49 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
 		arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP;
 	}
 
-	/* When len=0, we just calculate the needed length */
-#define LEN_OR_ZERO (len ? len - pos : 0)
-
 	pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt);
 
 	for (i = 0; i < tp->nr_args; i++) {
-		pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%s",
-				tp->args[i].name, tp->args[i].type->fmt);
+		parg = tp->args + i;
+		pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=", parg->name);
+		if (parg->count) {
+			pos += snprintf(buf + pos, LEN_OR_ZERO, "{%s",
+					parg->type->fmt);
+			for (j = 1; j < parg->count; j++)
+				pos += snprintf(buf + pos, LEN_OR_ZERO, ",%s",
+						parg->type->fmt);
+			pos += snprintf(buf + pos, LEN_OR_ZERO, "}");
+		} else
+			pos += snprintf(buf + pos, LEN_OR_ZERO, "%s",
+					parg->type->fmt);
 	}
 
 	pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg);
 
 	for (i = 0; i < tp->nr_args; i++) {
-		if (strcmp(tp->args[i].type->name, "string") == 0)
+		parg = tp->args + i;
+		if (parg->count) {
+			if (strcmp(parg->type->name, "string") == 0)
+				fmt = ", __get_str(%s[%d])";
+			else
+				fmt = ", REC->%s[%d]";
+			for (j = 0; j < parg->count; j++)
+				pos += snprintf(buf + pos, LEN_OR_ZERO,
+						fmt, parg->name, j);
+		} else {
+			if (strcmp(parg->type->name, "string") == 0)
+				fmt = ", __get_str(%s)";
+			else
+				fmt = ", REC->%s";
 			pos += snprintf(buf + pos, LEN_OR_ZERO,
-					", __get_str(%s)",
-					tp->args[i].name);
-		else
-			pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s",
-					tp->args[i].name);
+					fmt, parg->name);
+		}
 	}
 
-#undef LEN_OR_ZERO
-
 	/* return the length of print_fmt */
 	return pos;
 }
+#undef LEN_OR_ZERO
 
 int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return)
 {
@@ -546,11 +610,15 @@ int traceprobe_define_arg_fields(struct trace_event_call *event_call,
 	/* Set argument names as fields */
 	for (i = 0; i < tp->nr_args; i++) {
 		struct probe_arg *parg = &tp->args[i];
-
-		ret = trace_define_field(event_call, parg->type->fmttype,
-					 parg->name,
-					 offset + parg->offset,
-					 parg->type->size,
+		const char *fmt = parg->type->fmttype;
+		int size = parg->type->size;
+
+		if (parg->fmt)
+			fmt = parg->fmt;
+		if (parg->count)
+			size *= parg->count;
+		ret = trace_define_field(event_call, fmt, parg->name,
+					 offset + parg->offset, size,
 					 parg->type->is_signed,
 					 FILTER_OTHER);
 		if (ret)
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index ff91faf70887..d256a19ee6d1 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -43,6 +43,7 @@
 
 #define MAX_TRACE_ARGS		128
 #define MAX_ARGSTR_LEN		63
+#define MAX_ARRAY_LEN		64
 #define MAX_STRING_SIZE		PATH_MAX
 
 /* Reserved field names */
@@ -78,6 +79,14 @@ static nokprobe_inline void *get_loc_data(u32 *dl, void *ent)
 	return (u8 *)ent + get_loc_offs(*dl);
 }
 
+static nokprobe_inline u32 update_data_loc(u32 loc, int consumed)
+{
+	u32 maxlen = get_loc_len(loc);
+	u32 offset = get_loc_offs(loc);
+
+	return make_data_loc(maxlen - consumed, offset + consumed);
+}
+
 /* Printing function type */
 typedef int (*print_type_func_t)(struct trace_seq *, void *, void *);
 
@@ -100,6 +109,8 @@ enum fetch_op {
 	FETCH_OP_ST_STRING,	/* String: .offset, .size */
 	// Stage 4 (modify) op
 	FETCH_OP_MOD_BF,	/* Bitfield: .basesize, .lshift, .rshift */
+	// Stage 5 (loop) op
+	FETCH_OP_LP_ARRAY,	/* Array: .param = loop count */
 	FETCH_OP_END,
 };
 
@@ -189,6 +200,7 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(symbol);
 	_ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, atype)
 
 #define ASSIGN_FETCH_TYPE_END {}
+#define MAX_ARRAY_LEN	64
 
 #ifdef CONFIG_KPROBE_EVENTS
 bool trace_kprobe_on_func_entry(struct trace_event_call *call);
@@ -209,8 +221,10 @@ struct probe_arg {
 	struct fetch_insn	*code;
 	bool			dynamic;/* Dynamic array (string) is used */
 	unsigned int		offset;	/* Offset from argument entry */
+	unsigned int		count;	/* Array count */
 	const char		*name;	/* Name of this argument */
 	const char		*comm;	/* Command of this argument */
+	char			*fmt;	/* Format string if needed */
 	const struct fetch_type	*type;	/* Type of this argument */
 };
 
diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmpl.h
index b4075f3e3a29..5c56afc17cf8 100644
--- a/kernel/trace/trace_probe_tmpl.h
+++ b/kernel/trace/trace_probe_tmpl.h
@@ -67,10 +67,15 @@ static nokprobe_inline int
 process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
 			   void *dest, void *base)
 {
-	int ret = 0;
+	struct fetch_insn *s3 = NULL;
+	int total = 0, ret = 0, i = 0;
+	u32 loc = 0;
+	unsigned long lval = val;
 
+stage2:
 	/* 2nd stage: dereference memory if needed */
 	while (code->op == FETCH_OP_DEREF) {
+		lval = val;
 		ret = probe_mem_read(&val, (void *)val + code->offset,
 					sizeof(val));
 		if (ret)
@@ -78,11 +83,15 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
 		code++;
 	}
 
+	s3 = code;
+stage3:
 	/* 3rd stage: store value to buffer */
 	if (unlikely(!dest)) {
-		if (code->op == FETCH_OP_ST_STRING)
-			return fetch_store_strlen(val + code->offset);
-		else
+		if (code->op == FETCH_OP_ST_STRING) {
+			ret += fetch_store_strlen(val + code->offset);
+			code++;
+			goto array;
+		} else
 			return -EILSEQ;
 	}
 
@@ -94,6 +103,7 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
 		probe_mem_read(dest, (void *)val + code->offset, code->size);
 		break;
 	case FETCH_OP_ST_STRING:
+		loc = *(u32 *)dest;
 		ret = fetch_store_string(val + code->offset, dest, base);
 		break;
 	default:
@@ -107,6 +117,29 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
 		code++;
 	}
 
+array:
+	/* the last stage: Loop on array */
+	if (code->op == FETCH_OP_LP_ARRAY) {
+		total += ret;
+		if (++i < code->param) {
+			code = s3;
+			if (s3->op != FETCH_OP_ST_STRING) {
+				dest += s3->size;
+				val += s3->size;
+				goto stage3;
+			}
+			code--;
+			val = lval + sizeof(char *);
+			if (dest) {
+				dest += sizeof(u32);
+				*(u32 *)dest = update_data_loc(loc, ret);
+			}
+			goto stage2;
+		}
+		code++;
+		ret = total;
+	}
+
 	return code->op == FETCH_OP_END ? ret : -EILSEQ;
 }
 
@@ -158,12 +191,26 @@ static inline int
 print_probe_args(struct trace_seq *s, struct probe_arg *args, int nr_args,
 		 u8 *data, void *field)
 {
-	int i;
+	void *p;
+	int i, j;
 
 	for (i = 0; i < nr_args; i++) {
-		trace_seq_printf(s, " %s=", args[i].name);
-		if (!args[i].type->print(s, data + args[i].offset, field))
-			return -ENOMEM;
+		struct probe_arg *a = args + i;
+
+		trace_seq_printf(s, " %s=", a->name);
+		if (likely(!a->count)) {
+			if (!a->type->print(s, data + a->offset, field))
+				return -ENOMEM;
+			continue;
+		}
+		trace_seq_putc(s, '{');
+		p = data + a->offset;
+		for (j = 0; j < a->count; j++) {
+			if (!a->type->print(s, p, field))
+				return -ENOMEM;
+			trace_seq_putc(s, j == a->count - 1 ? '}' : ',');
+			p += a->type->size;
+		}
 	}
 	return 0;
 }

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 13/16] selftests: ftrace: Add a testcase for symbol type
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
                   ` (12 preceding siblings ...)
  2018-04-25 12:21 ` [PATCH v7 12/16] tracing: probeevent: Add array type support mhiramat
@ 2018-04-25 12:22 ` mhiramat
  2018-04-25 12:22   ` Masami Hiramatsu
  2018-04-25 12:22 ` [PATCH v7 14/16] selftests: ftrace: Add a testcase for $argN with kprobe_event mhiramat
                   ` (5 subsequent siblings)
  19 siblings, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-04-25 12:22 UTC (permalink / raw)


Add a testcase for symbol type with kprobe event.
This tests good/bad syntax combinations and also
the traced data.
If the kernel doesn't support symbol type, it skips
the test as UNSUPPORTED.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v3:
  - Use IP/PC register to test the symbol type
---
 .../ftrace/test.d/kprobe/kprobe_args_symbol.tc     |   77 ++++++++++++++++++++
 1 file changed, 77 insertions(+)
 create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc

diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc
new file mode 100644
index 000000000000..20a8664a838b
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc
@@ -0,0 +1,77 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Kprobe event argument symbol type
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+grep -qe "type:.* symbol" README || exit_unsupported # version issue
+
+echo 0 > events/enable
+echo > kprobe_events
+
+PROBEFUNC="vfs_read"
+GOODREG=
+BADREG=
+REG=
+GOODSYM="_sdata"
+if ! grep -qw ${GOODSYM} /proc/kallsyms ; then
+  GOODSYM=$PROBEFUNC
+fi
+
+case `uname -m` in
+x86_64|i[3456]86)
+  GOODREG=%ax
+  BADREG=%ex
+  REG=%ip
+;;
+aarch64)
+  GOODREG=%x0
+  BADREG=%ax
+  REG=%pc
+;;
+arm*)
+  GOODREG=%r0
+  BADREG=%ax
+  REG=%pc
+;;
+*)
+  echo "Please implement other architecture here"
+  exit_untested
+esac
+
+test_goodarg() # Good-args
+{
+  while [ "$1" ]; do
+    echo "p ${PROBEFUNC} $1" > kprobe_events
+    shift 1
+  done;
+}
+
+test_badarg() # Bad-args
+{
+  while [ "$1" ]; do
+    ! echo "p ${PROBEFUNC} $1" > kprobe_events
+    shift 1
+  done;
+}
+
+echo > kprobe_events
+
+: "Symbol type"
+test_goodarg "${GOODREG}:symbol" "@${GOODSYM}:symbol" "@${GOODSYM}+10:symbol" \
+	 "\$stack0:symbol" "+0(\$stack):symbol"
+test_badarg "\$comm:symbol"
+
+: "Retval with symbol type"
+echo "r ${PROBEFUNC} \$retval:symbol" > kprobe_events
+
+echo > kprobe_events
+
+: "Test get symbol"
+echo "p:testprobe create_trace_kprobe ${REG}:symbol" > kprobe_events
+echo 1 > events/kprobes/testprobe/enable
+! echo test >> kprobe_events
+tail -n 1 trace | grep -q "arg1=create_trace_kprobe"
+
+echo 0 > events/enable
+echo > kprobe_events

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 13/16] selftests: ftrace: Add a testcase for symbol type
  2018-04-25 12:22 ` [PATCH v7 13/16] selftests: ftrace: Add a testcase for symbol type mhiramat
@ 2018-04-25 12:22   ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-04-25 12:22 UTC (permalink / raw)


Add a testcase for symbol type with kprobe event.
This tests good/bad syntax combinations and also
the traced data.
If the kernel doesn't support symbol type, it skips
the test as UNSUPPORTED.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v3:
  - Use IP/PC register to test the symbol type
---
 .../ftrace/test.d/kprobe/kprobe_args_symbol.tc     |   77 ++++++++++++++++++++
 1 file changed, 77 insertions(+)
 create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc

diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc
new file mode 100644
index 000000000000..20a8664a838b
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc
@@ -0,0 +1,77 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Kprobe event argument symbol type
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+grep -qe "type:.* symbol" README || exit_unsupported # version issue
+
+echo 0 > events/enable
+echo > kprobe_events
+
+PROBEFUNC="vfs_read"
+GOODREG=
+BADREG=
+REG=
+GOODSYM="_sdata"
+if ! grep -qw ${GOODSYM} /proc/kallsyms ; then
+  GOODSYM=$PROBEFUNC
+fi
+
+case `uname -m` in
+x86_64|i[3456]86)
+  GOODREG=%ax
+  BADREG=%ex
+  REG=%ip
+;;
+aarch64)
+  GOODREG=%x0
+  BADREG=%ax
+  REG=%pc
+;;
+arm*)
+  GOODREG=%r0
+  BADREG=%ax
+  REG=%pc
+;;
+*)
+  echo "Please implement other architecture here"
+  exit_untested
+esac
+
+test_goodarg() # Good-args
+{
+  while [ "$1" ]; do
+    echo "p ${PROBEFUNC} $1" > kprobe_events
+    shift 1
+  done;
+}
+
+test_badarg() # Bad-args
+{
+  while [ "$1" ]; do
+    ! echo "p ${PROBEFUNC} $1" > kprobe_events
+    shift 1
+  done;
+}
+
+echo > kprobe_events
+
+: "Symbol type"
+test_goodarg "${GOODREG}:symbol" "@${GOODSYM}:symbol" "@${GOODSYM}+10:symbol" \
+	 "\$stack0:symbol" "+0(\$stack):symbol"
+test_badarg "\$comm:symbol"
+
+: "Retval with symbol type"
+echo "r ${PROBEFUNC} \$retval:symbol" > kprobe_events
+
+echo > kprobe_events
+
+: "Test get symbol"
+echo "p:testprobe create_trace_kprobe ${REG}:symbol" > kprobe_events
+echo 1 > events/kprobes/testprobe/enable
+! echo test >> kprobe_events
+tail -n 1 trace | grep -q "arg1=create_trace_kprobe"
+
+echo 0 > events/enable
+echo > kprobe_events

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 14/16] selftests: ftrace: Add a testcase for $argN with kprobe_event
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
                   ` (13 preceding siblings ...)
  2018-04-25 12:22 ` [PATCH v7 13/16] selftests: ftrace: Add a testcase for symbol type mhiramat
@ 2018-04-25 12:22 ` mhiramat
  2018-04-25 12:22   ` Masami Hiramatsu
  2018-04-25 12:23 ` [PATCH v7 15/16] selftests: ftrace: Add a testcase for array type " mhiramat
                   ` (4 subsequent siblings)
  19 siblings, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-04-25 12:22 UTC (permalink / raw)


Add a testcase for $argN with kprobe event.
This tests whether the traced data is correct or not.
If the kernel doesn't support $argN (depends on arch),
it skips the test as UNSUPPORTED.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v5:
  - Fix description. (Thanks Namhyung!)
---
 .../ftrace/test.d/kprobe/kprobe_args_argN.tc       |   25 ++++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc

diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc
new file mode 100644
index 000000000000..d5c5c8c3a51e
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc
@@ -0,0 +1,25 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Kprobe event argN argument
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+grep -q "arg<N>" README || exit_unsupported # version issue
+
+echo 0 > events/enable
+echo > kprobe_events
+
+: "Test bad pattern : arg0 is not allowed"
+! echo 'p:testprobe create_trace_kprobe $arg0' > kprobe_events
+
+: "Test get argument"
+echo 'p:testprobe create_trace_kprobe $arg1' > kprobe_events
+echo 1 > events/kprobes/testprobe/enable
+! echo test >> kprobe_events
+tail -n 1 trace | grep -qe "testprobe.* arg1=0x1"
+
+! echo test test test >> kprobe_events
+tail -n 1 trace | grep -qe "testprobe.* arg1=0x3"
+
+echo 0 > events/enable
+echo > kprobe_events

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 14/16] selftests: ftrace: Add a testcase for $argN with kprobe_event
  2018-04-25 12:22 ` [PATCH v7 14/16] selftests: ftrace: Add a testcase for $argN with kprobe_event mhiramat
@ 2018-04-25 12:22   ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-04-25 12:22 UTC (permalink / raw)


Add a testcase for $argN with kprobe event.
This tests whether the traced data is correct or not.
If the kernel doesn't support $argN (depends on arch),
it skips the test as UNSUPPORTED.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v5:
  - Fix description. (Thanks Namhyung!)
---
 .../ftrace/test.d/kprobe/kprobe_args_argN.tc       |   25 ++++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc

diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc
new file mode 100644
index 000000000000..d5c5c8c3a51e
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc
@@ -0,0 +1,25 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Kprobe event argN argument
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+grep -q "arg<N>" README || exit_unsupported # version issue
+
+echo 0 > events/enable
+echo > kprobe_events
+
+: "Test bad pattern : arg0 is not allowed"
+! echo 'p:testprobe create_trace_kprobe $arg0' > kprobe_events
+
+: "Test get argument"
+echo 'p:testprobe create_trace_kprobe $arg1' > kprobe_events
+echo 1 > events/kprobes/testprobe/enable
+! echo test >> kprobe_events
+tail -n 1 trace | grep -qe "testprobe.* arg1=0x1"
+
+! echo test test test >> kprobe_events
+tail -n 1 trace | grep -qe "testprobe.* arg1=0x3"
+
+echo 0 > events/enable
+echo > kprobe_events

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 15/16] selftests: ftrace: Add a testcase for array type with kprobe_event
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
                   ` (14 preceding siblings ...)
  2018-04-25 12:22 ` [PATCH v7 14/16] selftests: ftrace: Add a testcase for $argN with kprobe_event mhiramat
@ 2018-04-25 12:23 ` mhiramat
  2018-04-25 12:23   ` Masami Hiramatsu
  2018-04-25 12:23 ` [PATCH v7 16/16] perf-probe: Add array argument support mhiramat
                   ` (3 subsequent siblings)
  19 siblings, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-04-25 12:23 UTC (permalink / raw)


Add a testcase for array type with kprobe event.
This tests good/bad syntax combinations and also
the traced data is correct in several way.
If the kernel doesn't support array type, it skips
the test as UNSUPPORTED.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v7:
  - Fix README test.
---
 .../ftrace/test.d/kprobe/kprobe_args_array.tc      |   92 ++++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc

diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc
new file mode 100644
index 000000000000..7a3819fc1c31
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc
@@ -0,0 +1,92 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Kprobe event array argument
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+grep -q '<type>\\\[<array-size>\\\]' README || exit_unsupported # version issue
+
+GOODSYM="_sdata"
+if ! grep -qw ${GOODSYM} /proc/kallsyms ; then
+  GOODSYM="create_trace_kprobe"
+fi
+case `uname -m` in
+x86_64)
+  ARG2=%si
+  OFFS=8
+  BITS=64
+;;
+i[3456]86)
+  ARG2=%cx
+  OFFS=4
+  BITS=32
+;;
+aarch64)
+  ARG2=%x1
+  OFFS=8
+  BITS=64
+;;
+arm*)
+  ARG2=%r1
+  OFFS=4
+  BITS=32
+;;
+*)
+  echo "Please implement other architecture here"
+  exit_untested
+esac
+
+create_testprobe() { # args
+  echo "p:testprobe create_trace_kprobe $*" > kprobe_events
+}
+
+check_field() { # grep-pattern
+  grep -e "$*" events/kprobes/testprobe/format
+}
+
+echo 0 > events/enable
+echo > kprobe_events
+
+: "Syntax test"
+create_testprobe "+0(${ARG2}):x8[1] +0(${ARG2}):s16[1] +0(${ARG2}):u32[1]"
+check_field "field:u8 arg1\[1\];.*size:1;"
+check_field "field:s16 arg2\[1\];.*size:2;"
+check_field "field:u32 arg3\[1\];.*size:4;"
+create_testprobe "+0(${ARG2}):x64[1] +0(${ARG2}):symbol[1]"
+check_field "field:u64 arg1\[1\];.*size:8;"
+check_field "field:u${BITS} arg2\[1\];.*size:${OFFS};"
+create_testprobe "+0(${ARG2}):b2 at 3/8[1] +0(${ARG2}):string[1]"
+check_field "field:u8 arg1\[1\];.*size:1;"
+check_field "field:__data_loc char\[\]\[1\] arg2;.*size:4;"
+create_testprobe "+0(${ARG2}):x8[64] @${GOODSYM}:x8[4]"
+check_field "field:u8 arg1\[64\];.*size:64;"
+check_field "field:u8 arg2\[4\];.*size:4;"
+
+! create_testprobe "${ARG2}:x8[1]" # Can not use array type on register
+! create_testprobe "\$comm:x8[1]" # Can not use array type on \$comm
+! create_testprobe "\$comm:string[1]" # No, even if it is string array
+! create_testprobe "+0(${ARG2}):x64[0]" # array size >= 1
+! create_testprobe "+0(${ARG2}):x64[65]" # array size <= 64
+
+: "Test get argument (1)"
+create_testprobe "arg1=+0(${ARG2}):string[1]" > kprobe_events
+echo 1 > events/kprobes/testprobe/enable
+! echo test >> kprobe_events
+tail -n 1 trace | grep -qe "testprobe.* arg1={\"test\"}"
+echo 0 > events/kprobes/testprobe/enable
+
+: "Test get argument (2)"
+create_testprobe "arg1=+0(${ARG2}):string[3]" > kprobe_events
+echo 1 > events/kprobes/testprobe/enable
+! echo foo bar buzz >> kprobe_events
+tail -n 1 trace | grep -qe "testprobe.* arg1={\"foo\",\"bar\",\"buzz\"}"
+echo 0 > events/kprobes/testprobe/enable
+
+: "Test get argument (3)"
+create_testprobe "arg1=+0(+0(${ARG2})):u8[4]" > kprobe_events
+echo 1 > events/kprobes/testprobe/enable
+! echo 1234 >> kprobe_events
+tail -n 1 trace | grep -qe "testprobe.* arg1={49,50,51,52}" # ascii code
+echo 0 > events/kprobes/testprobe/enable
+
+echo > kprobe_events

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 15/16] selftests: ftrace: Add a testcase for array type with kprobe_event
  2018-04-25 12:23 ` [PATCH v7 15/16] selftests: ftrace: Add a testcase for array type " mhiramat
@ 2018-04-25 12:23   ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-04-25 12:23 UTC (permalink / raw)


Add a testcase for array type with kprobe event.
This tests good/bad syntax combinations and also
the traced data is correct in several way.
If the kernel doesn't support array type, it skips
the test as UNSUPPORTED.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v7:
  - Fix README test.
---
 .../ftrace/test.d/kprobe/kprobe_args_array.tc      |   92 ++++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc

diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc
new file mode 100644
index 000000000000..7a3819fc1c31
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc
@@ -0,0 +1,92 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Kprobe event array argument
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+grep -q '<type>\\\[<array-size>\\\]' README || exit_unsupported # version issue
+
+GOODSYM="_sdata"
+if ! grep -qw ${GOODSYM} /proc/kallsyms ; then
+  GOODSYM="create_trace_kprobe"
+fi
+case `uname -m` in
+x86_64)
+  ARG2=%si
+  OFFS=8
+  BITS=64
+;;
+i[3456]86)
+  ARG2=%cx
+  OFFS=4
+  BITS=32
+;;
+aarch64)
+  ARG2=%x1
+  OFFS=8
+  BITS=64
+;;
+arm*)
+  ARG2=%r1
+  OFFS=4
+  BITS=32
+;;
+*)
+  echo "Please implement other architecture here"
+  exit_untested
+esac
+
+create_testprobe() { # args
+  echo "p:testprobe create_trace_kprobe $*" > kprobe_events
+}
+
+check_field() { # grep-pattern
+  grep -e "$*" events/kprobes/testprobe/format
+}
+
+echo 0 > events/enable
+echo > kprobe_events
+
+: "Syntax test"
+create_testprobe "+0(${ARG2}):x8[1] +0(${ARG2}):s16[1] +0(${ARG2}):u32[1]"
+check_field "field:u8 arg1\[1\];.*size:1;"
+check_field "field:s16 arg2\[1\];.*size:2;"
+check_field "field:u32 arg3\[1\];.*size:4;"
+create_testprobe "+0(${ARG2}):x64[1] +0(${ARG2}):symbol[1]"
+check_field "field:u64 arg1\[1\];.*size:8;"
+check_field "field:u${BITS} arg2\[1\];.*size:${OFFS};"
+create_testprobe "+0(${ARG2}):b2 at 3/8[1] +0(${ARG2}):string[1]"
+check_field "field:u8 arg1\[1\];.*size:1;"
+check_field "field:__data_loc char\[\]\[1\] arg2;.*size:4;"
+create_testprobe "+0(${ARG2}):x8[64] @${GOODSYM}:x8[4]"
+check_field "field:u8 arg1\[64\];.*size:64;"
+check_field "field:u8 arg2\[4\];.*size:4;"
+
+! create_testprobe "${ARG2}:x8[1]" # Can not use array type on register
+! create_testprobe "\$comm:x8[1]" # Can not use array type on \$comm
+! create_testprobe "\$comm:string[1]" # No, even if it is string array
+! create_testprobe "+0(${ARG2}):x64[0]" # array size >= 1
+! create_testprobe "+0(${ARG2}):x64[65]" # array size <= 64
+
+: "Test get argument (1)"
+create_testprobe "arg1=+0(${ARG2}):string[1]" > kprobe_events
+echo 1 > events/kprobes/testprobe/enable
+! echo test >> kprobe_events
+tail -n 1 trace | grep -qe "testprobe.* arg1={\"test\"}"
+echo 0 > events/kprobes/testprobe/enable
+
+: "Test get argument (2)"
+create_testprobe "arg1=+0(${ARG2}):string[3]" > kprobe_events
+echo 1 > events/kprobes/testprobe/enable
+! echo foo bar buzz >> kprobe_events
+tail -n 1 trace | grep -qe "testprobe.* arg1={\"foo\",\"bar\",\"buzz\"}"
+echo 0 > events/kprobes/testprobe/enable
+
+: "Test get argument (3)"
+create_testprobe "arg1=+0(+0(${ARG2})):u8[4]" > kprobe_events
+echo 1 > events/kprobes/testprobe/enable
+! echo 1234 >> kprobe_events
+tail -n 1 trace | grep -qe "testprobe.* arg1={49,50,51,52}" # ascii code
+echo 0 > events/kprobes/testprobe/enable
+
+echo > kprobe_events

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 16/16] perf-probe: Add array argument support
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
                   ` (15 preceding siblings ...)
  2018-04-25 12:23 ` [PATCH v7 15/16] selftests: ftrace: Add a testcase for array type " mhiramat
@ 2018-04-25 12:23 ` mhiramat
  2018-04-25 12:23   ` Masami Hiramatsu
  2018-04-27  1:42 ` [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features rostedt
                   ` (2 subsequent siblings)
  19 siblings, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-04-25 12:23 UTC (permalink / raw)


Since kprobes events support an array argument, perf-probe
can also support dumping array now.
The syntax are

 <array-var>[<range>]
or
 <pointer-var>[<range>]

where the <range> is <start>..<end>. e.g. array[0..5].
This can also be available with string type. In this
case, the string array should be "char *array[]" or
"char **array_ptr".

Note that this feature is only available on the kernel which
supports array type. Users still can specify "type casting"
with array type on such kernel, but kernel does not accept it.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v7
  - Add type-casting description (and note) to documentation.
---
 tools/perf/Documentation/perf-probe.txt |   12 +++-
 tools/perf/util/probe-event.c           |   20 ++++++-
 tools/perf/util/probe-event.h           |    2 +
 tools/perf/util/probe-file.c            |    5 ++
 tools/perf/util/probe-file.h            |    1 
 tools/perf/util/probe-finder.c          |   95 ++++++++++++++++++-------------
 6 files changed, 91 insertions(+), 44 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index b6866a05edd2..1a4a6b3cdfa6 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -196,19 +196,23 @@ Each probe argument follows below syntax.
 
  [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE]
 
-'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.)
+'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]) or range (e.g. array[1..4], var->array[0..2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.)
 '$vars' and '$params' special arguments are also available for NAME, '$vars' is expanded to the local variables (including function parameters) which can access at given probe point. '$params' is expanded to only the function parameters.
-'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo (*). Currently, basic types (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal integers (x/x8/x16/x32/x64), signedness casting (u/s), "string" and bitfield are supported. (see TYPES for detail)
+'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo (*). Currently, basic types (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal integers (x/x8/x16/x32/x64), signedness casting (u/s), "string", bitfield and array types are supported. (see TYPE CASTING for detail)
 On x86 systems %REG is always the short form of the register: for example %AX. %RAX or %EAX is not valid.
 
-TYPES
------
+TYPE CASTING
+------------
 Basic types (u8/u16/u32/u64/s8/s16/s32/s64) and hexadecimal integers (x8/x16/x32/x64) are integer types. Prefix 's' and 'u' means those types are signed and unsigned respectively, and 'x' means that is shown in hexadecimal format. Traced arguments are shown in decimal (sNN/uNN) or hex (xNN). You can also use 's' or 'u' to specify only signedness and leave its size auto-detected by perf probe. Moreover, you can use 'x' to explicitly specify to be shown in hexadecimal (the size is also auto-detected).
 String type is a special type, which fetches a "null-terminated" string from kernel space. This means it will fail and store NULL if the string container has been paged out. You can specify 'string' type only for the local variable or structure member which is an array of or a pointer to 'char' or 'unsigned char' type.
 Bitfield is another special type, which takes 3 parameters, bit-width, bit-offset, and container-size (usually 32). The syntax is;
 
  b<bit-width>@<bit-offset>/<container-size>
 
+Array type is an extension of other types. User can put '[<array-size>]' next to the other types. For example 'x8[10]' means a 10 element array of 8bit hexadecimal integers.
+
+Note that some types may not be available on older kernel. In that case, kernel will reject it.
+
 LINE SYNTAX
 -----------
 Line range is described by following syntax.
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index e1dbc9821617..e07a1957c9cd 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1570,6 +1570,7 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
 {
 	char *tmp, *goodname;
 	struct perf_probe_arg_field **fieldp;
+	long end;
 
 	pr_debug("parsing arg: %s into ", str);
 
@@ -1617,7 +1618,18 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
 			str = tmp;
 			(*fieldp)->index = strtol(str + 1, &tmp, 0);
 			(*fieldp)->ref = true;
-			if (*tmp != ']' || tmp == str + 1) {
+			if (tmp[0] == '.' && tmp[1] == '.') { /* dump array */
+				end = strtol(tmp + 2, &tmp, 0);
+				if (end < (*fieldp)->index || *tmp != ']') {
+					semantic_error("Invalid array range\n");
+					return -EINVAL;
+				}
+				arg->length = end - (*fieldp)->index + 1;
+				if (tmp[1] != '\0') {
+					semantic_error("Array range must not follow anything.");
+					return -EINVAL;
+				}
+			} else if (*tmp != ']' || tmp == str + 1) {
 				semantic_error("Array index must be a"
 						" number.\n");
 				return -EINVAL;
@@ -2022,6 +2034,12 @@ static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
 	if (!err && arg->type)
 		err = strbuf_addf(buf, ":%s", arg->type);
 
+	if (!err && arg->length) {
+		if (!arg->type)
+			return -EINVAL;
+		err = strbuf_addf(buf, "[%d]", arg->length);
+	}
+
 	return err;
 }
 
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 45b14f020558..e5ca1bf33ee7 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -42,6 +42,7 @@ struct probe_trace_arg {
 	char				*name;	/* Argument name */
 	char				*value;	/* Base value */
 	char				*type;	/* Type name */
+	unsigned int			length;	/* Length of array */
 	struct probe_trace_arg_ref	*ref;	/* Referencing offset */
 };
 
@@ -79,6 +80,7 @@ struct perf_probe_arg {
 	char				*name;	/* Argument name */
 	char				*var;	/* Variable name */
 	char				*type;	/* Type name */
+	unsigned int			length;	/* Length of array */
 	struct perf_probe_arg_field	*field;	/* Structure fields */
 };
 
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 4ae1123c6794..a879fe8eede3 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -999,6 +999,7 @@ int probe_cache__show_all_caches(struct strfilter *filter)
 enum ftrace_readme {
 	FTRACE_README_PROBE_TYPE_X = 0,
 	FTRACE_README_KRETPROBE_OFFSET,
+	FTRACE_README_ARRAY_TYPE,
 	FTRACE_README_END,
 };
 
@@ -1010,6 +1011,8 @@ static struct {
 	[idx] = {.pattern = pat, .avail = false}
 	DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"),
 	DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"),
+	DEFINE_TYPE(FTRACE_README_ARRAY_TYPE,
+		    "*<type>\\\\\\[<array-size>\\\\\\]*"),
 };
 
 static bool scan_ftrace_readme(enum ftrace_readme type)
@@ -1057,6 +1060,8 @@ bool probe_type_is_available(enum probe_type type)
 		return false;
 	else if (type == PROBE_TYPE_X)
 		return scan_ftrace_readme(FTRACE_README_PROBE_TYPE_X);
+	else if (type == PROBE_TYPE_ARRAY)
+		return scan_ftrace_readme(FTRACE_README_ARRAY_TYPE);
 
 	return true;
 }
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index 63f29b1d22c1..654290b2fd9c 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -27,6 +27,7 @@ enum probe_type {
 	PROBE_TYPE_X,
 	PROBE_TYPE_STRING,
 	PROBE_TYPE_BITFIELD,
+	PROBE_TYPE_ARRAY,
 	PROBE_TYPE_END,
 };
 
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c37fbef1711d..a1df7926edfc 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -290,13 +290,52 @@ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
 	return ret2;
 }
 
+static int convert_variable_string_type(Dwarf_Die *vr_die, Dwarf_Die *type,
+					struct probe_trace_arg *tvar)
+{
+	struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
+	int ret;
+
+	ret = dwarf_tag(type);
+	if (ret != DW_TAG_pointer_type && ret != DW_TAG_array_type) {
+		pr_warning("Failed to cast into string: "
+			   "%s(%s) is not a pointer nor array.\n",
+			   dwarf_diename(vr_die), dwarf_diename(type));
+		return -EINVAL;
+	}
+	if (ret == DW_TAG_pointer_type && tvar->length == 0) {
+		while (*ref_ptr)
+			ref_ptr = &(*ref_ptr)->next;
+		/* Add new reference with offset +0 */
+		*ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref));
+		if (*ref_ptr == NULL) {
+			pr_warning("Out of memory error\n");
+			return -ENOMEM;
+		}
+	}
+	if (die_get_real_type(type, type) == NULL) {
+		pr_warning("Failed to get a type"
+			   " information.\n");
+		return -ENOENT;
+	}
+	if (!die_compare_name(type, "char") &&
+	    !die_compare_name(type, "unsigned char")) {
+		pr_warning("Failed to cast into string: "
+			   "%s is not (unsigned) char *.\n",
+			   dwarf_diename(vr_die));
+		return -EINVAL;
+	}
+	tvar->type = strdup("string");
+	return (tvar->type == NULL) ? -ENOMEM : 0;
+}
+
 #define BYTES_TO_BITS(nb)	((nb) * BITS_PER_LONG / sizeof(long))
 
 static int convert_variable_type(Dwarf_Die *vr_die,
 				 struct probe_trace_arg *tvar,
-				 const char *cast)
+				 struct perf_probe_arg *pvar)
 {
-	struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
+	const char *cast = pvar->type;
 	Dwarf_Die type;
 	char buf[16];
 	char sbuf[STRERR_BUFSIZE];
@@ -304,6 +343,12 @@ static int convert_variable_type(Dwarf_Die *vr_die,
 	int ret;
 	char prefix;
 
+	tvar->length = pvar->length;
+	if (tvar->length && !probe_type_is_available(PROBE_TYPE_ARRAY)) {
+		pr_warning("This kerneld doesn't support array type.\n");
+		return -ENOTSUP;
+	}
+
 	/* TODO: check all types */
 	if (cast && strcmp(cast, "string") != 0 && strcmp(cast, "x") != 0 &&
 	    strcmp(cast, "s") != 0 && strcmp(cast, "u") != 0) {
@@ -334,40 +379,8 @@ static int convert_variable_type(Dwarf_Die *vr_die,
 	pr_debug("%s type is %s.\n",
 		 dwarf_diename(vr_die), dwarf_diename(&type));
 
-	if (cast && strcmp(cast, "string") == 0) {	/* String type */
-		ret = dwarf_tag(&type);
-		if (ret != DW_TAG_pointer_type &&
-		    ret != DW_TAG_array_type) {
-			pr_warning("Failed to cast into string: "
-				   "%s(%s) is not a pointer nor array.\n",
-				   dwarf_diename(vr_die), dwarf_diename(&type));
-			return -EINVAL;
-		}
-		if (die_get_real_type(&type, &type) == NULL) {
-			pr_warning("Failed to get a type"
-				   " information.\n");
-			return -ENOENT;
-		}
-		if (ret == DW_TAG_pointer_type) {
-			while (*ref_ptr)
-				ref_ptr = &(*ref_ptr)->next;
-			/* Add new reference with offset +0 */
-			*ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref));
-			if (*ref_ptr == NULL) {
-				pr_warning("Out of memory error\n");
-				return -ENOMEM;
-			}
-		}
-		if (!die_compare_name(&type, "char") &&
-		    !die_compare_name(&type, "unsigned char")) {
-			pr_warning("Failed to cast into string: "
-				   "%s is not (unsigned) char *.\n",
-				   dwarf_diename(vr_die));
-			return -EINVAL;
-		}
-		tvar->type = strdup(cast);
-		return (tvar->type == NULL) ? -ENOMEM : 0;
-	}
+	if (cast && strcmp(cast, "string") == 0)	/* String type */
+		return convert_variable_string_type(vr_die, &type, tvar);
 
 	if (cast && (strcmp(cast, "u") == 0))
 		prefix = 'u';
@@ -381,9 +394,13 @@ static int convert_variable_type(Dwarf_Die *vr_die,
 			 probe_type_is_available(PROBE_TYPE_X) ? 'x' : 'u';
 
 	ret = dwarf_bytesize(&type);
-	if (ret <= 0)
-		/* No size ... try to use default type */
+	if (ret <= 0) { /* No size ... try to use default type */
+		if (tvar->length) {	/* But array can not be dumped */
+			pr_warning("Failed to convert array with unsupported type\n");
+			return -EINVAL;
+		}
 		return 0;
+	}
 	ret = BYTES_TO_BITS(ret);
 
 	/* Check the bitwidth */
@@ -559,7 +576,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
 		vr_die = &die_mem;
 	}
 	if (ret == 0)
-		ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type);
+		ret = convert_variable_type(vr_die, pf->tvar, pf->pvar);
 	/* *expr will be cached in libdw. Don't free it. */
 	return ret;
 }

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 16/16] perf-probe: Add array argument support
  2018-04-25 12:23 ` [PATCH v7 16/16] perf-probe: Add array argument support mhiramat
@ 2018-04-25 12:23   ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-04-25 12:23 UTC (permalink / raw)


Since kprobes events support an array argument, perf-probe
can also support dumping array now.
The syntax are

 <array-var>[<range>]
or
 <pointer-var>[<range>]

where the <range> is <start>..<end>. e.g. array[0..5].
This can also be available with string type. In this
case, the string array should be "char *array[]" or
"char **array_ptr".

Note that this feature is only available on the kernel which
supports array type. Users still can specify "type casting"
with array type on such kernel, but kernel does not accept it.

Signed-off-by: Masami Hiramatsu <mhiramat at kernel.org>
---
 Changes in v7
  - Add type-casting description (and note) to documentation.
---
 tools/perf/Documentation/perf-probe.txt |   12 +++-
 tools/perf/util/probe-event.c           |   20 ++++++-
 tools/perf/util/probe-event.h           |    2 +
 tools/perf/util/probe-file.c            |    5 ++
 tools/perf/util/probe-file.h            |    1 
 tools/perf/util/probe-finder.c          |   95 ++++++++++++++++++-------------
 6 files changed, 91 insertions(+), 44 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index b6866a05edd2..1a4a6b3cdfa6 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -196,19 +196,23 @@ Each probe argument follows below syntax.
 
  [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE]
 
-'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.)
+'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]) or range (e.g. array[1..4], var->array[0..2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.)
 '$vars' and '$params' special arguments are also available for NAME, '$vars' is expanded to the local variables (including function parameters) which can access at given probe point. '$params' is expanded to only the function parameters.
-'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo (*). Currently, basic types (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal integers (x/x8/x16/x32/x64), signedness casting (u/s), "string" and bitfield are supported. (see TYPES for detail)
+'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo (*). Currently, basic types (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal integers (x/x8/x16/x32/x64), signedness casting (u/s), "string", bitfield and array types are supported. (see TYPE CASTING for detail)
 On x86 systems %REG is always the short form of the register: for example %AX. %RAX or %EAX is not valid.
 
-TYPES
------
+TYPE CASTING
+------------
 Basic types (u8/u16/u32/u64/s8/s16/s32/s64) and hexadecimal integers (x8/x16/x32/x64) are integer types. Prefix 's' and 'u' means those types are signed and unsigned respectively, and 'x' means that is shown in hexadecimal format. Traced arguments are shown in decimal (sNN/uNN) or hex (xNN). You can also use 's' or 'u' to specify only signedness and leave its size auto-detected by perf probe. Moreover, you can use 'x' to explicitly specify to be shown in hexadecimal (the size is also auto-detected).
 String type is a special type, which fetches a "null-terminated" string from kernel space. This means it will fail and store NULL if the string container has been paged out. You can specify 'string' type only for the local variable or structure member which is an array of or a pointer to 'char' or 'unsigned char' type.
 Bitfield is another special type, which takes 3 parameters, bit-width, bit-offset, and container-size (usually 32). The syntax is;
 
  b<bit-width>@<bit-offset>/<container-size>
 
+Array type is an extension of other types. User can put '[<array-size>]' next to the other types. For example 'x8[10]' means a 10 element array of 8bit hexadecimal integers.
+
+Note that some types may not be available on older kernel. In that case, kernel will reject it.
+
 LINE SYNTAX
 -----------
 Line range is described by following syntax.
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index e1dbc9821617..e07a1957c9cd 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1570,6 +1570,7 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
 {
 	char *tmp, *goodname;
 	struct perf_probe_arg_field **fieldp;
+	long end;
 
 	pr_debug("parsing arg: %s into ", str);
 
@@ -1617,7 +1618,18 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
 			str = tmp;
 			(*fieldp)->index = strtol(str + 1, &tmp, 0);
 			(*fieldp)->ref = true;
-			if (*tmp != ']' || tmp == str + 1) {
+			if (tmp[0] == '.' && tmp[1] == '.') { /* dump array */
+				end = strtol(tmp + 2, &tmp, 0);
+				if (end < (*fieldp)->index || *tmp != ']') {
+					semantic_error("Invalid array range\n");
+					return -EINVAL;
+				}
+				arg->length = end - (*fieldp)->index + 1;
+				if (tmp[1] != '\0') {
+					semantic_error("Array range must not follow anything.");
+					return -EINVAL;
+				}
+			} else if (*tmp != ']' || tmp == str + 1) {
 				semantic_error("Array index must be a"
 						" number.\n");
 				return -EINVAL;
@@ -2022,6 +2034,12 @@ static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
 	if (!err && arg->type)
 		err = strbuf_addf(buf, ":%s", arg->type);
 
+	if (!err && arg->length) {
+		if (!arg->type)
+			return -EINVAL;
+		err = strbuf_addf(buf, "[%d]", arg->length);
+	}
+
 	return err;
 }
 
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 45b14f020558..e5ca1bf33ee7 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -42,6 +42,7 @@ struct probe_trace_arg {
 	char				*name;	/* Argument name */
 	char				*value;	/* Base value */
 	char				*type;	/* Type name */
+	unsigned int			length;	/* Length of array */
 	struct probe_trace_arg_ref	*ref;	/* Referencing offset */
 };
 
@@ -79,6 +80,7 @@ struct perf_probe_arg {
 	char				*name;	/* Argument name */
 	char				*var;	/* Variable name */
 	char				*type;	/* Type name */
+	unsigned int			length;	/* Length of array */
 	struct perf_probe_arg_field	*field;	/* Structure fields */
 };
 
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 4ae1123c6794..a879fe8eede3 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -999,6 +999,7 @@ int probe_cache__show_all_caches(struct strfilter *filter)
 enum ftrace_readme {
 	FTRACE_README_PROBE_TYPE_X = 0,
 	FTRACE_README_KRETPROBE_OFFSET,
+	FTRACE_README_ARRAY_TYPE,
 	FTRACE_README_END,
 };
 
@@ -1010,6 +1011,8 @@ static struct {
 	[idx] = {.pattern = pat, .avail = false}
 	DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"),
 	DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"),
+	DEFINE_TYPE(FTRACE_README_ARRAY_TYPE,
+		    "*<type>\\\\\\[<array-size>\\\\\\]*"),
 };
 
 static bool scan_ftrace_readme(enum ftrace_readme type)
@@ -1057,6 +1060,8 @@ bool probe_type_is_available(enum probe_type type)
 		return false;
 	else if (type == PROBE_TYPE_X)
 		return scan_ftrace_readme(FTRACE_README_PROBE_TYPE_X);
+	else if (type == PROBE_TYPE_ARRAY)
+		return scan_ftrace_readme(FTRACE_README_ARRAY_TYPE);
 
 	return true;
 }
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index 63f29b1d22c1..654290b2fd9c 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -27,6 +27,7 @@ enum probe_type {
 	PROBE_TYPE_X,
 	PROBE_TYPE_STRING,
 	PROBE_TYPE_BITFIELD,
+	PROBE_TYPE_ARRAY,
 	PROBE_TYPE_END,
 };
 
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c37fbef1711d..a1df7926edfc 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -290,13 +290,52 @@ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
 	return ret2;
 }
 
+static int convert_variable_string_type(Dwarf_Die *vr_die, Dwarf_Die *type,
+					struct probe_trace_arg *tvar)
+{
+	struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
+	int ret;
+
+	ret = dwarf_tag(type);
+	if (ret != DW_TAG_pointer_type && ret != DW_TAG_array_type) {
+		pr_warning("Failed to cast into string: "
+			   "%s(%s) is not a pointer nor array.\n",
+			   dwarf_diename(vr_die), dwarf_diename(type));
+		return -EINVAL;
+	}
+	if (ret == DW_TAG_pointer_type && tvar->length == 0) {
+		while (*ref_ptr)
+			ref_ptr = &(*ref_ptr)->next;
+		/* Add new reference with offset +0 */
+		*ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref));
+		if (*ref_ptr == NULL) {
+			pr_warning("Out of memory error\n");
+			return -ENOMEM;
+		}
+	}
+	if (die_get_real_type(type, type) == NULL) {
+		pr_warning("Failed to get a type"
+			   " information.\n");
+		return -ENOENT;
+	}
+	if (!die_compare_name(type, "char") &&
+	    !die_compare_name(type, "unsigned char")) {
+		pr_warning("Failed to cast into string: "
+			   "%s is not (unsigned) char *.\n",
+			   dwarf_diename(vr_die));
+		return -EINVAL;
+	}
+	tvar->type = strdup("string");
+	return (tvar->type == NULL) ? -ENOMEM : 0;
+}
+
 #define BYTES_TO_BITS(nb)	((nb) * BITS_PER_LONG / sizeof(long))
 
 static int convert_variable_type(Dwarf_Die *vr_die,
 				 struct probe_trace_arg *tvar,
-				 const char *cast)
+				 struct perf_probe_arg *pvar)
 {
-	struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
+	const char *cast = pvar->type;
 	Dwarf_Die type;
 	char buf[16];
 	char sbuf[STRERR_BUFSIZE];
@@ -304,6 +343,12 @@ static int convert_variable_type(Dwarf_Die *vr_die,
 	int ret;
 	char prefix;
 
+	tvar->length = pvar->length;
+	if (tvar->length && !probe_type_is_available(PROBE_TYPE_ARRAY)) {
+		pr_warning("This kerneld doesn't support array type.\n");
+		return -ENOTSUP;
+	}
+
 	/* TODO: check all types */
 	if (cast && strcmp(cast, "string") != 0 && strcmp(cast, "x") != 0 &&
 	    strcmp(cast, "s") != 0 && strcmp(cast, "u") != 0) {
@@ -334,40 +379,8 @@ static int convert_variable_type(Dwarf_Die *vr_die,
 	pr_debug("%s type is %s.\n",
 		 dwarf_diename(vr_die), dwarf_diename(&type));
 
-	if (cast && strcmp(cast, "string") == 0) {	/* String type */
-		ret = dwarf_tag(&type);
-		if (ret != DW_TAG_pointer_type &&
-		    ret != DW_TAG_array_type) {
-			pr_warning("Failed to cast into string: "
-				   "%s(%s) is not a pointer nor array.\n",
-				   dwarf_diename(vr_die), dwarf_diename(&type));
-			return -EINVAL;
-		}
-		if (die_get_real_type(&type, &type) == NULL) {
-			pr_warning("Failed to get a type"
-				   " information.\n");
-			return -ENOENT;
-		}
-		if (ret == DW_TAG_pointer_type) {
-			while (*ref_ptr)
-				ref_ptr = &(*ref_ptr)->next;
-			/* Add new reference with offset +0 */
-			*ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref));
-			if (*ref_ptr == NULL) {
-				pr_warning("Out of memory error\n");
-				return -ENOMEM;
-			}
-		}
-		if (!die_compare_name(&type, "char") &&
-		    !die_compare_name(&type, "unsigned char")) {
-			pr_warning("Failed to cast into string: "
-				   "%s is not (unsigned) char *.\n",
-				   dwarf_diename(vr_die));
-			return -EINVAL;
-		}
-		tvar->type = strdup(cast);
-		return (tvar->type == NULL) ? -ENOMEM : 0;
-	}
+	if (cast && strcmp(cast, "string") == 0)	/* String type */
+		return convert_variable_string_type(vr_die, &type, tvar);
 
 	if (cast && (strcmp(cast, "u") == 0))
 		prefix = 'u';
@@ -381,9 +394,13 @@ static int convert_variable_type(Dwarf_Die *vr_die,
 			 probe_type_is_available(PROBE_TYPE_X) ? 'x' : 'u';
 
 	ret = dwarf_bytesize(&type);
-	if (ret <= 0)
-		/* No size ... try to use default type */
+	if (ret <= 0) { /* No size ... try to use default type */
+		if (tvar->length) {	/* But array can not be dumped */
+			pr_warning("Failed to convert array with unsupported type\n");
+			return -EINVAL;
+		}
 		return 0;
+	}
 	ret = BYTES_TO_BITS(ret);
 
 	/* Check the bitwidth */
@@ -559,7 +576,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
 		vr_die = &die_mem;
 	}
 	if (ret == 0)
-		ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type);
+		ret = convert_variable_type(vr_die, pf->tvar, pf->pvar);
 	/* *expr will be cached in libdw. Don't free it. */
 	return ret;
 }

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
                   ` (16 preceding siblings ...)
  2018-04-25 12:23 ` [PATCH v7 16/16] perf-probe: Add array argument support mhiramat
@ 2018-04-27  1:42 ` rostedt
  2018-04-27  1:42   ` Steven Rostedt
  2018-05-03 22:11 ` rostedt
  2018-06-21 20:16 ` rostedt
  19 siblings, 1 reply; 72+ messages in thread
From: rostedt @ 2018-04-27  1:42 UTC (permalink / raw)


On Wed, 25 Apr 2018 21:16:06 +0900
Masami Hiramatsu <mhiramat at kernel.org> wrote:

> Hi,
> 
> This is the 7th version of the fetch-arg improvement series.
> This includes variable changes on fetcharg framework like,
> 
> - Add fetcharg testcases (syntax, argN, symbol, string and array)
>   and probepoint testcase.
> - Rewrite fetcharg framework with fetch_insn, switch-case based
>   instead of function pointer.
> - Add "symbol" type support, which shows symbol+offset instead of
>   address value.
> - Add "$argN" fetcharg, which fetches function parameters.
>   (currently only for x86-64)
> - Add array type support (including string arrary :) ) ,
>   which enables to get fixed length array from probe-events.
> - Add array type support for perf-probe, so that user can
>   dump partial array entries.
> 

Masami,

Thanks for posting this! I'm currently trying to get a set of patches
in the -rc releases, and this would be for 4.18 (or 5.0?), I'll try to
get some time next week to look at this.

Thanks!

-- Steve
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-04-27  1:42 ` [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features rostedt
@ 2018-04-27  1:42   ` Steven Rostedt
  0 siblings, 0 replies; 72+ messages in thread
From: Steven Rostedt @ 2018-04-27  1:42 UTC (permalink / raw)


On Wed, 25 Apr 2018 21:16:06 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> Hi,
> 
> This is the 7th version of the fetch-arg improvement series.
> This includes variable changes on fetcharg framework like,
> 
> - Add fetcharg testcases (syntax, argN, symbol, string and array)
>   and probepoint testcase.
> - Rewrite fetcharg framework with fetch_insn, switch-case based
>   instead of function pointer.
> - Add "symbol" type support, which shows symbol+offset instead of
>   address value.
> - Add "$argN" fetcharg, which fetches function parameters.
>   (currently only for x86-64)
> - Add array type support (including string arrary :) ) ,
>   which enables to get fixed length array from probe-events.
> - Add array type support for perf-probe, so that user can
>   dump partial array entries.
> 

Masami,

Thanks for posting this! I'm currently trying to get a set of patches
in the -rc releases, and this would be for 4.18 (or 5.0?), I'll try to
get some time next week to look at this.

Thanks!

-- Steve
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
                   ` (17 preceding siblings ...)
  2018-04-27  1:42 ` [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features rostedt
@ 2018-05-03 22:11 ` rostedt
  2018-05-03 22:11   ` Steven Rostedt
  2018-05-04 15:48   ` mhiramat
  2018-06-21 20:16 ` rostedt
  19 siblings, 2 replies; 72+ messages in thread
From: rostedt @ 2018-05-03 22:11 UTC (permalink / raw)


On Wed, 25 Apr 2018 21:16:06 +0900
Masami Hiramatsu <mhiramat at kernel.org> wrote:

> Hi,
> 
> This is the 7th version of the fetch-arg improvement series.
> This includes variable changes on fetcharg framework like,
> 
> - Add fetcharg testcases (syntax, argN, symbol, string and array)
>   and probepoint testcase.
> - Rewrite fetcharg framework with fetch_insn, switch-case based
>   instead of function pointer.
> - Add "symbol" type support, which shows symbol+offset instead of
>   address value.
> - Add "$argN" fetcharg, which fetches function parameters.
>   (currently only for x86-64)
> - Add array type support (including string arrary :) ) ,
>   which enables to get fixed length array from probe-events.
> - Add array type support for perf-probe, so that user can
>   dump partial array entries.
> 
> V6 is here:
>  https://lkml.org/lkml/2018/3/17/75
> 
> Changes from the v6 are here:
>  [6/16]  - Fix to return an error if failed to fetch string and
>         fill zero-length data_loc in error case.
>  [11/16] - Update document for restructured text.
>  [15/16] - Fix README test.
>  [16/16] - Add type-casting description (and note) to documentation.
> 
> And rebased on the latest Steve's ftrace/core branch.
> 

Hi Masami,

I skimmed through the patches and it they appear fine. I've applied
them and started playing a little.

I've been thinking my function based events, and thought instead I
would make them part of the kprobe infrastructure. Just have a slightly
different format, and instead of being p: or r: be f: And keep the
format I was suggesting.

What do you think?

Also, when looking at the kprobe code, I was looking at this function:

> /* Ftrace callback handler for kprobes -- called under preepmt disabed */
> void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
> 			   struct ftrace_ops *ops, struct pt_regs *regs)
> {
> 	struct kprobe *p;
> 	struct kprobe_ctlblk *kcb;
> 
> 	/* Preempt is disabled by ftrace */
> 	p = get_kprobe((kprobe_opcode_t *)ip);
> 	if (unlikely(!p) || kprobe_disabled(p))
> 		return;
> 
> 	kcb = get_kprobe_ctlblk();
> 	if (kprobe_running()) {
> 		kprobes_inc_nmissed_count(p);
> 	} else {
> 		unsigned long orig_ip = regs->ip;
> 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
> 		regs->ip = ip + sizeof(kprobe_opcode_t);
> 
> 		/* To emulate trap based kprobes, preempt_disable here */
> 		preempt_disable();
> 		__this_cpu_write(current_kprobe, p);
> 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> 			__skip_singlestep(p, regs, kcb, orig_ip);
> 			preempt_enable_no_resched();

This preemption disabling and enabling looks rather strange. Looking at
git blame, it appears this was added for jprobes. Can we remove it now
that jprobes is going away?

> 		}
> 		/*
> 		 * If pre_handler returns !0, it sets regs->ip and
> 		 * resets current kprobe, and keep preempt count +1.
> 		 */
> 	}
> }

-- Steve
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-03 22:11 ` rostedt
@ 2018-05-03 22:11   ` Steven Rostedt
  2018-05-04 15:48   ` mhiramat
  1 sibling, 0 replies; 72+ messages in thread
From: Steven Rostedt @ 2018-05-03 22:11 UTC (permalink / raw)


On Wed, 25 Apr 2018 21:16:06 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> Hi,
> 
> This is the 7th version of the fetch-arg improvement series.
> This includes variable changes on fetcharg framework like,
> 
> - Add fetcharg testcases (syntax, argN, symbol, string and array)
>   and probepoint testcase.
> - Rewrite fetcharg framework with fetch_insn, switch-case based
>   instead of function pointer.
> - Add "symbol" type support, which shows symbol+offset instead of
>   address value.
> - Add "$argN" fetcharg, which fetches function parameters.
>   (currently only for x86-64)
> - Add array type support (including string arrary :) ) ,
>   which enables to get fixed length array from probe-events.
> - Add array type support for perf-probe, so that user can
>   dump partial array entries.
> 
> V6 is here:
>  https://lkml.org/lkml/2018/3/17/75
> 
> Changes from the v6 are here:
>  [6/16]  - Fix to return an error if failed to fetch string and
>         fill zero-length data_loc in error case.
>  [11/16] - Update document for restructured text.
>  [15/16] - Fix README test.
>  [16/16] - Add type-casting description (and note) to documentation.
> 
> And rebased on the latest Steve's ftrace/core branch.
> 

Hi Masami,

I skimmed through the patches and it they appear fine. I've applied
them and started playing a little.

I've been thinking my function based events, and thought instead I
would make them part of the kprobe infrastructure. Just have a slightly
different format, and instead of being p: or r: be f: And keep the
format I was suggesting.

What do you think?

Also, when looking at the kprobe code, I was looking at this function:

> /* Ftrace callback handler for kprobes -- called under preepmt disabed */
> void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
> 			   struct ftrace_ops *ops, struct pt_regs *regs)
> {
> 	struct kprobe *p;
> 	struct kprobe_ctlblk *kcb;
> 
> 	/* Preempt is disabled by ftrace */
> 	p = get_kprobe((kprobe_opcode_t *)ip);
> 	if (unlikely(!p) || kprobe_disabled(p))
> 		return;
> 
> 	kcb = get_kprobe_ctlblk();
> 	if (kprobe_running()) {
> 		kprobes_inc_nmissed_count(p);
> 	} else {
> 		unsigned long orig_ip = regs->ip;
> 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
> 		regs->ip = ip + sizeof(kprobe_opcode_t);
> 
> 		/* To emulate trap based kprobes, preempt_disable here */
> 		preempt_disable();
> 		__this_cpu_write(current_kprobe, p);
> 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> 			__skip_singlestep(p, regs, kcb, orig_ip);
> 			preempt_enable_no_resched();

This preemption disabling and enabling looks rather strange. Looking at
git blame, it appears this was added for jprobes. Can we remove it now
that jprobes is going away?

> 		}
> 		/*
> 		 * If pre_handler returns !0, it sets regs->ip and
> 		 * resets current kprobe, and keep preempt count +1.
> 		 */
> 	}
> }

-- Steve
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-03 22:11 ` rostedt
  2018-05-03 22:11   ` Steven Rostedt
@ 2018-05-04 15:48   ` mhiramat
  2018-05-04 15:48     ` Masami Hiramatsu
  2018-05-04 16:06     ` rostedt
  1 sibling, 2 replies; 72+ messages in thread
From: mhiramat @ 2018-05-04 15:48 UTC (permalink / raw)


On Thu, 3 May 2018 18:11:37 -0400
Steven Rostedt <rostedt at goodmis.org> wrote:

> On Wed, 25 Apr 2018 21:16:06 +0900
> Masami Hiramatsu <mhiramat at kernel.org> wrote:
> 
> > Hi,
> > 
> > This is the 7th version of the fetch-arg improvement series.
> > This includes variable changes on fetcharg framework like,
> > 
> > - Add fetcharg testcases (syntax, argN, symbol, string and array)
> >   and probepoint testcase.
> > - Rewrite fetcharg framework with fetch_insn, switch-case based
> >   instead of function pointer.
> > - Add "symbol" type support, which shows symbol+offset instead of
> >   address value.
> > - Add "$argN" fetcharg, which fetches function parameters.
> >   (currently only for x86-64)
> > - Add array type support (including string arrary :) ) ,
> >   which enables to get fixed length array from probe-events.
> > - Add array type support for perf-probe, so that user can
> >   dump partial array entries.
> > 
> > V6 is here:
> >  https://lkml.org/lkml/2018/3/17/75
> > 
> > Changes from the v6 are here:
> >  [6/16]  - Fix to return an error if failed to fetch string and
> >         fill zero-length data_loc in error case.
> >  [11/16] - Update document for restructured text.
> >  [15/16] - Fix README test.
> >  [16/16] - Add type-casting description (and note) to documentation.
> > 
> > And rebased on the latest Steve's ftrace/core branch.
> > 
> 
> Hi Masami,
> 
> I skimmed through the patches and it they appear fine. I've applied
> them and started playing a little.
> 

Thanks!

> I've been thinking my function based events, and thought instead I
> would make them part of the kprobe infrastructure. Just have a slightly
> different format, and instead of being p: or r: be f: And keep the
> format I was suggesting.
> 
> What do you think?

Unifying the user knob is great!

But if so, the format also should not be so different, I mean user
can use it same way. And maybe "f:" will be non-sense. "p:" with
"function+0" allows user to use "function type casting", that is
enough I think.

So the syntax will be

p[:EVENT] SYM[(CAST)|+OFFS] [FETCHARG]

And here is an example;

p:myevent vfs_read(void *file, char *buf, size_t count, void *pos) $arg1 $arg2

In this case inside '()' will be analyzed and packed as something
like "reference type" data and it is used when converting "$argN".
And maybe we can provide $args special variable to record all
arguments (it can be available only when the (CAST) is given).

This gives the user a consistent model; if you just give a symbol
the arguments may not be correctly translated. but if you give a
type-casting information, it will be much better.

> 
> Also, when looking at the kprobe code, I was looking at this function:
> 
> > /* Ftrace callback handler for kprobes -- called under preepmt disabed */
> > void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
> > 			   struct ftrace_ops *ops, struct pt_regs *regs)
> > {
> > 	struct kprobe *p;
> > 	struct kprobe_ctlblk *kcb;
> > 
> > 	/* Preempt is disabled by ftrace */
> > 	p = get_kprobe((kprobe_opcode_t *)ip);
> > 	if (unlikely(!p) || kprobe_disabled(p))
> > 		return;
> > 
> > 	kcb = get_kprobe_ctlblk();
> > 	if (kprobe_running()) {
> > 		kprobes_inc_nmissed_count(p);
> > 	} else {
> > 		unsigned long orig_ip = regs->ip;
> > 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
> > 		regs->ip = ip + sizeof(kprobe_opcode_t);
> > 
> > 		/* To emulate trap based kprobes, preempt_disable here */
> > 		preempt_disable();
> > 		__this_cpu_write(current_kprobe, p);
> > 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> > 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> > 			__skip_singlestep(p, regs, kcb, orig_ip);
> > 			preempt_enable_no_resched();
> 
> This preemption disabling and enabling looks rather strange. Looking at
> git blame, it appears this was added for jprobes. Can we remove it now
> that jprobes is going away?

No, that is not for jprobes but for compatibility with kprobe's user
handler. Since this transformation is done silently, user can not
change their handler for ftrace case. So we need to keep this condition
same as original kprobes.

And anyway, for using smp_processor_id() for accessing per-cpu,
we should disable preemption, correct?

Thanks,


> 
> > 		}
> > 		/*
> > 		 * If pre_handler returns !0, it sets regs->ip and
> > 		 * resets current kprobe, and keep preempt count +1.
> > 		 */
> > 	}
> > }
> 
> -- Steve


-- 
Masami Hiramatsu <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-04 15:48   ` mhiramat
@ 2018-05-04 15:48     ` Masami Hiramatsu
  2018-05-04 16:06     ` rostedt
  1 sibling, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-05-04 15:48 UTC (permalink / raw)


On Thu, 3 May 2018 18:11:37 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Wed, 25 Apr 2018 21:16:06 +0900
> Masami Hiramatsu <mhiramat@kernel.org> wrote:
> 
> > Hi,
> > 
> > This is the 7th version of the fetch-arg improvement series.
> > This includes variable changes on fetcharg framework like,
> > 
> > - Add fetcharg testcases (syntax, argN, symbol, string and array)
> >   and probepoint testcase.
> > - Rewrite fetcharg framework with fetch_insn, switch-case based
> >   instead of function pointer.
> > - Add "symbol" type support, which shows symbol+offset instead of
> >   address value.
> > - Add "$argN" fetcharg, which fetches function parameters.
> >   (currently only for x86-64)
> > - Add array type support (including string arrary :) ) ,
> >   which enables to get fixed length array from probe-events.
> > - Add array type support for perf-probe, so that user can
> >   dump partial array entries.
> > 
> > V6 is here:
> >  https://lkml.org/lkml/2018/3/17/75
> > 
> > Changes from the v6 are here:
> >  [6/16]  - Fix to return an error if failed to fetch string and
> >         fill zero-length data_loc in error case.
> >  [11/16] - Update document for restructured text.
> >  [15/16] - Fix README test.
> >  [16/16] - Add type-casting description (and note) to documentation.
> > 
> > And rebased on the latest Steve's ftrace/core branch.
> > 
> 
> Hi Masami,
> 
> I skimmed through the patches and it they appear fine. I've applied
> them and started playing a little.
> 

Thanks!

> I've been thinking my function based events, and thought instead I
> would make them part of the kprobe infrastructure. Just have a slightly
> different format, and instead of being p: or r: be f: And keep the
> format I was suggesting.
> 
> What do you think?

Unifying the user knob is great!

But if so, the format also should not be so different, I mean user
can use it same way. And maybe "f:" will be non-sense. "p:" with
"function+0" allows user to use "function type casting", that is
enough I think.

So the syntax will be

p[:EVENT] SYM[(CAST)|+OFFS] [FETCHARG]

And here is an example;

p:myevent vfs_read(void *file, char *buf, size_t count, void *pos) $arg1 $arg2

In this case inside '()' will be analyzed and packed as something
like "reference type" data and it is used when converting "$argN".
And maybe we can provide $args special variable to record all
arguments (it can be available only when the (CAST) is given).

This gives the user a consistent model; if you just give a symbol
the arguments may not be correctly translated. but if you give a
type-casting information, it will be much better.

> 
> Also, when looking at the kprobe code, I was looking at this function:
> 
> > /* Ftrace callback handler for kprobes -- called under preepmt disabed */
> > void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
> > 			   struct ftrace_ops *ops, struct pt_regs *regs)
> > {
> > 	struct kprobe *p;
> > 	struct kprobe_ctlblk *kcb;
> > 
> > 	/* Preempt is disabled by ftrace */
> > 	p = get_kprobe((kprobe_opcode_t *)ip);
> > 	if (unlikely(!p) || kprobe_disabled(p))
> > 		return;
> > 
> > 	kcb = get_kprobe_ctlblk();
> > 	if (kprobe_running()) {
> > 		kprobes_inc_nmissed_count(p);
> > 	} else {
> > 		unsigned long orig_ip = regs->ip;
> > 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
> > 		regs->ip = ip + sizeof(kprobe_opcode_t);
> > 
> > 		/* To emulate trap based kprobes, preempt_disable here */
> > 		preempt_disable();
> > 		__this_cpu_write(current_kprobe, p);
> > 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> > 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> > 			__skip_singlestep(p, regs, kcb, orig_ip);
> > 			preempt_enable_no_resched();
> 
> This preemption disabling and enabling looks rather strange. Looking at
> git blame, it appears this was added for jprobes. Can we remove it now
> that jprobes is going away?

No, that is not for jprobes but for compatibility with kprobe's user
handler. Since this transformation is done silently, user can not
change their handler for ftrace case. So we need to keep this condition
same as original kprobes.

And anyway, for using smp_processor_id() for accessing per-cpu,
we should disable preemption, correct?

Thanks,


> 
> > 		}
> > 		/*
> > 		 * If pre_handler returns !0, it sets regs->ip and
> > 		 * resets current kprobe, and keep preempt count +1.
> > 		 */
> > 	}
> > }
> 
> -- Steve


-- 
Masami Hiramatsu <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-04 15:48   ` mhiramat
  2018-05-04 15:48     ` Masami Hiramatsu
@ 2018-05-04 16:06     ` rostedt
  2018-05-04 16:06       ` Steven Rostedt
                         ` (2 more replies)
  1 sibling, 3 replies; 72+ messages in thread
From: rostedt @ 2018-05-04 16:06 UTC (permalink / raw)


On Sat, 5 May 2018 00:48:28 +0900
Masami Hiramatsu <mhiramat at kernel.org> wrote:

> So the syntax will be
> 
> p[:EVENT] SYM[(CAST)|+OFFS] [FETCHARG]
> 
> And here is an example;
> 
> p:myevent vfs_read(void *file, char *buf, size_t count, void *pos) $arg1 $arg2

If we do this, why bother with $arg1 $arg2?

We could allow this to be an alternative format?

> 
> In this case inside '()' will be analyzed and packed as something
> like "reference type" data and it is used when converting "$argN".
> And maybe we can provide $args special variable to record all
> arguments (it can be available only when the (CAST) is given).
> 
> This gives the user a consistent model; if you just give a symbol
> the arguments may not be correctly translated. but if you give a
> type-casting information, it will be much better.
> 
> > 
> > Also, when looking at the kprobe code, I was looking at this function:
> >   
> > > /* Ftrace callback handler for kprobes -- called under preepmt disabed */
> > > void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
> > > 			   struct ftrace_ops *ops, struct pt_regs *regs)
> > > {
> > > 	struct kprobe *p;
> > > 	struct kprobe_ctlblk *kcb;
> > > 
> > > 	/* Preempt is disabled by ftrace */
> > > 	p = get_kprobe((kprobe_opcode_t *)ip);
> > > 	if (unlikely(!p) || kprobe_disabled(p))
> > > 		return;
> > > 
> > > 	kcb = get_kprobe_ctlblk();
> > > 	if (kprobe_running()) {
> > > 		kprobes_inc_nmissed_count(p);
> > > 	} else {
> > > 		unsigned long orig_ip = regs->ip;
> > > 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
> > > 		regs->ip = ip + sizeof(kprobe_opcode_t);
> > > 
> > > 		/* To emulate trap based kprobes, preempt_disable here */
> > > 		preempt_disable();
> > > 		__this_cpu_write(current_kprobe, p);
> > > 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> > > 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> > > 			__skip_singlestep(p, regs, kcb, orig_ip);
> > > 			preempt_enable_no_resched();  
> > 
> > This preemption disabling and enabling looks rather strange. Looking at
> > git blame, it appears this was added for jprobes. Can we remove it now
> > that jprobes is going away?  
> 
> No, that is not for jprobes but for compatibility with kprobe's user
> handler. Since this transformation is done silently, user can not
> change their handler for ftrace case. So we need to keep this condition
> same as original kprobes.
> 
> And anyway, for using smp_processor_id() for accessing per-cpu,
> we should disable preemption, correct?

But as stated at the start of the function:

 /* Preempt is disabled by ftrace */


The reason I ask, is that we have for this function:

		/* To emulate trap based kprobes, preempt_disable here */
		preempt_disable();
		__this_cpu_write(current_kprobe, p);
		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
		if (!p->pre_handler || !p->pre_handler(p, regs)) {
			__skip_singlestep(p, regs, kcb, orig_ip);
			preempt_enable_no_resched();
		}

And in arch/x86/kernel/kprobes/core.c we have:

	preempt_disable();

	kcb = get_kprobe_ctlblk();
	p = get_kprobe(addr);

	if (p) {
		if (kprobe_running()) {
			if (reenter_kprobe(p, regs, kcb))
				return 1;
		} else {
			set_current_kprobe(p, regs, kcb);
			kcb->kprobe_status = KPROBE_HIT_ACTIVE;

			/*
			 * If we have no pre-handler or it returned 0, we
			 * continue with normal processing.  If we have a
			 * pre-handler and it returned non-zero, it prepped
			 * for calling the break_handler below on re-entry
			 * for jprobe processing, so get out doing nothing
			 * more here.
			 */
			if (!p->pre_handler || !p->pre_handler(p, regs))
				setup_singlestep(p, regs, kcb, 0);
			return 1;


Which is why I thought it was for jprobes. I'm a bit confused about
where preemption is enabled again.

-- Steve
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-04 16:06     ` rostedt
@ 2018-05-04 16:06       ` Steven Rostedt
  2018-05-04 17:30       ` naveen.n.rao
  2018-05-05  2:38       ` mhiramat
  2 siblings, 0 replies; 72+ messages in thread
From: Steven Rostedt @ 2018-05-04 16:06 UTC (permalink / raw)


On Sat, 5 May 2018 00:48:28 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> So the syntax will be
> 
> p[:EVENT] SYM[(CAST)|+OFFS] [FETCHARG]
> 
> And here is an example;
> 
> p:myevent vfs_read(void *file, char *buf, size_t count, void *pos) $arg1 $arg2

If we do this, why bother with $arg1 $arg2?

We could allow this to be an alternative format?

> 
> In this case inside '()' will be analyzed and packed as something
> like "reference type" data and it is used when converting "$argN".
> And maybe we can provide $args special variable to record all
> arguments (it can be available only when the (CAST) is given).
> 
> This gives the user a consistent model; if you just give a symbol
> the arguments may not be correctly translated. but if you give a
> type-casting information, it will be much better.
> 
> > 
> > Also, when looking at the kprobe code, I was looking at this function:
> >   
> > > /* Ftrace callback handler for kprobes -- called under preepmt disabed */
> > > void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
> > > 			   struct ftrace_ops *ops, struct pt_regs *regs)
> > > {
> > > 	struct kprobe *p;
> > > 	struct kprobe_ctlblk *kcb;
> > > 
> > > 	/* Preempt is disabled by ftrace */
> > > 	p = get_kprobe((kprobe_opcode_t *)ip);
> > > 	if (unlikely(!p) || kprobe_disabled(p))
> > > 		return;
> > > 
> > > 	kcb = get_kprobe_ctlblk();
> > > 	if (kprobe_running()) {
> > > 		kprobes_inc_nmissed_count(p);
> > > 	} else {
> > > 		unsigned long orig_ip = regs->ip;
> > > 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
> > > 		regs->ip = ip + sizeof(kprobe_opcode_t);
> > > 
> > > 		/* To emulate trap based kprobes, preempt_disable here */
> > > 		preempt_disable();
> > > 		__this_cpu_write(current_kprobe, p);
> > > 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> > > 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> > > 			__skip_singlestep(p, regs, kcb, orig_ip);
> > > 			preempt_enable_no_resched();  
> > 
> > This preemption disabling and enabling looks rather strange. Looking at
> > git blame, it appears this was added for jprobes. Can we remove it now
> > that jprobes is going away?  
> 
> No, that is not for jprobes but for compatibility with kprobe's user
> handler. Since this transformation is done silently, user can not
> change their handler for ftrace case. So we need to keep this condition
> same as original kprobes.
> 
> And anyway, for using smp_processor_id() for accessing per-cpu,
> we should disable preemption, correct?

But as stated at the start of the function:

 /* Preempt is disabled by ftrace */


The reason I ask, is that we have for this function:

		/* To emulate trap based kprobes, preempt_disable here */
		preempt_disable();
		__this_cpu_write(current_kprobe, p);
		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
		if (!p->pre_handler || !p->pre_handler(p, regs)) {
			__skip_singlestep(p, regs, kcb, orig_ip);
			preempt_enable_no_resched();
		}

And in arch/x86/kernel/kprobes/core.c we have:

	preempt_disable();

	kcb = get_kprobe_ctlblk();
	p = get_kprobe(addr);

	if (p) {
		if (kprobe_running()) {
			if (reenter_kprobe(p, regs, kcb))
				return 1;
		} else {
			set_current_kprobe(p, regs, kcb);
			kcb->kprobe_status = KPROBE_HIT_ACTIVE;

			/*
			 * If we have no pre-handler or it returned 0, we
			 * continue with normal processing.  If we have a
			 * pre-handler and it returned non-zero, it prepped
			 * for calling the break_handler below on re-entry
			 * for jprobe processing, so get out doing nothing
			 * more here.
			 */
			if (!p->pre_handler || !p->pre_handler(p, regs))
				setup_singlestep(p, regs, kcb, 0);
			return 1;


Which is why I thought it was for jprobes. I'm a bit confused about
where preemption is enabled again.

-- Steve
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-04 16:06     ` rostedt
  2018-05-04 16:06       ` Steven Rostedt
@ 2018-05-04 17:30       ` naveen.n.rao
  2018-05-04 17:30         ` Naveen N. Rao
  2018-05-05  2:38       ` mhiramat
  2 siblings, 1 reply; 72+ messages in thread
From: naveen.n.rao @ 2018-05-04 17:30 UTC (permalink / raw)


Steven Rostedt wrote:
> On Sat, 5 May 2018 00:48:28 +0900
> Masami Hiramatsu <mhiramat at kernel.org> wrote:
>> > 
>> > Also, when looking at the kprobe code, I was looking at this function:
>> >   
>> > > /* Ftrace callback handler for kprobes -- called under preepmt disabed */
>> > > void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
>> > > 			   struct ftrace_ops *ops, struct pt_regs *regs)
>> > > {
>> > > 	struct kprobe *p;
>> > > 	struct kprobe_ctlblk *kcb;
>> > > 
>> > > 	/* Preempt is disabled by ftrace */
>> > > 	p = get_kprobe((kprobe_opcode_t *)ip);
>> > > 	if (unlikely(!p) || kprobe_disabled(p))
>> > > 		return;
>> > > 
>> > > 	kcb = get_kprobe_ctlblk();
>> > > 	if (kprobe_running()) {
>> > > 		kprobes_inc_nmissed_count(p);
>> > > 	} else {
>> > > 		unsigned long orig_ip = regs->ip;
>> > > 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
>> > > 		regs->ip = ip + sizeof(kprobe_opcode_t);
>> > > 
>> > > 		/* To emulate trap based kprobes, preempt_disable here */
>> > > 		preempt_disable();
>> > > 		__this_cpu_write(current_kprobe, p);
>> > > 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
>> > > 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
>> > > 			__skip_singlestep(p, regs, kcb, orig_ip);
>> > > 			preempt_enable_no_resched();  
>> > 
>> > This preemption disabling and enabling looks rather strange. Looking at
>> > git blame, it appears this was added for jprobes. Can we remove it now
>> > that jprobes is going away?  
>> 
>> No, that is not for jprobes but for compatibility with kprobe's user
>> handler. Since this transformation is done silently, user can not
>> change their handler for ftrace case. So we need to keep this condition
>> same as original kprobes.
>> 
>> And anyway, for using smp_processor_id() for accessing per-cpu,
>> we should disable preemption, correct?
> 
> But as stated at the start of the function:
> 
>  /* Preempt is disabled by ftrace */
> 
> 
> The reason I ask, is that we have for this function:
> 
> 		/* To emulate trap based kprobes, preempt_disable here */
> 		preempt_disable();
> 		__this_cpu_write(current_kprobe, p);
> 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> 			__skip_singlestep(p, regs, kcb, orig_ip);
> 			preempt_enable_no_resched();
> 		}
> 
> And in arch/x86/kernel/kprobes/core.c we have:
> 
> 	preempt_disable();
> 
> 	kcb = get_kprobe_ctlblk();
> 	p = get_kprobe(addr);
> 
> 	if (p) {
> 		if (kprobe_running()) {
> 			if (reenter_kprobe(p, regs, kcb))
> 				return 1;
> 		} else {
> 			set_current_kprobe(p, regs, kcb);
> 			kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> 
> 			/*
> 			 * If we have no pre-handler or it returned 0, we
> 			 * continue with normal processing.  If we have a
> 			 * pre-handler and it returned non-zero, it prepped
> 			 * for calling the break_handler below on re-entry
> 			 * for jprobe processing, so get out doing nothing
> 			 * more here.
> 			 */
> 			if (!p->pre_handler || !p->pre_handler(p, regs))
> 				setup_singlestep(p, regs, kcb, 0);
> 			return 1;
> 
> 
> Which is why I thought it was for jprobes. I'm a bit confused about
> where preemption is enabled again.

Jprobes was the in-kernel user for that. However, users can write custom 
kprobe [pre-]handlers that return a non-zero value if they want to 
suppress normal processing of the probe (single stepping the instruction 
where the probe was installed). In this case, the custom handler is 
expected to deal with re-enabling preemption before returning from the 
pre handler. Or, there must be some other way to re-enable preemption 
later on like with jprobes -- where the hook would cause a trap to 
complete jprobe handling.

For optprobes, we actually break this and do not disable preemption.  
But, the expectation there is that the user set a post-handler to force 
optprobes to be disabled, *if* they want to do custom handling by 
returning a non-zero return value from the pre handler.

For KPROBES_ON_FTRACE, we need to emulate the behavior of the normal, 
trap-based kprobes. This is the reason preemption needs to be disabled 
again, so as to balance it with the user's custom handler re-enabling 
it.

Of course, with the in-kernel user (jprobes) now gone, it is anybody's 
guess as to who is still depending on this custom pre-handler behavior 
;)


- Naveen


--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-04 17:30       ` naveen.n.rao
@ 2018-05-04 17:30         ` Naveen N. Rao
  0 siblings, 0 replies; 72+ messages in thread
From: Naveen N. Rao @ 2018-05-04 17:30 UTC (permalink / raw)


Steven Rostedt wrote:
> On Sat, 5 May 2018 00:48:28 +0900
> Masami Hiramatsu <mhiramat@kernel.org> wrote:
>> > 
>> > Also, when looking at the kprobe code, I was looking at this function:
>> >   
>> > > /* Ftrace callback handler for kprobes -- called under preepmt disabed */
>> > > void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
>> > > 			   struct ftrace_ops *ops, struct pt_regs *regs)
>> > > {
>> > > 	struct kprobe *p;
>> > > 	struct kprobe_ctlblk *kcb;
>> > > 
>> > > 	/* Preempt is disabled by ftrace */
>> > > 	p = get_kprobe((kprobe_opcode_t *)ip);
>> > > 	if (unlikely(!p) || kprobe_disabled(p))
>> > > 		return;
>> > > 
>> > > 	kcb = get_kprobe_ctlblk();
>> > > 	if (kprobe_running()) {
>> > > 		kprobes_inc_nmissed_count(p);
>> > > 	} else {
>> > > 		unsigned long orig_ip = regs->ip;
>> > > 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
>> > > 		regs->ip = ip + sizeof(kprobe_opcode_t);
>> > > 
>> > > 		/* To emulate trap based kprobes, preempt_disable here */
>> > > 		preempt_disable();
>> > > 		__this_cpu_write(current_kprobe, p);
>> > > 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
>> > > 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
>> > > 			__skip_singlestep(p, regs, kcb, orig_ip);
>> > > 			preempt_enable_no_resched();  
>> > 
>> > This preemption disabling and enabling looks rather strange. Looking at
>> > git blame, it appears this was added for jprobes. Can we remove it now
>> > that jprobes is going away?  
>> 
>> No, that is not for jprobes but for compatibility with kprobe's user
>> handler. Since this transformation is done silently, user can not
>> change their handler for ftrace case. So we need to keep this condition
>> same as original kprobes.
>> 
>> And anyway, for using smp_processor_id() for accessing per-cpu,
>> we should disable preemption, correct?
> 
> But as stated at the start of the function:
> 
>  /* Preempt is disabled by ftrace */
> 
> 
> The reason I ask, is that we have for this function:
> 
> 		/* To emulate trap based kprobes, preempt_disable here */
> 		preempt_disable();
> 		__this_cpu_write(current_kprobe, p);
> 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> 			__skip_singlestep(p, regs, kcb, orig_ip);
> 			preempt_enable_no_resched();
> 		}
> 
> And in arch/x86/kernel/kprobes/core.c we have:
> 
> 	preempt_disable();
> 
> 	kcb = get_kprobe_ctlblk();
> 	p = get_kprobe(addr);
> 
> 	if (p) {
> 		if (kprobe_running()) {
> 			if (reenter_kprobe(p, regs, kcb))
> 				return 1;
> 		} else {
> 			set_current_kprobe(p, regs, kcb);
> 			kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> 
> 			/*
> 			 * If we have no pre-handler or it returned 0, we
> 			 * continue with normal processing.  If we have a
> 			 * pre-handler and it returned non-zero, it prepped
> 			 * for calling the break_handler below on re-entry
> 			 * for jprobe processing, so get out doing nothing
> 			 * more here.
> 			 */
> 			if (!p->pre_handler || !p->pre_handler(p, regs))
> 				setup_singlestep(p, regs, kcb, 0);
> 			return 1;
> 
> 
> Which is why I thought it was for jprobes. I'm a bit confused about
> where preemption is enabled again.

Jprobes was the in-kernel user for that. However, users can write custom 
kprobe [pre-]handlers that return a non-zero value if they want to 
suppress normal processing of the probe (single stepping the instruction 
where the probe was installed). In this case, the custom handler is 
expected to deal with re-enabling preemption before returning from the 
pre handler. Or, there must be some other way to re-enable preemption 
later on like with jprobes -- where the hook would cause a trap to 
complete jprobe handling.

For optprobes, we actually break this and do not disable preemption.  
But, the expectation there is that the user set a post-handler to force 
optprobes to be disabled, *if* they want to do custom handling by 
returning a non-zero return value from the pre handler.

For KPROBES_ON_FTRACE, we need to emulate the behavior of the normal, 
trap-based kprobes. This is the reason preemption needs to be disabled 
again, so as to balance it with the user's custom handler re-enabling 
it.

Of course, with the in-kernel user (jprobes) now gone, it is anybody's 
guess as to who is still depending on this custom pre-handler behavior 
;)


- Naveen


--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-04 16:06     ` rostedt
  2018-05-04 16:06       ` Steven Rostedt
  2018-05-04 17:30       ` naveen.n.rao
@ 2018-05-05  2:38       ` mhiramat
  2018-05-05  2:38         ` Masami Hiramatsu
                           ` (3 more replies)
  2 siblings, 4 replies; 72+ messages in thread
From: mhiramat @ 2018-05-05  2:38 UTC (permalink / raw)


On Fri, 4 May 2018 12:06:42 -0400
Steven Rostedt <rostedt at goodmis.org> wrote:

> On Sat, 5 May 2018 00:48:28 +0900
> Masami Hiramatsu <mhiramat at kernel.org> wrote:
> 
> > So the syntax will be
> > 
> > p[:EVENT] SYM[(CAST)|+OFFS] [FETCHARG]
> > 
> > And here is an example;
> > 
> > p:myevent vfs_read(void *file, char *buf, size_t count, void *pos) $arg1 $arg2
> 
> If we do this, why bother with $arg1 $arg2?

User may want to trace only some of them. :)

> 
> We could allow this to be an alternative format?

I think we can skip passing $args, which implies trace all arguments.

p[:EVENT] SYM[(CAST)|+OFFS] [FETCHARG(*)]

*) if SYM(CAST) is given but no FETCHARG, which implies to trace
all arguments in the CAST.

> > In this case inside '()' will be analyzed and packed as something
> > like "reference type" data and it is used when converting "$argN".
> > And maybe we can provide $args special variable to record all
> > arguments (it can be available only when the (CAST) is given).
> > 
> > This gives the user a consistent model; if you just give a symbol
> > the arguments may not be correctly translated. but if you give a
> > type-casting information, it will be much better.
> > 
> > > 
> > > Also, when looking at the kprobe code, I was looking at this function:
> > >   
> > > > /* Ftrace callback handler for kprobes -- called under preepmt disabed */
> > > > void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
> > > > 			   struct ftrace_ops *ops, struct pt_regs *regs)
> > > > {
> > > > 	struct kprobe *p;
> > > > 	struct kprobe_ctlblk *kcb;
> > > > 
> > > > 	/* Preempt is disabled by ftrace */
> > > > 	p = get_kprobe((kprobe_opcode_t *)ip);
> > > > 	if (unlikely(!p) || kprobe_disabled(p))
> > > > 		return;
> > > > 
> > > > 	kcb = get_kprobe_ctlblk();
> > > > 	if (kprobe_running()) {
> > > > 		kprobes_inc_nmissed_count(p);
> > > > 	} else {
> > > > 		unsigned long orig_ip = regs->ip;
> > > > 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
> > > > 		regs->ip = ip + sizeof(kprobe_opcode_t);
> > > > 
> > > > 		/* To emulate trap based kprobes, preempt_disable here */
> > > > 		preempt_disable();
> > > > 		__this_cpu_write(current_kprobe, p);
> > > > 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> > > > 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> > > > 			__skip_singlestep(p, regs, kcb, orig_ip);
> > > > 			preempt_enable_no_resched();  
> > > 
> > > This preemption disabling and enabling looks rather strange. Looking at
> > > git blame, it appears this was added for jprobes. Can we remove it now
> > > that jprobes is going away?  
> > 
> > No, that is not for jprobes but for compatibility with kprobe's user
> > handler. Since this transformation is done silently, user can not
> > change their handler for ftrace case. So we need to keep this condition
> > same as original kprobes.
> > 
> > And anyway, for using smp_processor_id() for accessing per-cpu,
> > we should disable preemption, correct?
> 
> But as stated at the start of the function:
> 
>  /* Preempt is disabled by ftrace */

Ah, yes. So this is only for the jprobes.

> 
> 
> The reason I ask, is that we have for this function:
> 
> 		/* To emulate trap based kprobes, preempt_disable here */
> 		preempt_disable();
> 		__this_cpu_write(current_kprobe, p);
> 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> 			__skip_singlestep(p, regs, kcb, orig_ip);
> 			preempt_enable_no_resched();
> 		}
> 
> And in arch/x86/kernel/kprobes/core.c we have:
> 
> 	preempt_disable();
> 
> 	kcb = get_kprobe_ctlblk();
> 	p = get_kprobe(addr);
> 
> 	if (p) {
> 		if (kprobe_running()) {
> 			if (reenter_kprobe(p, regs, kcb))
> 				return 1;
> 		} else {
> 			set_current_kprobe(p, regs, kcb);
> 			kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> 
> 			/*
> 			 * If we have no pre-handler or it returned 0, we
> 			 * continue with normal processing.  If we have a
> 			 * pre-handler and it returned non-zero, it prepped
> 			 * for calling the break_handler below on re-entry
> 			 * for jprobe processing, so get out doing nothing
> 			 * more here.
> 			 */
> 			if (!p->pre_handler || !p->pre_handler(p, regs))
> 				setup_singlestep(p, regs, kcb, 0);
> 			return 1;
> 
> 
> Which is why I thought it was for jprobes. I'm a bit confused about
> where preemption is enabled again.

You're right. So I would like to remove it with x86 jprobe support
code to avoid inconsistency.

Thanks!

-- 
Masami Hiramatsu <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-05  2:38       ` mhiramat
@ 2018-05-05  2:38         ` Masami Hiramatsu
  2018-05-05  7:46         ` naveen.n.rao
                           ` (2 subsequent siblings)
  3 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-05-05  2:38 UTC (permalink / raw)


On Fri, 4 May 2018 12:06:42 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Sat, 5 May 2018 00:48:28 +0900
> Masami Hiramatsu <mhiramat@kernel.org> wrote:
> 
> > So the syntax will be
> > 
> > p[:EVENT] SYM[(CAST)|+OFFS] [FETCHARG]
> > 
> > And here is an example;
> > 
> > p:myevent vfs_read(void *file, char *buf, size_t count, void *pos) $arg1 $arg2
> 
> If we do this, why bother with $arg1 $arg2?

User may want to trace only some of them. :)

> 
> We could allow this to be an alternative format?

I think we can skip passing $args, which implies trace all arguments.

p[:EVENT] SYM[(CAST)|+OFFS] [FETCHARG(*)]

*) if SYM(CAST) is given but no FETCHARG, which implies to trace
all arguments in the CAST.

> > In this case inside '()' will be analyzed and packed as something
> > like "reference type" data and it is used when converting "$argN".
> > And maybe we can provide $args special variable to record all
> > arguments (it can be available only when the (CAST) is given).
> > 
> > This gives the user a consistent model; if you just give a symbol
> > the arguments may not be correctly translated. but if you give a
> > type-casting information, it will be much better.
> > 
> > > 
> > > Also, when looking at the kprobe code, I was looking at this function:
> > >   
> > > > /* Ftrace callback handler for kprobes -- called under preepmt disabed */
> > > > void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
> > > > 			   struct ftrace_ops *ops, struct pt_regs *regs)
> > > > {
> > > > 	struct kprobe *p;
> > > > 	struct kprobe_ctlblk *kcb;
> > > > 
> > > > 	/* Preempt is disabled by ftrace */
> > > > 	p = get_kprobe((kprobe_opcode_t *)ip);
> > > > 	if (unlikely(!p) || kprobe_disabled(p))
> > > > 		return;
> > > > 
> > > > 	kcb = get_kprobe_ctlblk();
> > > > 	if (kprobe_running()) {
> > > > 		kprobes_inc_nmissed_count(p);
> > > > 	} else {
> > > > 		unsigned long orig_ip = regs->ip;
> > > > 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
> > > > 		regs->ip = ip + sizeof(kprobe_opcode_t);
> > > > 
> > > > 		/* To emulate trap based kprobes, preempt_disable here */
> > > > 		preempt_disable();
> > > > 		__this_cpu_write(current_kprobe, p);
> > > > 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> > > > 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> > > > 			__skip_singlestep(p, regs, kcb, orig_ip);
> > > > 			preempt_enable_no_resched();  
> > > 
> > > This preemption disabling and enabling looks rather strange. Looking at
> > > git blame, it appears this was added for jprobes. Can we remove it now
> > > that jprobes is going away?  
> > 
> > No, that is not for jprobes but for compatibility with kprobe's user
> > handler. Since this transformation is done silently, user can not
> > change their handler for ftrace case. So we need to keep this condition
> > same as original kprobes.
> > 
> > And anyway, for using smp_processor_id() for accessing per-cpu,
> > we should disable preemption, correct?
> 
> But as stated at the start of the function:
> 
>  /* Preempt is disabled by ftrace */

Ah, yes. So this is only for the jprobes.

> 
> 
> The reason I ask, is that we have for this function:
> 
> 		/* To emulate trap based kprobes, preempt_disable here */
> 		preempt_disable();
> 		__this_cpu_write(current_kprobe, p);
> 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> 			__skip_singlestep(p, regs, kcb, orig_ip);
> 			preempt_enable_no_resched();
> 		}
> 
> And in arch/x86/kernel/kprobes/core.c we have:
> 
> 	preempt_disable();
> 
> 	kcb = get_kprobe_ctlblk();
> 	p = get_kprobe(addr);
> 
> 	if (p) {
> 		if (kprobe_running()) {
> 			if (reenter_kprobe(p, regs, kcb))
> 				return 1;
> 		} else {
> 			set_current_kprobe(p, regs, kcb);
> 			kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> 
> 			/*
> 			 * If we have no pre-handler or it returned 0, we
> 			 * continue with normal processing.  If we have a
> 			 * pre-handler and it returned non-zero, it prepped
> 			 * for calling the break_handler below on re-entry
> 			 * for jprobe processing, so get out doing nothing
> 			 * more here.
> 			 */
> 			if (!p->pre_handler || !p->pre_handler(p, regs))
> 				setup_singlestep(p, regs, kcb, 0);
> 			return 1;
> 
> 
> Which is why I thought it was for jprobes. I'm a bit confused about
> where preemption is enabled again.

You're right. So I would like to remove it with x86 jprobe support
code to avoid inconsistency.

Thanks!

-- 
Masami Hiramatsu <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-05  2:38       ` mhiramat
  2018-05-05  2:38         ` Masami Hiramatsu
@ 2018-05-05  7:46         ` naveen.n.rao
  2018-05-05  7:46           ` Naveen N. Rao
  2018-05-05 14:32           ` mhiramat
  2018-05-05 15:51         ` mhiramat
  2018-05-07 15:21         ` rostedt
  3 siblings, 2 replies; 72+ messages in thread
From: naveen.n.rao @ 2018-05-05  7:46 UTC (permalink / raw)


Masami Hiramatsu wrote:
> On Fri, 4 May 2018 12:06:42 -0400
> Steven Rostedt <rostedt at goodmis.org> wrote:
> 
>> On Sat, 5 May 2018 00:48:28 +0900
>> Masami Hiramatsu <mhiramat at kernel.org> wrote:
>> 
>> > > Also, when looking at the kprobe code, I was looking at this 
>> > > function:
>> > >   
>> > > > /* Ftrace callback handler for kprobes -- called under preepmt disabed */
>> > > > void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
>> > > > 			   struct ftrace_ops *ops, struct pt_regs *regs)
>> > > > {
>> > > > 	struct kprobe *p;
>> > > > 	struct kprobe_ctlblk *kcb;
>> > > > 
>> > > > 	/* Preempt is disabled by ftrace */
>> > > > 	p = get_kprobe((kprobe_opcode_t *)ip);
>> > > > 	if (unlikely(!p) || kprobe_disabled(p))
>> > > > 		return;
>> > > > 
>> > > > 	kcb = get_kprobe_ctlblk();
>> > > > 	if (kprobe_running()) {
>> > > > 		kprobes_inc_nmissed_count(p);
>> > > > 	} else {
>> > > > 		unsigned long orig_ip = regs->ip;
>> > > > 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
>> > > > 		regs->ip = ip + sizeof(kprobe_opcode_t);
>> > > > 
>> > > > 		/* To emulate trap based kprobes, preempt_disable here */
>> > > > 		preempt_disable();
>> > > > 		__this_cpu_write(current_kprobe, p);
>> > > > 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
>> > > > 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
>> > > > 			__skip_singlestep(p, regs, kcb, orig_ip);
>> > > > 			preempt_enable_no_resched();  
>> > > 
>> > > This preemption disabling and enabling looks rather strange. Looking at
>> > > git blame, it appears this was added for jprobes. Can we remove it now
>> > > that jprobes is going away?  
>> > 
>> > No, that is not for jprobes but for compatibility with kprobe's user
>> > handler. Since this transformation is done silently, user can not
>> > change their handler for ftrace case. So we need to keep this condition
>> > same as original kprobes.
>> > 
>> > And anyway, for using smp_processor_id() for accessing per-cpu,
>> > we should disable preemption, correct?
>> 
>> But as stated at the start of the function:
>> 
>>  /* Preempt is disabled by ftrace */
> 
> Ah, yes. So this is only for the jprobes.
> 
>> 
>> 
>> The reason I ask, is that we have for this function:
>> 
>> 		/* To emulate trap based kprobes, preempt_disable here */
>> 		preempt_disable();
>> 		__this_cpu_write(current_kprobe, p);
>> 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
>> 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
>> 			__skip_singlestep(p, regs, kcb, orig_ip);
>> 			preempt_enable_no_resched();
>> 		}
>> 
>> And in arch/x86/kernel/kprobes/core.c we have:
>> 
>> 	preempt_disable();
>> 
>> 	kcb = get_kprobe_ctlblk();
>> 	p = get_kprobe(addr);
>> 
>> 	if (p) {
>> 		if (kprobe_running()) {
>> 			if (reenter_kprobe(p, regs, kcb))
>> 				return 1;
>> 		} else {
>> 			set_current_kprobe(p, regs, kcb);
>> 			kcb->kprobe_status = KPROBE_HIT_ACTIVE;
>> 
>> 			/*
>> 			 * If we have no pre-handler or it returned 0, we
>> 			 * continue with normal processing.  If we have a
>> 			 * pre-handler and it returned non-zero, it prepped
>> 			 * for calling the break_handler below on re-entry
>> 			 * for jprobe processing, so get out doing nothing
>> 			 * more here.
>> 			 */
>> 			if (!p->pre_handler || !p->pre_handler(p, regs))
>> 				setup_singlestep(p, regs, kcb, 0);
>> 			return 1;
>> 
>> 
>> Which is why I thought it was for jprobes. I'm a bit confused about
>> where preemption is enabled again.
> 
> You're right. So I would like to remove it with x86 jprobe support
> code to avoid inconsistency.

I didn't understand that. Which code are you planning to remove? Can you 
please elaborate? I thought we still need to disable preemption in the 
ftrace handler.

Thanks,
Naveen


--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-05  7:46         ` naveen.n.rao
@ 2018-05-05  7:46           ` Naveen N. Rao
  2018-05-05 14:32           ` mhiramat
  1 sibling, 0 replies; 72+ messages in thread
From: Naveen N. Rao @ 2018-05-05  7:46 UTC (permalink / raw)


Masami Hiramatsu wrote:
> On Fri, 4 May 2018 12:06:42 -0400
> Steven Rostedt <rostedt@goodmis.org> wrote:
> 
>> On Sat, 5 May 2018 00:48:28 +0900
>> Masami Hiramatsu <mhiramat@kernel.org> wrote:
>> 
>> > > Also, when looking at the kprobe code, I was looking at this 
>> > > function:
>> > >   
>> > > > /* Ftrace callback handler for kprobes -- called under preepmt disabed */
>> > > > void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
>> > > > 			   struct ftrace_ops *ops, struct pt_regs *regs)
>> > > > {
>> > > > 	struct kprobe *p;
>> > > > 	struct kprobe_ctlblk *kcb;
>> > > > 
>> > > > 	/* Preempt is disabled by ftrace */
>> > > > 	p = get_kprobe((kprobe_opcode_t *)ip);
>> > > > 	if (unlikely(!p) || kprobe_disabled(p))
>> > > > 		return;
>> > > > 
>> > > > 	kcb = get_kprobe_ctlblk();
>> > > > 	if (kprobe_running()) {
>> > > > 		kprobes_inc_nmissed_count(p);
>> > > > 	} else {
>> > > > 		unsigned long orig_ip = regs->ip;
>> > > > 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
>> > > > 		regs->ip = ip + sizeof(kprobe_opcode_t);
>> > > > 
>> > > > 		/* To emulate trap based kprobes, preempt_disable here */
>> > > > 		preempt_disable();
>> > > > 		__this_cpu_write(current_kprobe, p);
>> > > > 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
>> > > > 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
>> > > > 			__skip_singlestep(p, regs, kcb, orig_ip);
>> > > > 			preempt_enable_no_resched();  
>> > > 
>> > > This preemption disabling and enabling looks rather strange. Looking at
>> > > git blame, it appears this was added for jprobes. Can we remove it now
>> > > that jprobes is going away?  
>> > 
>> > No, that is not for jprobes but for compatibility with kprobe's user
>> > handler. Since this transformation is done silently, user can not
>> > change their handler for ftrace case. So we need to keep this condition
>> > same as original kprobes.
>> > 
>> > And anyway, for using smp_processor_id() for accessing per-cpu,
>> > we should disable preemption, correct?
>> 
>> But as stated at the start of the function:
>> 
>>  /* Preempt is disabled by ftrace */
> 
> Ah, yes. So this is only for the jprobes.
> 
>> 
>> 
>> The reason I ask, is that we have for this function:
>> 
>> 		/* To emulate trap based kprobes, preempt_disable here */
>> 		preempt_disable();
>> 		__this_cpu_write(current_kprobe, p);
>> 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
>> 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
>> 			__skip_singlestep(p, regs, kcb, orig_ip);
>> 			preempt_enable_no_resched();
>> 		}
>> 
>> And in arch/x86/kernel/kprobes/core.c we have:
>> 
>> 	preempt_disable();
>> 
>> 	kcb = get_kprobe_ctlblk();
>> 	p = get_kprobe(addr);
>> 
>> 	if (p) {
>> 		if (kprobe_running()) {
>> 			if (reenter_kprobe(p, regs, kcb))
>> 				return 1;
>> 		} else {
>> 			set_current_kprobe(p, regs, kcb);
>> 			kcb->kprobe_status = KPROBE_HIT_ACTIVE;
>> 
>> 			/*
>> 			 * If we have no pre-handler or it returned 0, we
>> 			 * continue with normal processing.  If we have a
>> 			 * pre-handler and it returned non-zero, it prepped
>> 			 * for calling the break_handler below on re-entry
>> 			 * for jprobe processing, so get out doing nothing
>> 			 * more here.
>> 			 */
>> 			if (!p->pre_handler || !p->pre_handler(p, regs))
>> 				setup_singlestep(p, regs, kcb, 0);
>> 			return 1;
>> 
>> 
>> Which is why I thought it was for jprobes. I'm a bit confused about
>> where preemption is enabled again.
> 
> You're right. So I would like to remove it with x86 jprobe support
> code to avoid inconsistency.

I didn't understand that. Which code are you planning to remove? Can you 
please elaborate? I thought we still need to disable preemption in the 
ftrace handler.

Thanks,
Naveen


--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-05  7:46         ` naveen.n.rao
  2018-05-05  7:46           ` Naveen N. Rao
@ 2018-05-05 14:32           ` mhiramat
  2018-05-05 14:32             ` Masami Hiramatsu
  2018-05-07  8:11             ` naveen.n.rao
  1 sibling, 2 replies; 72+ messages in thread
From: mhiramat @ 2018-05-05 14:32 UTC (permalink / raw)


On Sat, 05 May 2018 13:16:04 +0530
"Naveen N. Rao" <naveen.n.rao at linux.vnet.ibm.com> wrote:

> Masami Hiramatsu wrote:
> > On Fri, 4 May 2018 12:06:42 -0400
> > Steven Rostedt <rostedt at goodmis.org> wrote:
> > 
> >> On Sat, 5 May 2018 00:48:28 +0900
> >> Masami Hiramatsu <mhiramat at kernel.org> wrote:
> >> 
> >> > > Also, when looking at the kprobe code, I was looking at this 
> >> > > function:
> >> > >   
> >> > > > /* Ftrace callback handler for kprobes -- called under preepmt disabed */
> >> > > > void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
> >> > > > 			   struct ftrace_ops *ops, struct pt_regs *regs)
> >> > > > {
> >> > > > 	struct kprobe *p;
> >> > > > 	struct kprobe_ctlblk *kcb;
> >> > > > 
> >> > > > 	/* Preempt is disabled by ftrace */
> >> > > > 	p = get_kprobe((kprobe_opcode_t *)ip);
> >> > > > 	if (unlikely(!p) || kprobe_disabled(p))
> >> > > > 		return;
> >> > > > 
> >> > > > 	kcb = get_kprobe_ctlblk();
> >> > > > 	if (kprobe_running()) {
> >> > > > 		kprobes_inc_nmissed_count(p);
> >> > > > 	} else {
> >> > > > 		unsigned long orig_ip = regs->ip;
> >> > > > 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
> >> > > > 		regs->ip = ip + sizeof(kprobe_opcode_t);
> >> > > > 
> >> > > > 		/* To emulate trap based kprobes, preempt_disable here */
> >> > > > 		preempt_disable();
> >> > > > 		__this_cpu_write(current_kprobe, p);
> >> > > > 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> >> > > > 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> >> > > > 			__skip_singlestep(p, regs, kcb, orig_ip);
> >> > > > 			preempt_enable_no_resched();  
> >> > > 
> >> > > This preemption disabling and enabling looks rather strange. Looking at
> >> > > git blame, it appears this was added for jprobes. Can we remove it now
> >> > > that jprobes is going away?  
> >> > 
> >> > No, that is not for jprobes but for compatibility with kprobe's user
> >> > handler. Since this transformation is done silently, user can not
> >> > change their handler for ftrace case. So we need to keep this condition
> >> > same as original kprobes.
> >> > 
> >> > And anyway, for using smp_processor_id() for accessing per-cpu,
> >> > we should disable preemption, correct?
> >> 
> >> But as stated at the start of the function:
> >> 
> >>  /* Preempt is disabled by ftrace */
> > 
> > Ah, yes. So this is only for the jprobes.
> > 
> >> 
> >> 
> >> The reason I ask, is that we have for this function:
> >> 
> >> 		/* To emulate trap based kprobes, preempt_disable here */
> >> 		preempt_disable();
> >> 		__this_cpu_write(current_kprobe, p);
> >> 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> >> 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> >> 			__skip_singlestep(p, regs, kcb, orig_ip);
> >> 			preempt_enable_no_resched();
> >> 		}
> >> 
> >> And in arch/x86/kernel/kprobes/core.c we have:
> >> 
> >> 	preempt_disable();
> >> 
> >> 	kcb = get_kprobe_ctlblk();
> >> 	p = get_kprobe(addr);
> >> 
> >> 	if (p) {
> >> 		if (kprobe_running()) {
> >> 			if (reenter_kprobe(p, regs, kcb))
> >> 				return 1;
> >> 		} else {
> >> 			set_current_kprobe(p, regs, kcb);
> >> 			kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> >> 
> >> 			/*
> >> 			 * If we have no pre-handler or it returned 0, we
> >> 			 * continue with normal processing.  If we have a
> >> 			 * pre-handler and it returned non-zero, it prepped
> >> 			 * for calling the break_handler below on re-entry
> >> 			 * for jprobe processing, so get out doing nothing
> >> 			 * more here.
> >> 			 */
> >> 			if (!p->pre_handler || !p->pre_handler(p, regs))
> >> 				setup_singlestep(p, regs, kcb, 0);
> >> 			return 1;
> >> 
> >> 
> >> Which is why I thought it was for jprobes. I'm a bit confused about
> >> where preemption is enabled again.
> > 
> > You're right. So I would like to remove it with x86 jprobe support
> > code to avoid inconsistency.
> 
> I didn't understand that. Which code are you planning to remove? Can you 
> please elaborate? I thought we still need to disable preemption in the 
> ftrace handler.

Yes, kprobe_ftrace_handler itself must be run under preempt disabled
because it depends on a per-cpu variable. What I will remove is the
redundant preempt disable/enable_noresched (unbalanced) pair in the
kprobe_ftrace_handler, and jprobe x86 ports which is no more used.

Thank you,


-- 
Masami Hiramatsu <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-05 14:32           ` mhiramat
@ 2018-05-05 14:32             ` Masami Hiramatsu
  2018-05-07  8:11             ` naveen.n.rao
  1 sibling, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-05-05 14:32 UTC (permalink / raw)


On Sat, 05 May 2018 13:16:04 +0530
"Naveen N. Rao" <naveen.n.rao@linux.vnet.ibm.com> wrote:

> Masami Hiramatsu wrote:
> > On Fri, 4 May 2018 12:06:42 -0400
> > Steven Rostedt <rostedt@goodmis.org> wrote:
> > 
> >> On Sat, 5 May 2018 00:48:28 +0900
> >> Masami Hiramatsu <mhiramat@kernel.org> wrote:
> >> 
> >> > > Also, when looking at the kprobe code, I was looking at this 
> >> > > function:
> >> > >   
> >> > > > /* Ftrace callback handler for kprobes -- called under preepmt disabed */
> >> > > > void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
> >> > > > 			   struct ftrace_ops *ops, struct pt_regs *regs)
> >> > > > {
> >> > > > 	struct kprobe *p;
> >> > > > 	struct kprobe_ctlblk *kcb;
> >> > > > 
> >> > > > 	/* Preempt is disabled by ftrace */
> >> > > > 	p = get_kprobe((kprobe_opcode_t *)ip);
> >> > > > 	if (unlikely(!p) || kprobe_disabled(p))
> >> > > > 		return;
> >> > > > 
> >> > > > 	kcb = get_kprobe_ctlblk();
> >> > > > 	if (kprobe_running()) {
> >> > > > 		kprobes_inc_nmissed_count(p);
> >> > > > 	} else {
> >> > > > 		unsigned long orig_ip = regs->ip;
> >> > > > 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
> >> > > > 		regs->ip = ip + sizeof(kprobe_opcode_t);
> >> > > > 
> >> > > > 		/* To emulate trap based kprobes, preempt_disable here */
> >> > > > 		preempt_disable();
> >> > > > 		__this_cpu_write(current_kprobe, p);
> >> > > > 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> >> > > > 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> >> > > > 			__skip_singlestep(p, regs, kcb, orig_ip);
> >> > > > 			preempt_enable_no_resched();  
> >> > > 
> >> > > This preemption disabling and enabling looks rather strange. Looking at
> >> > > git blame, it appears this was added for jprobes. Can we remove it now
> >> > > that jprobes is going away?  
> >> > 
> >> > No, that is not for jprobes but for compatibility with kprobe's user
> >> > handler. Since this transformation is done silently, user can not
> >> > change their handler for ftrace case. So we need to keep this condition
> >> > same as original kprobes.
> >> > 
> >> > And anyway, for using smp_processor_id() for accessing per-cpu,
> >> > we should disable preemption, correct?
> >> 
> >> But as stated at the start of the function:
> >> 
> >>  /* Preempt is disabled by ftrace */
> > 
> > Ah, yes. So this is only for the jprobes.
> > 
> >> 
> >> 
> >> The reason I ask, is that we have for this function:
> >> 
> >> 		/* To emulate trap based kprobes, preempt_disable here */
> >> 		preempt_disable();
> >> 		__this_cpu_write(current_kprobe, p);
> >> 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> >> 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> >> 			__skip_singlestep(p, regs, kcb, orig_ip);
> >> 			preempt_enable_no_resched();
> >> 		}
> >> 
> >> And in arch/x86/kernel/kprobes/core.c we have:
> >> 
> >> 	preempt_disable();
> >> 
> >> 	kcb = get_kprobe_ctlblk();
> >> 	p = get_kprobe(addr);
> >> 
> >> 	if (p) {
> >> 		if (kprobe_running()) {
> >> 			if (reenter_kprobe(p, regs, kcb))
> >> 				return 1;
> >> 		} else {
> >> 			set_current_kprobe(p, regs, kcb);
> >> 			kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> >> 
> >> 			/*
> >> 			 * If we have no pre-handler or it returned 0, we
> >> 			 * continue with normal processing.  If we have a
> >> 			 * pre-handler and it returned non-zero, it prepped
> >> 			 * for calling the break_handler below on re-entry
> >> 			 * for jprobe processing, so get out doing nothing
> >> 			 * more here.
> >> 			 */
> >> 			if (!p->pre_handler || !p->pre_handler(p, regs))
> >> 				setup_singlestep(p, regs, kcb, 0);
> >> 			return 1;
> >> 
> >> 
> >> Which is why I thought it was for jprobes. I'm a bit confused about
> >> where preemption is enabled again.
> > 
> > You're right. So I would like to remove it with x86 jprobe support
> > code to avoid inconsistency.
> 
> I didn't understand that. Which code are you planning to remove? Can you 
> please elaborate? I thought we still need to disable preemption in the 
> ftrace handler.

Yes, kprobe_ftrace_handler itself must be run under preempt disabled
because it depends on a per-cpu variable. What I will remove is the
redundant preempt disable/enable_noresched (unbalanced) pair in the
kprobe_ftrace_handler, and jprobe x86 ports which is no more used.

Thank you,


-- 
Masami Hiramatsu <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-05  2:38       ` mhiramat
  2018-05-05  2:38         ` Masami Hiramatsu
  2018-05-05  7:46         ` naveen.n.rao
@ 2018-05-05 15:51         ` mhiramat
  2018-05-05 15:51           ` Masami Hiramatsu
  2018-05-07 15:30           ` rostedt
  2018-05-07 15:21         ` rostedt
  3 siblings, 2 replies; 72+ messages in thread
From: mhiramat @ 2018-05-05 15:51 UTC (permalink / raw)


On Sat, 5 May 2018 11:38:03 +0900
Masami Hiramatsu <mhiramat at kernel.org> wrote:

> On Fri, 4 May 2018 12:06:42 -0400
> Steven Rostedt <rostedt at goodmis.org> wrote:
> 
> > On Sat, 5 May 2018 00:48:28 +0900
> > Masami Hiramatsu <mhiramat at kernel.org> wrote:
> > 
> > > So the syntax will be
> > > 
> > > p[:EVENT] SYM[(CAST)|+OFFS] [FETCHARG]
> > > 
> > > And here is an example;
> > > 
> > > p:myevent vfs_read(void *file, char *buf, size_t count, void *pos) $arg1 $arg2
> > 
> > If we do this, why bother with $arg1 $arg2?
> 
> User may want to trace only some of them. :)
> 

OK, now I think it is a time to introduce new unified interface for dynamic events,
tracefs/dynamic_events and make uprobe_events and kprobe_events as symbolic-links
to the new interface file.

Actually, there is no reason we split those 2 interfaces, since
both have similar, but very clear syntax differences.

o Uprobe event definition
  p[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a uprobe
  r[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a return uprobe (uretprobe)
  -:[GRP/]EVENT                           : Clear uprobe or uretprobe event

o Kprobe event definition
  p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS]  : Set a probe
  r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS]  : Set a return probe
  -:[GRP/]EVENT                                         : Clear a probe

At first, it is clear that those can share the parser. 2nd, it is easy to
distinguish those, because Uprobe event must require the PATH which starts
with '/', on the other hand, Kprobe event must NOT start with '/'.
(both SYM and MOD will start with alphabet or '_', of course MEMADDR
will start with digits)

If we can merge those to unified dynamic_events interface, I think
'f[:[GRP/]EVENT] SYM(CAST)' is also acceptable, since it is no more
only for kprobe/uprobe. We can directly add some other dynamic
events via dynamic_events interface. ;)

Thank you,

-- 
Masami Hiramatsu <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-05 15:51         ` mhiramat
@ 2018-05-05 15:51           ` Masami Hiramatsu
  2018-05-07 15:30           ` rostedt
  1 sibling, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-05-05 15:51 UTC (permalink / raw)


On Sat, 5 May 2018 11:38:03 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> On Fri, 4 May 2018 12:06:42 -0400
> Steven Rostedt <rostedt@goodmis.org> wrote:
> 
> > On Sat, 5 May 2018 00:48:28 +0900
> > Masami Hiramatsu <mhiramat@kernel.org> wrote:
> > 
> > > So the syntax will be
> > > 
> > > p[:EVENT] SYM[(CAST)|+OFFS] [FETCHARG]
> > > 
> > > And here is an example;
> > > 
> > > p:myevent vfs_read(void *file, char *buf, size_t count, void *pos) $arg1 $arg2
> > 
> > If we do this, why bother with $arg1 $arg2?
> 
> User may want to trace only some of them. :)
> 

OK, now I think it is a time to introduce new unified interface for dynamic events,
tracefs/dynamic_events and make uprobe_events and kprobe_events as symbolic-links
to the new interface file.

Actually, there is no reason we split those 2 interfaces, since
both have similar, but very clear syntax differences.

o Uprobe event definition
  p[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a uprobe
  r[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a return uprobe (uretprobe)
  -:[GRP/]EVENT                           : Clear uprobe or uretprobe event

o Kprobe event definition
  p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS]  : Set a probe
  r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS]  : Set a return probe
  -:[GRP/]EVENT                                         : Clear a probe

At first, it is clear that those can share the parser. 2nd, it is easy to
distinguish those, because Uprobe event must require the PATH which starts
with '/', on the other hand, Kprobe event must NOT start with '/'.
(both SYM and MOD will start with alphabet or '_', of course MEMADDR
will start with digits)

If we can merge those to unified dynamic_events interface, I think
'f[:[GRP/]EVENT] SYM(CAST)' is also acceptable, since it is no more
only for kprobe/uprobe. We can directly add some other dynamic
events via dynamic_events interface. ;)

Thank you,

-- 
Masami Hiramatsu <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-05 14:32           ` mhiramat
  2018-05-05 14:32             ` Masami Hiramatsu
@ 2018-05-07  8:11             ` naveen.n.rao
  2018-05-07  8:11               ` Naveen N. Rao
  2018-05-07 14:53               ` mhiramat
  1 sibling, 2 replies; 72+ messages in thread
From: naveen.n.rao @ 2018-05-07  8:11 UTC (permalink / raw)


Masami Hiramatsu wrote:
> On Sat, 05 May 2018 13:16:04 +0530
> "Naveen N. Rao" <naveen.n.rao at linux.vnet.ibm.com> wrote:
> 
>> Masami Hiramatsu wrote:
>> > On Fri, 4 May 2018 12:06:42 -0400
>> > Steven Rostedt <rostedt at goodmis.org> wrote:
>> > 
>> >> On Sat, 5 May 2018 00:48:28 +0900
>> >> Masami Hiramatsu <mhiramat at kernel.org> wrote:
>> >> 
>> >> > > Also, when looking at the kprobe code, I was looking at this 
>> >> > > function:
>> >> > >   
>> >> > > > /* Ftrace callback handler for kprobes -- called under preepmt disabed */
>> >> > > > void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
>> >> > > > 			   struct ftrace_ops *ops, struct pt_regs *regs)
>> >> > > > {
>> >> > > > 	struct kprobe *p;
>> >> > > > 	struct kprobe_ctlblk *kcb;
>> >> > > > 
>> >> > > > 	/* Preempt is disabled by ftrace */
>> >> > > > 	p = get_kprobe((kprobe_opcode_t *)ip);
>> >> > > > 	if (unlikely(!p) || kprobe_disabled(p))
>> >> > > > 		return;
>> >> > > > 
>> >> > > > 	kcb = get_kprobe_ctlblk();
>> >> > > > 	if (kprobe_running()) {
>> >> > > > 		kprobes_inc_nmissed_count(p);
>> >> > > > 	} else {
>> >> > > > 		unsigned long orig_ip = regs->ip;
>> >> > > > 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
>> >> > > > 		regs->ip = ip + sizeof(kprobe_opcode_t);
>> >> > > > 
>> >> > > > 		/* To emulate trap based kprobes, preempt_disable here */
>> >> > > > 		preempt_disable();
>> >> > > > 		__this_cpu_write(current_kprobe, p);
>> >> > > > 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
>> >> > > > 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
>> >> > > > 			__skip_singlestep(p, regs, kcb, orig_ip);
>> >> > > > 			preempt_enable_no_resched();  
>> >> > > 
>> >> > > This preemption disabling and enabling looks rather strange. Looking at
>> >> > > git blame, it appears this was added for jprobes. Can we remove it now
>> >> > > that jprobes is going away?  
>> >> > 
>> >> > No, that is not for jprobes but for compatibility with kprobe's user
>> >> > handler. Since this transformation is done silently, user can not
>> >> > change their handler for ftrace case. So we need to keep this condition
>> >> > same as original kprobes.
>> >> > 
>> >> > And anyway, for using smp_processor_id() for accessing per-cpu,
>> >> > we should disable preemption, correct?
>> >> 
>> >> But as stated at the start of the function:
>> >> 
>> >>  /* Preempt is disabled by ftrace */
>> > 
>> > Ah, yes. So this is only for the jprobes.
>> > 
>> >> 
>> >> 
>> >> The reason I ask, is that we have for this function:
>> >> 
>> >> 		/* To emulate trap based kprobes, preempt_disable here */
>> >> 		preempt_disable();
>> >> 		__this_cpu_write(current_kprobe, p);
>> >> 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
>> >> 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
>> >> 			__skip_singlestep(p, regs, kcb, orig_ip);
>> >> 			preempt_enable_no_resched();
>> >> 		}
>> >> 
>> >> And in arch/x86/kernel/kprobes/core.c we have:
>> >> 
>> >> 	preempt_disable();
>> >> 
>> >> 	kcb = get_kprobe_ctlblk();
>> >> 	p = get_kprobe(addr);
>> >> 
>> >> 	if (p) {
>> >> 		if (kprobe_running()) {
>> >> 			if (reenter_kprobe(p, regs, kcb))
>> >> 				return 1;
>> >> 		} else {
>> >> 			set_current_kprobe(p, regs, kcb);
>> >> 			kcb->kprobe_status = KPROBE_HIT_ACTIVE;
>> >> 
>> >> 			/*
>> >> 			 * If we have no pre-handler or it returned 0, we
>> >> 			 * continue with normal processing.  If we have a
>> >> 			 * pre-handler and it returned non-zero, it prepped
>> >> 			 * for calling the break_handler below on re-entry
>> >> 			 * for jprobe processing, so get out doing nothing
>> >> 			 * more here.
>> >> 			 */
>> >> 			if (!p->pre_handler || !p->pre_handler(p, regs))
>> >> 				setup_singlestep(p, regs, kcb, 0);
>> >> 			return 1;
>> >> 
>> >> 
>> >> Which is why I thought it was for jprobes. I'm a bit confused about
>> >> where preemption is enabled again.
>> > 
>> > You're right. So I would like to remove it with x86 jprobe support
>> > code to avoid inconsistency.
>> 
>> I didn't understand that. Which code are you planning to remove? Can you 
>> please elaborate? I thought we still need to disable preemption in the 
>> ftrace handler.
> 
> Yes, kprobe_ftrace_handler itself must be run under preempt disabled
> because it depends on a per-cpu variable. What I will remove is the
> redundant preempt disable/enable_noresched (unbalanced) pair in the
> kprobe_ftrace_handler, and jprobe x86 ports which is no more used.

Won't that break out-of-tree users depending on returning a non-zero 
value to handle preemption differently? You seem to have alluded to it 
earlier in the mail chain above where you said that this is not just for 
jprobes (though it was added for jprobes as the main use case).

- Naveen


--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-07  8:11             ` naveen.n.rao
@ 2018-05-07  8:11               ` Naveen N. Rao
  2018-05-07 14:53               ` mhiramat
  1 sibling, 0 replies; 72+ messages in thread
From: Naveen N. Rao @ 2018-05-07  8:11 UTC (permalink / raw)


Masami Hiramatsu wrote:
> On Sat, 05 May 2018 13:16:04 +0530
> "Naveen N. Rao" <naveen.n.rao@linux.vnet.ibm.com> wrote:
> 
>> Masami Hiramatsu wrote:
>> > On Fri, 4 May 2018 12:06:42 -0400
>> > Steven Rostedt <rostedt@goodmis.org> wrote:
>> > 
>> >> On Sat, 5 May 2018 00:48:28 +0900
>> >> Masami Hiramatsu <mhiramat@kernel.org> wrote:
>> >> 
>> >> > > Also, when looking at the kprobe code, I was looking at this 
>> >> > > function:
>> >> > >   
>> >> > > > /* Ftrace callback handler for kprobes -- called under preepmt disabed */
>> >> > > > void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
>> >> > > > 			   struct ftrace_ops *ops, struct pt_regs *regs)
>> >> > > > {
>> >> > > > 	struct kprobe *p;
>> >> > > > 	struct kprobe_ctlblk *kcb;
>> >> > > > 
>> >> > > > 	/* Preempt is disabled by ftrace */
>> >> > > > 	p = get_kprobe((kprobe_opcode_t *)ip);
>> >> > > > 	if (unlikely(!p) || kprobe_disabled(p))
>> >> > > > 		return;
>> >> > > > 
>> >> > > > 	kcb = get_kprobe_ctlblk();
>> >> > > > 	if (kprobe_running()) {
>> >> > > > 		kprobes_inc_nmissed_count(p);
>> >> > > > 	} else {
>> >> > > > 		unsigned long orig_ip = regs->ip;
>> >> > > > 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
>> >> > > > 		regs->ip = ip + sizeof(kprobe_opcode_t);
>> >> > > > 
>> >> > > > 		/* To emulate trap based kprobes, preempt_disable here */
>> >> > > > 		preempt_disable();
>> >> > > > 		__this_cpu_write(current_kprobe, p);
>> >> > > > 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
>> >> > > > 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
>> >> > > > 			__skip_singlestep(p, regs, kcb, orig_ip);
>> >> > > > 			preempt_enable_no_resched();  
>> >> > > 
>> >> > > This preemption disabling and enabling looks rather strange. Looking at
>> >> > > git blame, it appears this was added for jprobes. Can we remove it now
>> >> > > that jprobes is going away?  
>> >> > 
>> >> > No, that is not for jprobes but for compatibility with kprobe's user
>> >> > handler. Since this transformation is done silently, user can not
>> >> > change their handler for ftrace case. So we need to keep this condition
>> >> > same as original kprobes.
>> >> > 
>> >> > And anyway, for using smp_processor_id() for accessing per-cpu,
>> >> > we should disable preemption, correct?
>> >> 
>> >> But as stated at the start of the function:
>> >> 
>> >>  /* Preempt is disabled by ftrace */
>> > 
>> > Ah, yes. So this is only for the jprobes.
>> > 
>> >> 
>> >> 
>> >> The reason I ask, is that we have for this function:
>> >> 
>> >> 		/* To emulate trap based kprobes, preempt_disable here */
>> >> 		preempt_disable();
>> >> 		__this_cpu_write(current_kprobe, p);
>> >> 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
>> >> 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
>> >> 			__skip_singlestep(p, regs, kcb, orig_ip);
>> >> 			preempt_enable_no_resched();
>> >> 		}
>> >> 
>> >> And in arch/x86/kernel/kprobes/core.c we have:
>> >> 
>> >> 	preempt_disable();
>> >> 
>> >> 	kcb = get_kprobe_ctlblk();
>> >> 	p = get_kprobe(addr);
>> >> 
>> >> 	if (p) {
>> >> 		if (kprobe_running()) {
>> >> 			if (reenter_kprobe(p, regs, kcb))
>> >> 				return 1;
>> >> 		} else {
>> >> 			set_current_kprobe(p, regs, kcb);
>> >> 			kcb->kprobe_status = KPROBE_HIT_ACTIVE;
>> >> 
>> >> 			/*
>> >> 			 * If we have no pre-handler or it returned 0, we
>> >> 			 * continue with normal processing.  If we have a
>> >> 			 * pre-handler and it returned non-zero, it prepped
>> >> 			 * for calling the break_handler below on re-entry
>> >> 			 * for jprobe processing, so get out doing nothing
>> >> 			 * more here.
>> >> 			 */
>> >> 			if (!p->pre_handler || !p->pre_handler(p, regs))
>> >> 				setup_singlestep(p, regs, kcb, 0);
>> >> 			return 1;
>> >> 
>> >> 
>> >> Which is why I thought it was for jprobes. I'm a bit confused about
>> >> where preemption is enabled again.
>> > 
>> > You're right. So I would like to remove it with x86 jprobe support
>> > code to avoid inconsistency.
>> 
>> I didn't understand that. Which code are you planning to remove? Can you 
>> please elaborate? I thought we still need to disable preemption in the 
>> ftrace handler.
> 
> Yes, kprobe_ftrace_handler itself must be run under preempt disabled
> because it depends on a per-cpu variable. What I will remove is the
> redundant preempt disable/enable_noresched (unbalanced) pair in the
> kprobe_ftrace_handler, and jprobe x86 ports which is no more used.

Won't that break out-of-tree users depending on returning a non-zero 
value to handle preemption differently? You seem to have alluded to it 
earlier in the mail chain above where you said that this is not just for 
jprobes (though it was added for jprobes as the main use case).

- Naveen


--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-07  8:11             ` naveen.n.rao
  2018-05-07  8:11               ` Naveen N. Rao
@ 2018-05-07 14:53               ` mhiramat
  2018-05-07 14:53                 ` Masami Hiramatsu
  2018-05-08 10:11                 ` naveen.n.rao
  1 sibling, 2 replies; 72+ messages in thread
From: mhiramat @ 2018-05-07 14:53 UTC (permalink / raw)


On Mon, 07 May 2018 13:41:53 +0530
"Naveen N. Rao" <naveen.n.rao at linux.vnet.ibm.com> wrote:

> Masami Hiramatsu wrote:
> > On Sat, 05 May 2018 13:16:04 +0530
> > "Naveen N. Rao" <naveen.n.rao at linux.vnet.ibm.com> wrote:
> > 
> >> Masami Hiramatsu wrote:
> >> > On Fri, 4 May 2018 12:06:42 -0400
> >> > Steven Rostedt <rostedt at goodmis.org> wrote:
> >> > 
> >> >> On Sat, 5 May 2018 00:48:28 +0900
> >> >> Masami Hiramatsu <mhiramat at kernel.org> wrote:
> >> >> 
> >> >> > > Also, when looking at the kprobe code, I was looking at this 
> >> >> > > function:
> >> >> > >   
> >> >> > > > /* Ftrace callback handler for kprobes -- called under preepmt disabed */
> >> >> > > > void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
> >> >> > > > 			   struct ftrace_ops *ops, struct pt_regs *regs)
> >> >> > > > {
> >> >> > > > 	struct kprobe *p;
> >> >> > > > 	struct kprobe_ctlblk *kcb;
> >> >> > > > 
> >> >> > > > 	/* Preempt is disabled by ftrace */
> >> >> > > > 	p = get_kprobe((kprobe_opcode_t *)ip);
> >> >> > > > 	if (unlikely(!p) || kprobe_disabled(p))
> >> >> > > > 		return;
> >> >> > > > 
> >> >> > > > 	kcb = get_kprobe_ctlblk();
> >> >> > > > 	if (kprobe_running()) {
> >> >> > > > 		kprobes_inc_nmissed_count(p);
> >> >> > > > 	} else {
> >> >> > > > 		unsigned long orig_ip = regs->ip;
> >> >> > > > 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
> >> >> > > > 		regs->ip = ip + sizeof(kprobe_opcode_t);
> >> >> > > > 
> >> >> > > > 		/* To emulate trap based kprobes, preempt_disable here */
> >> >> > > > 		preempt_disable();
> >> >> > > > 		__this_cpu_write(current_kprobe, p);
> >> >> > > > 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> >> >> > > > 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> >> >> > > > 			__skip_singlestep(p, regs, kcb, orig_ip);
> >> >> > > > 			preempt_enable_no_resched();  
> >> >> > > 
> >> >> > > This preemption disabling and enabling looks rather strange. Looking at
> >> >> > > git blame, it appears this was added for jprobes. Can we remove it now
> >> >> > > that jprobes is going away?  
> >> >> > 
> >> >> > No, that is not for jprobes but for compatibility with kprobe's user
> >> >> > handler. Since this transformation is done silently, user can not
> >> >> > change their handler for ftrace case. So we need to keep this condition
> >> >> > same as original kprobes.
> >> >> > 
> >> >> > And anyway, for using smp_processor_id() for accessing per-cpu,
> >> >> > we should disable preemption, correct?
> >> >> 
> >> >> But as stated at the start of the function:
> >> >> 
> >> >>  /* Preempt is disabled by ftrace */
> >> > 
> >> > Ah, yes. So this is only for the jprobes.
> >> > 
> >> >> 
> >> >> 
> >> >> The reason I ask, is that we have for this function:
> >> >> 
> >> >> 		/* To emulate trap based kprobes, preempt_disable here */
> >> >> 		preempt_disable();
> >> >> 		__this_cpu_write(current_kprobe, p);
> >> >> 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> >> >> 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> >> >> 			__skip_singlestep(p, regs, kcb, orig_ip);
> >> >> 			preempt_enable_no_resched();
> >> >> 		}
> >> >> 
> >> >> And in arch/x86/kernel/kprobes/core.c we have:
> >> >> 
> >> >> 	preempt_disable();
> >> >> 
> >> >> 	kcb = get_kprobe_ctlblk();
> >> >> 	p = get_kprobe(addr);
> >> >> 
> >> >> 	if (p) {
> >> >> 		if (kprobe_running()) {
> >> >> 			if (reenter_kprobe(p, regs, kcb))
> >> >> 				return 1;
> >> >> 		} else {
> >> >> 			set_current_kprobe(p, regs, kcb);
> >> >> 			kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> >> >> 
> >> >> 			/*
> >> >> 			 * If we have no pre-handler or it returned 0, we
> >> >> 			 * continue with normal processing.  If we have a
> >> >> 			 * pre-handler and it returned non-zero, it prepped
> >> >> 			 * for calling the break_handler below on re-entry
> >> >> 			 * for jprobe processing, so get out doing nothing
> >> >> 			 * more here.
> >> >> 			 */
> >> >> 			if (!p->pre_handler || !p->pre_handler(p, regs))
> >> >> 				setup_singlestep(p, regs, kcb, 0);
> >> >> 			return 1;
> >> >> 
> >> >> 
> >> >> Which is why I thought it was for jprobes. I'm a bit confused about
> >> >> where preemption is enabled again.
> >> > 
> >> > You're right. So I would like to remove it with x86 jprobe support
> >> > code to avoid inconsistency.
> >> 
> >> I didn't understand that. Which code are you planning to remove? Can you 
> >> please elaborate? I thought we still need to disable preemption in the 
> >> ftrace handler.
> > 
> > Yes, kprobe_ftrace_handler itself must be run under preempt disabled
> > because it depends on a per-cpu variable. What I will remove is the
> > redundant preempt disable/enable_noresched (unbalanced) pair in the
> > kprobe_ftrace_handler, and jprobe x86 ports which is no more used.
> 
> Won't that break out-of-tree users depending on returning a non-zero 
> value to handle preemption differently? You seem to have alluded to it 
> earlier in the mail chain above where you said that this is not just for 
> jprobes (though it was added for jprobes as the main use case).

No, all users are in tree already (function override for bpf and error-injection).
And also, for changing execution path by using kprobes, user handler must call
not only preempt_enable(), but also clear current_kprobe per-cpu variable which
is not exported to kmodules.

This means if there is such out-of-tree module, that must change the kernel or
hack the kernel to identify the address of curent_kprobe. If it requires such
a change or hack for the kernel, it is very easy to update the module too.

Thank you,

> 
> - Naveen
> 
> 


-- 
Masami Hiramatsu <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-07 14:53               ` mhiramat
@ 2018-05-07 14:53                 ` Masami Hiramatsu
  2018-05-08 10:11                 ` naveen.n.rao
  1 sibling, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-05-07 14:53 UTC (permalink / raw)


On Mon, 07 May 2018 13:41:53 +0530
"Naveen N. Rao" <naveen.n.rao@linux.vnet.ibm.com> wrote:

> Masami Hiramatsu wrote:
> > On Sat, 05 May 2018 13:16:04 +0530
> > "Naveen N. Rao" <naveen.n.rao@linux.vnet.ibm.com> wrote:
> > 
> >> Masami Hiramatsu wrote:
> >> > On Fri, 4 May 2018 12:06:42 -0400
> >> > Steven Rostedt <rostedt@goodmis.org> wrote:
> >> > 
> >> >> On Sat, 5 May 2018 00:48:28 +0900
> >> >> Masami Hiramatsu <mhiramat@kernel.org> wrote:
> >> >> 
> >> >> > > Also, when looking at the kprobe code, I was looking at this 
> >> >> > > function:
> >> >> > >   
> >> >> > > > /* Ftrace callback handler for kprobes -- called under preepmt disabed */
> >> >> > > > void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
> >> >> > > > 			   struct ftrace_ops *ops, struct pt_regs *regs)
> >> >> > > > {
> >> >> > > > 	struct kprobe *p;
> >> >> > > > 	struct kprobe_ctlblk *kcb;
> >> >> > > > 
> >> >> > > > 	/* Preempt is disabled by ftrace */
> >> >> > > > 	p = get_kprobe((kprobe_opcode_t *)ip);
> >> >> > > > 	if (unlikely(!p) || kprobe_disabled(p))
> >> >> > > > 		return;
> >> >> > > > 
> >> >> > > > 	kcb = get_kprobe_ctlblk();
> >> >> > > > 	if (kprobe_running()) {
> >> >> > > > 		kprobes_inc_nmissed_count(p);
> >> >> > > > 	} else {
> >> >> > > > 		unsigned long orig_ip = regs->ip;
> >> >> > > > 		/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
> >> >> > > > 		regs->ip = ip + sizeof(kprobe_opcode_t);
> >> >> > > > 
> >> >> > > > 		/* To emulate trap based kprobes, preempt_disable here */
> >> >> > > > 		preempt_disable();
> >> >> > > > 		__this_cpu_write(current_kprobe, p);
> >> >> > > > 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> >> >> > > > 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> >> >> > > > 			__skip_singlestep(p, regs, kcb, orig_ip);
> >> >> > > > 			preempt_enable_no_resched();  
> >> >> > > 
> >> >> > > This preemption disabling and enabling looks rather strange. Looking at
> >> >> > > git blame, it appears this was added for jprobes. Can we remove it now
> >> >> > > that jprobes is going away?  
> >> >> > 
> >> >> > No, that is not for jprobes but for compatibility with kprobe's user
> >> >> > handler. Since this transformation is done silently, user can not
> >> >> > change their handler for ftrace case. So we need to keep this condition
> >> >> > same as original kprobes.
> >> >> > 
> >> >> > And anyway, for using smp_processor_id() for accessing per-cpu,
> >> >> > we should disable preemption, correct?
> >> >> 
> >> >> But as stated at the start of the function:
> >> >> 
> >> >>  /* Preempt is disabled by ftrace */
> >> > 
> >> > Ah, yes. So this is only for the jprobes.
> >> > 
> >> >> 
> >> >> 
> >> >> The reason I ask, is that we have for this function:
> >> >> 
> >> >> 		/* To emulate trap based kprobes, preempt_disable here */
> >> >> 		preempt_disable();
> >> >> 		__this_cpu_write(current_kprobe, p);
> >> >> 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> >> >> 		if (!p->pre_handler || !p->pre_handler(p, regs)) {
> >> >> 			__skip_singlestep(p, regs, kcb, orig_ip);
> >> >> 			preempt_enable_no_resched();
> >> >> 		}
> >> >> 
> >> >> And in arch/x86/kernel/kprobes/core.c we have:
> >> >> 
> >> >> 	preempt_disable();
> >> >> 
> >> >> 	kcb = get_kprobe_ctlblk();
> >> >> 	p = get_kprobe(addr);
> >> >> 
> >> >> 	if (p) {
> >> >> 		if (kprobe_running()) {
> >> >> 			if (reenter_kprobe(p, regs, kcb))
> >> >> 				return 1;
> >> >> 		} else {
> >> >> 			set_current_kprobe(p, regs, kcb);
> >> >> 			kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> >> >> 
> >> >> 			/*
> >> >> 			 * If we have no pre-handler or it returned 0, we
> >> >> 			 * continue with normal processing.  If we have a
> >> >> 			 * pre-handler and it returned non-zero, it prepped
> >> >> 			 * for calling the break_handler below on re-entry
> >> >> 			 * for jprobe processing, so get out doing nothing
> >> >> 			 * more here.
> >> >> 			 */
> >> >> 			if (!p->pre_handler || !p->pre_handler(p, regs))
> >> >> 				setup_singlestep(p, regs, kcb, 0);
> >> >> 			return 1;
> >> >> 
> >> >> 
> >> >> Which is why I thought it was for jprobes. I'm a bit confused about
> >> >> where preemption is enabled again.
> >> > 
> >> > You're right. So I would like to remove it with x86 jprobe support
> >> > code to avoid inconsistency.
> >> 
> >> I didn't understand that. Which code are you planning to remove? Can you 
> >> please elaborate? I thought we still need to disable preemption in the 
> >> ftrace handler.
> > 
> > Yes, kprobe_ftrace_handler itself must be run under preempt disabled
> > because it depends on a per-cpu variable. What I will remove is the
> > redundant preempt disable/enable_noresched (unbalanced) pair in the
> > kprobe_ftrace_handler, and jprobe x86 ports which is no more used.
> 
> Won't that break out-of-tree users depending on returning a non-zero 
> value to handle preemption differently? You seem to have alluded to it 
> earlier in the mail chain above where you said that this is not just for 
> jprobes (though it was added for jprobes as the main use case).

No, all users are in tree already (function override for bpf and error-injection).
And also, for changing execution path by using kprobes, user handler must call
not only preempt_enable(), but also clear current_kprobe per-cpu variable which
is not exported to kmodules.

This means if there is such out-of-tree module, that must change the kernel or
hack the kernel to identify the address of curent_kprobe. If it requires such
a change or hack for the kernel, it is very easy to update the module too.

Thank you,

> 
> - Naveen
> 
> 


-- 
Masami Hiramatsu <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-05  2:38       ` mhiramat
                           ` (2 preceding siblings ...)
  2018-05-05 15:51         ` mhiramat
@ 2018-05-07 15:21         ` rostedt
  2018-05-07 15:21           ` Steven Rostedt
  3 siblings, 1 reply; 72+ messages in thread
From: rostedt @ 2018-05-07 15:21 UTC (permalink / raw)


On Sat, 5 May 2018 11:38:03 +0900
Masami Hiramatsu <mhiramat at kernel.org> wrote:

> On Fri, 4 May 2018 12:06:42 -0400
> Steven Rostedt <rostedt at goodmis.org> wrote:
> 
> > On Sat, 5 May 2018 00:48:28 +0900
> > Masami Hiramatsu <mhiramat at kernel.org> wrote:
> >   
> > > So the syntax will be
> > > 
> > > p[:EVENT] SYM[(CAST)|+OFFS] [FETCHARG]
> > > 
> > > And here is an example;
> > > 
> > > p:myevent vfs_read(void *file, char *buf, size_t count, void *pos) $arg1 $arg2  
> > 
> > If we do this, why bother with $arg1 $arg2?  
> 
> User may want to trace only some of them. :)

Yes, and this is why I like my solution of the NULL parameter, and you
don't need to show anything after what you want.

 p:myevent vfs_read(void *file, NULL, size_t count)

would only trace file and count, and ignore buf and pos.

-- Steve
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-07 15:21         ` rostedt
@ 2018-05-07 15:21           ` Steven Rostedt
  0 siblings, 0 replies; 72+ messages in thread
From: Steven Rostedt @ 2018-05-07 15:21 UTC (permalink / raw)


On Sat, 5 May 2018 11:38:03 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> On Fri, 4 May 2018 12:06:42 -0400
> Steven Rostedt <rostedt@goodmis.org> wrote:
> 
> > On Sat, 5 May 2018 00:48:28 +0900
> > Masami Hiramatsu <mhiramat@kernel.org> wrote:
> >   
> > > So the syntax will be
> > > 
> > > p[:EVENT] SYM[(CAST)|+OFFS] [FETCHARG]
> > > 
> > > And here is an example;
> > > 
> > > p:myevent vfs_read(void *file, char *buf, size_t count, void *pos) $arg1 $arg2  
> > 
> > If we do this, why bother with $arg1 $arg2?  
> 
> User may want to trace only some of them. :)

Yes, and this is why I like my solution of the NULL parameter, and you
don't need to show anything after what you want.

 p:myevent vfs_read(void *file, NULL, size_t count)

would only trace file and count, and ignore buf and pos.

-- Steve
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-05 15:51         ` mhiramat
  2018-05-05 15:51           ` Masami Hiramatsu
@ 2018-05-07 15:30           ` rostedt
  2018-05-07 15:30             ` Steven Rostedt
  2018-05-08  4:01             ` mhiramat
  1 sibling, 2 replies; 72+ messages in thread
From: rostedt @ 2018-05-07 15:30 UTC (permalink / raw)


On Sun, 6 May 2018 00:51:43 +0900
Masami Hiramatsu <mhiramat at kernel.org> wrote:

> OK, now I think it is a time to introduce new unified interface for dynamic events,
> tracefs/dynamic_events and make uprobe_events and kprobe_events as symbolic-links
> to the new interface file.

So basically make one file that does all the work?

I'm not sure we can keep the other files as symbolic links. Because we
don't want the kprobe_events showing up in the uprobe_events file, and
vice versa. We need to keep all this backward compatible.

But I do like the idea of one file to rule them all, approach.

-- Steve


> 
> Actually, there is no reason we split those 2 interfaces, since
> both have similar, but very clear syntax differences.
> 
> o Uprobe event definition
>   p[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a uprobe
>   r[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a return uprobe (uretprobe)
>   -:[GRP/]EVENT                           : Clear uprobe or uretprobe event
> 
> o Kprobe event definition
>   p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS]  : Set a probe
>   r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS]  : Set a return probe
>   -:[GRP/]EVENT                                         : Clear a probe
> 
> At first, it is clear that those can share the parser. 2nd, it is easy to
> distinguish those, because Uprobe event must require the PATH which starts
> with '/', on the other hand, Kprobe event must NOT start with '/'.
> (both SYM and MOD will start with alphabet or '_', of course MEMADDR
> will start with digits)
> 
> If we can merge those to unified dynamic_events interface, I think
> 'f[:[GRP/]EVENT] SYM(CAST)' is also acceptable, since it is no more
> only for kprobe/uprobe. We can directly add some other dynamic
> events via dynamic_events interface. ;)
> 
> Thank you,
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-07 15:30           ` rostedt
@ 2018-05-07 15:30             ` Steven Rostedt
  2018-05-08  4:01             ` mhiramat
  1 sibling, 0 replies; 72+ messages in thread
From: Steven Rostedt @ 2018-05-07 15:30 UTC (permalink / raw)


On Sun, 6 May 2018 00:51:43 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> OK, now I think it is a time to introduce new unified interface for dynamic events,
> tracefs/dynamic_events and make uprobe_events and kprobe_events as symbolic-links
> to the new interface file.

So basically make one file that does all the work?

I'm not sure we can keep the other files as symbolic links. Because we
don't want the kprobe_events showing up in the uprobe_events file, and
vice versa. We need to keep all this backward compatible.

But I do like the idea of one file to rule them all, approach.

-- Steve


> 
> Actually, there is no reason we split those 2 interfaces, since
> both have similar, but very clear syntax differences.
> 
> o Uprobe event definition
>   p[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a uprobe
>   r[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a return uprobe (uretprobe)
>   -:[GRP/]EVENT                           : Clear uprobe or uretprobe event
> 
> o Kprobe event definition
>   p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS]  : Set a probe
>   r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS]  : Set a return probe
>   -:[GRP/]EVENT                                         : Clear a probe
> 
> At first, it is clear that those can share the parser. 2nd, it is easy to
> distinguish those, because Uprobe event must require the PATH which starts
> with '/', on the other hand, Kprobe event must NOT start with '/'.
> (both SYM and MOD will start with alphabet or '_', of course MEMADDR
> will start with digits)
> 
> If we can merge those to unified dynamic_events interface, I think
> 'f[:[GRP/]EVENT] SYM(CAST)' is also acceptable, since it is no more
> only for kprobe/uprobe. We can directly add some other dynamic
> events via dynamic_events interface. ;)
> 
> Thank you,
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-07 15:30           ` rostedt
  2018-05-07 15:30             ` Steven Rostedt
@ 2018-05-08  4:01             ` mhiramat
  2018-05-08  4:01               ` Masami Hiramatsu
  1 sibling, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-05-08  4:01 UTC (permalink / raw)


On Mon, 7 May 2018 11:30:03 -0400
Steven Rostedt <rostedt at goodmis.org> wrote:

> On Sun, 6 May 2018 00:51:43 +0900
> Masami Hiramatsu <mhiramat at kernel.org> wrote:
> 
> > OK, now I think it is a time to introduce new unified interface for dynamic events,
> > tracefs/dynamic_events and make uprobe_events and kprobe_events as symbolic-links
> > to the new interface file.
> 
> So basically make one file that does all the work?
> 
> I'm not sure we can keep the other files as symbolic links. Because we
> don't want the kprobe_events showing up in the uprobe_events file, and
> vice versa. We need to keep all this backward compatible.

Good catch!
Can't we check which file the user opened? If not, even though
we can setup a filter in ops->open().

> 
> But I do like the idea of one file to rule them all, approach.

Thanks!

> 
> -- Steve
> 
> 
> > 
> > Actually, there is no reason we split those 2 interfaces, since
> > both have similar, but very clear syntax differences.
> > 
> > o Uprobe event definition
> >   p[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a uprobe
> >   r[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a return uprobe (uretprobe)
> >   -:[GRP/]EVENT                           : Clear uprobe or uretprobe event
> > 
> > o Kprobe event definition
> >   p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS]  : Set a probe
> >   r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS]  : Set a return probe
> >   -:[GRP/]EVENT                                         : Clear a probe
> > 
> > At first, it is clear that those can share the parser. 2nd, it is easy to
> > distinguish those, because Uprobe event must require the PATH which starts
> > with '/', on the other hand, Kprobe event must NOT start with '/'.
> > (both SYM and MOD will start with alphabet or '_', of course MEMADDR
> > will start with digits)
> > 
> > If we can merge those to unified dynamic_events interface, I think
> > 'f[:[GRP/]EVENT] SYM(CAST)' is also acceptable, since it is no more
> > only for kprobe/uprobe. We can directly add some other dynamic
> > events via dynamic_events interface. ;)
> > 
> > Thank you,
> > 
> 


-- 
Masami Hiramatsu <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-08  4:01             ` mhiramat
@ 2018-05-08  4:01               ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-05-08  4:01 UTC (permalink / raw)


On Mon, 7 May 2018 11:30:03 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Sun, 6 May 2018 00:51:43 +0900
> Masami Hiramatsu <mhiramat@kernel.org> wrote:
> 
> > OK, now I think it is a time to introduce new unified interface for dynamic events,
> > tracefs/dynamic_events and make uprobe_events and kprobe_events as symbolic-links
> > to the new interface file.
> 
> So basically make one file that does all the work?
> 
> I'm not sure we can keep the other files as symbolic links. Because we
> don't want the kprobe_events showing up in the uprobe_events file, and
> vice versa. We need to keep all this backward compatible.

Good catch!
Can't we check which file the user opened? If not, even though
we can setup a filter in ops->open().

> 
> But I do like the idea of one file to rule them all, approach.

Thanks!

> 
> -- Steve
> 
> 
> > 
> > Actually, there is no reason we split those 2 interfaces, since
> > both have similar, but very clear syntax differences.
> > 
> > o Uprobe event definition
> >   p[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a uprobe
> >   r[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a return uprobe (uretprobe)
> >   -:[GRP/]EVENT                           : Clear uprobe or uretprobe event
> > 
> > o Kprobe event definition
> >   p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS]  : Set a probe
> >   r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS]  : Set a return probe
> >   -:[GRP/]EVENT                                         : Clear a probe
> > 
> > At first, it is clear that those can share the parser. 2nd, it is easy to
> > distinguish those, because Uprobe event must require the PATH which starts
> > with '/', on the other hand, Kprobe event must NOT start with '/'.
> > (both SYM and MOD will start with alphabet or '_', of course MEMADDR
> > will start with digits)
> > 
> > If we can merge those to unified dynamic_events interface, I think
> > 'f[:[GRP/]EVENT] SYM(CAST)' is also acceptable, since it is no more
> > only for kprobe/uprobe. We can directly add some other dynamic
> > events via dynamic_events interface. ;)
> > 
> > Thank you,
> > 
> 


-- 
Masami Hiramatsu <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-07 14:53               ` mhiramat
  2018-05-07 14:53                 ` Masami Hiramatsu
@ 2018-05-08 10:11                 ` naveen.n.rao
  2018-05-08 10:11                   ` Naveen N. Rao
  2018-05-08 15:02                   ` mhiramat
  1 sibling, 2 replies; 72+ messages in thread
From: naveen.n.rao @ 2018-05-08 10:11 UTC (permalink / raw)


Masami Hiramatsu wrote:
> On Mon, 07 May 2018 13:41:53 +0530
> "Naveen N. Rao" <naveen.n.rao at linux.vnet.ibm.com> wrote:
>> >> 
>> >> I didn't understand that. Which code are you planning to remove? Can you 
>> >> please elaborate? I thought we still need to disable preemption in the 
>> >> ftrace handler.
>> > 
>> > Yes, kprobe_ftrace_handler itself must be run under preempt disabled
>> > because it depends on a per-cpu variable. What I will remove is the
>> > redundant preempt disable/enable_noresched (unbalanced) pair in the
>> > kprobe_ftrace_handler, and jprobe x86 ports which is no more used.
>> 
>> Won't that break out-of-tree users depending on returning a non-zero 
>> value to handle preemption differently? You seem to have alluded to it 
>> earlier in the mail chain above where you said that this is not just for 
>> jprobes (though it was added for jprobes as the main use case).
> 
> No, all users are in tree already (function override for bpf and error-injection).

Ok, so BPF error injection is a new user that can return a non-zero 
value from the pre handler. It looks like it can use KPROBES_ON_FTRACE 
too.

In that case, on function entry, we call into kprobe_ftrace_handler() 
which will call fei_kprobe_handler(), which can re-enable premption 
before returning 1. So, if you remove the additional 
prempt_disable()/enable_no_resched() in kprobe_ftrace_handler(), then it 
will become imbalanced, right?

> And also, for changing execution path by using kprobes, user handler must call
> not only preempt_enable(), but also clear current_kprobe per-cpu variable which
> is not exported to kmodules.

Ok, good point. And that means we don't have any external users any 
more.

Thanks,
Naveen


--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-08 10:11                 ` naveen.n.rao
@ 2018-05-08 10:11                   ` Naveen N. Rao
  2018-05-08 15:02                   ` mhiramat
  1 sibling, 0 replies; 72+ messages in thread
From: Naveen N. Rao @ 2018-05-08 10:11 UTC (permalink / raw)


Masami Hiramatsu wrote:
> On Mon, 07 May 2018 13:41:53 +0530
> "Naveen N. Rao" <naveen.n.rao@linux.vnet.ibm.com> wrote:
>> >> 
>> >> I didn't understand that. Which code are you planning to remove? Can you 
>> >> please elaborate? I thought we still need to disable preemption in the 
>> >> ftrace handler.
>> > 
>> > Yes, kprobe_ftrace_handler itself must be run under preempt disabled
>> > because it depends on a per-cpu variable. What I will remove is the
>> > redundant preempt disable/enable_noresched (unbalanced) pair in the
>> > kprobe_ftrace_handler, and jprobe x86 ports which is no more used.
>> 
>> Won't that break out-of-tree users depending on returning a non-zero 
>> value to handle preemption differently? You seem to have alluded to it 
>> earlier in the mail chain above where you said that this is not just for 
>> jprobes (though it was added for jprobes as the main use case).
> 
> No, all users are in tree already (function override for bpf and error-injection).

Ok, so BPF error injection is a new user that can return a non-zero 
value from the pre handler. It looks like it can use KPROBES_ON_FTRACE 
too.

In that case, on function entry, we call into kprobe_ftrace_handler() 
which will call fei_kprobe_handler(), which can re-enable premption 
before returning 1. So, if you remove the additional 
prempt_disable()/enable_no_resched() in kprobe_ftrace_handler(), then it 
will become imbalanced, right?

> And also, for changing execution path by using kprobes, user handler must call
> not only preempt_enable(), but also clear current_kprobe per-cpu variable which
> is not exported to kmodules.

Ok, good point. And that means we don't have any external users any 
more.

Thanks,
Naveen


--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-08 10:11                 ` naveen.n.rao
  2018-05-08 10:11                   ` Naveen N. Rao
@ 2018-05-08 15:02                   ` mhiramat
  2018-05-08 15:02                     ` Masami Hiramatsu
  2018-05-08 18:01                     ` naveen.n.rao
  1 sibling, 2 replies; 72+ messages in thread
From: mhiramat @ 2018-05-08 15:02 UTC (permalink / raw)


On Tue, 08 May 2018 15:41:11 +0530
"Naveen N. Rao" <naveen.n.rao at linux.vnet.ibm.com> wrote:

> Masami Hiramatsu wrote:
> > On Mon, 07 May 2018 13:41:53 +0530
> > "Naveen N. Rao" <naveen.n.rao at linux.vnet.ibm.com> wrote:
> >> >> 
> >> >> I didn't understand that. Which code are you planning to remove? Can you 
> >> >> please elaborate? I thought we still need to disable preemption in the 
> >> >> ftrace handler.
> >> > 
> >> > Yes, kprobe_ftrace_handler itself must be run under preempt disabled
> >> > because it depends on a per-cpu variable. What I will remove is the
> >> > redundant preempt disable/enable_noresched (unbalanced) pair in the
> >> > kprobe_ftrace_handler, and jprobe x86 ports which is no more used.
> >> 
> >> Won't that break out-of-tree users depending on returning a non-zero 
> >> value to handle preemption differently? You seem to have alluded to it 
> >> earlier in the mail chain above where you said that this is not just for 
> >> jprobes (though it was added for jprobes as the main use case).
> > 
> > No, all users are in tree already (function override for bpf and error-injection).
> 
> Ok, so BPF error injection is a new user that can return a non-zero 
> value from the pre handler. It looks like it can use KPROBES_ON_FTRACE 
> too.
> 
> In that case, on function entry, we call into kprobe_ftrace_handler() 
> which will call fei_kprobe_handler(), which can re-enable premption 
> before returning 1. So, if you remove the additional 
> prempt_disable()/enable_no_resched() in kprobe_ftrace_handler(), then it 
> will become imbalanced, right?

Right. So we have to fix both at once. Please check the patch below.

https://patchwork.kernel.org/patch/10386171/

(Sorry, I missed to cc you...)

> 
> > And also, for changing execution path by using kprobes, user handler must call
> > not only preempt_enable(), but also clear current_kprobe per-cpu variable which
> > is not exported to kmodules.
> 
> Ok, good point. And that means we don't have any external users any 
> more.

Yes :)

Thank you,

> 
> Thanks,
> Naveen
> 
> 


-- 
Masami Hiramatsu <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-08 15:02                   ` mhiramat
@ 2018-05-08 15:02                     ` Masami Hiramatsu
  2018-05-08 18:01                     ` naveen.n.rao
  1 sibling, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-05-08 15:02 UTC (permalink / raw)


On Tue, 08 May 2018 15:41:11 +0530
"Naveen N. Rao" <naveen.n.rao@linux.vnet.ibm.com> wrote:

> Masami Hiramatsu wrote:
> > On Mon, 07 May 2018 13:41:53 +0530
> > "Naveen N. Rao" <naveen.n.rao@linux.vnet.ibm.com> wrote:
> >> >> 
> >> >> I didn't understand that. Which code are you planning to remove? Can you 
> >> >> please elaborate? I thought we still need to disable preemption in the 
> >> >> ftrace handler.
> >> > 
> >> > Yes, kprobe_ftrace_handler itself must be run under preempt disabled
> >> > because it depends on a per-cpu variable. What I will remove is the
> >> > redundant preempt disable/enable_noresched (unbalanced) pair in the
> >> > kprobe_ftrace_handler, and jprobe x86 ports which is no more used.
> >> 
> >> Won't that break out-of-tree users depending on returning a non-zero 
> >> value to handle preemption differently? You seem to have alluded to it 
> >> earlier in the mail chain above where you said that this is not just for 
> >> jprobes (though it was added for jprobes as the main use case).
> > 
> > No, all users are in tree already (function override for bpf and error-injection).
> 
> Ok, so BPF error injection is a new user that can return a non-zero 
> value from the pre handler. It looks like it can use KPROBES_ON_FTRACE 
> too.
> 
> In that case, on function entry, we call into kprobe_ftrace_handler() 
> which will call fei_kprobe_handler(), which can re-enable premption 
> before returning 1. So, if you remove the additional 
> prempt_disable()/enable_no_resched() in kprobe_ftrace_handler(), then it 
> will become imbalanced, right?

Right. So we have to fix both at once. Please check the patch below.

https://patchwork.kernel.org/patch/10386171/

(Sorry, I missed to cc you...)

> 
> > And also, for changing execution path by using kprobes, user handler must call
> > not only preempt_enable(), but also clear current_kprobe per-cpu variable which
> > is not exported to kmodules.
> 
> Ok, good point. And that means we don't have any external users any 
> more.

Yes :)

Thank you,

> 
> Thanks,
> Naveen
> 
> 


-- 
Masami Hiramatsu <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-08 15:02                   ` mhiramat
  2018-05-08 15:02                     ` Masami Hiramatsu
@ 2018-05-08 18:01                     ` naveen.n.rao
  2018-05-08 18:01                       ` Naveen N. Rao
  1 sibling, 1 reply; 72+ messages in thread
From: naveen.n.rao @ 2018-05-08 18:01 UTC (permalink / raw)


Masami Hiramatsu wrote:
> On Tue, 08 May 2018 15:41:11 +0530
> "Naveen N. Rao" <naveen.n.rao at linux.vnet.ibm.com> wrote:
> 
>> Masami Hiramatsu wrote:
>> > On Mon, 07 May 2018 13:41:53 +0530
>> > "Naveen N. Rao" <naveen.n.rao at linux.vnet.ibm.com> wrote:
>> >> >> 
>> >> >> I didn't understand that. Which code are you planning to remove? Can you 
>> >> >> please elaborate? I thought we still need to disable preemption in the 
>> >> >> ftrace handler.
>> >> > 
>> >> > Yes, kprobe_ftrace_handler itself must be run under preempt disabled
>> >> > because it depends on a per-cpu variable. What I will remove is the
>> >> > redundant preempt disable/enable_noresched (unbalanced) pair in the
>> >> > kprobe_ftrace_handler, and jprobe x86 ports which is no more used.
>> >> 
>> >> Won't that break out-of-tree users depending on returning a non-zero 
>> >> value to handle preemption differently? You seem to have alluded to it 
>> >> earlier in the mail chain above where you said that this is not just for 
>> >> jprobes (though it was added for jprobes as the main use case).
>> > 
>> > No, all users are in tree already (function override for bpf and error-injection).
>> 
>> Ok, so BPF error injection is a new user that can return a non-zero 
>> value from the pre handler. It looks like it can use KPROBES_ON_FTRACE 
>> too.
>> 
>> In that case, on function entry, we call into kprobe_ftrace_handler() 
>> which will call fei_kprobe_handler(), which can re-enable premption 
>> before returning 1. So, if you remove the additional 
>> prempt_disable()/enable_no_resched() in kprobe_ftrace_handler(), then it 
>> will become imbalanced, right?
> 
> Right. So we have to fix both at once. Please check the patch below.
> 
> https://patchwork.kernel.org/patch/10386171/

Ah, so your intent was to change the semantics of how the pre handler 
works! I missed that aspect. This now makes sense. Thanks for the 
clarification.

- Naveen


--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-05-08 18:01                     ` naveen.n.rao
@ 2018-05-08 18:01                       ` Naveen N. Rao
  0 siblings, 0 replies; 72+ messages in thread
From: Naveen N. Rao @ 2018-05-08 18:01 UTC (permalink / raw)


Masami Hiramatsu wrote:
> On Tue, 08 May 2018 15:41:11 +0530
> "Naveen N. Rao" <naveen.n.rao@linux.vnet.ibm.com> wrote:
> 
>> Masami Hiramatsu wrote:
>> > On Mon, 07 May 2018 13:41:53 +0530
>> > "Naveen N. Rao" <naveen.n.rao@linux.vnet.ibm.com> wrote:
>> >> >> 
>> >> >> I didn't understand that. Which code are you planning to remove? Can you 
>> >> >> please elaborate? I thought we still need to disable preemption in the 
>> >> >> ftrace handler.
>> >> > 
>> >> > Yes, kprobe_ftrace_handler itself must be run under preempt disabled
>> >> > because it depends on a per-cpu variable. What I will remove is the
>> >> > redundant preempt disable/enable_noresched (unbalanced) pair in the
>> >> > kprobe_ftrace_handler, and jprobe x86 ports which is no more used.
>> >> 
>> >> Won't that break out-of-tree users depending on returning a non-zero 
>> >> value to handle preemption differently? You seem to have alluded to it 
>> >> earlier in the mail chain above where you said that this is not just for 
>> >> jprobes (though it was added for jprobes as the main use case).
>> > 
>> > No, all users are in tree already (function override for bpf and error-injection).
>> 
>> Ok, so BPF error injection is a new user that can return a non-zero 
>> value from the pre handler. It looks like it can use KPROBES_ON_FTRACE 
>> too.
>> 
>> In that case, on function entry, we call into kprobe_ftrace_handler() 
>> which will call fei_kprobe_handler(), which can re-enable premption 
>> before returning 1. So, if you remove the additional 
>> prempt_disable()/enable_no_resched() in kprobe_ftrace_handler(), then it 
>> will become imbalanced, right?
> 
> Right. So we have to fix both at once. Please check the patch below.
> 
> https://patchwork.kernel.org/patch/10386171/

Ah, so your intent was to change the semantics of how the pre handler 
works! I missed that aspect. This now makes sense. Thanks for the 
clarification.

- Naveen


--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
                   ` (18 preceding siblings ...)
  2018-05-03 22:11 ` rostedt
@ 2018-06-21 20:16 ` rostedt
  2018-06-21 20:16   ` Steven Rostedt
  2018-06-22  6:04   ` mhiramat
  19 siblings, 2 replies; 72+ messages in thread
From: rostedt @ 2018-06-21 20:16 UTC (permalink / raw)


Hi Masami,

Are you going to post another version of this patch set?

-- Steve


On Wed, 25 Apr 2018 21:16:06 +0900
Masami Hiramatsu <mhiramat at kernel.org> wrote:

> Hi,
> 
> This is the 7th version of the fetch-arg improvement series.
> This includes variable changes on fetcharg framework like,
> 
> - Add fetcharg testcases (syntax, argN, symbol, string and array)
>   and probepoint testcase.
> - Rewrite fetcharg framework with fetch_insn, switch-case based
>   instead of function pointer.
> - Add "symbol" type support, which shows symbol+offset instead of
>   address value.
> - Add "$argN" fetcharg, which fetches function parameters.
>   (currently only for x86-64)
> - Add array type support (including string arrary :) ) ,
>   which enables to get fixed length array from probe-events.
> - Add array type support for perf-probe, so that user can
>   dump partial array entries.
> 
> V6 is here:
>  https://lkml.org/lkml/2018/3/17/75
> 
> Changes from the v6 are here:
>  [6/16]  - Fix to return an error if failed to fetch string and
>         fill zero-length data_loc in error case.
>  [11/16] - Update document for restructured text.
>  [15/16] - Fix README test.
>  [16/16] - Add type-casting description (and note) to documentation.
> 
> And rebased on the latest Steve's ftrace/core branch.
> 
> Thank you,
> 
> ---
> 
> Masami Hiramatsu (16):
>       tracing: probeevent: Cleanup print argument functions
>       tracing: probeevent: Cleanup argument field definition
>       tracing: probeevent: Remove NOKPROBE_SYMBOL from print functions
>       tracing: probeevent: Introduce new argument fetching code
>       tracing: probeevent: Unify fetch type tables
>       tracing: probeevent: Return consumed bytes of dynamic area
>       tracing: probeevent: Append traceprobe_ for exported function
>       tracing: probeevent: Unify fetch_insn processing common part
>       tracing: probeevent: Add symbol type
>       x86: ptrace: Add function argument access API
>       tracing: probeevent: Add $argN for accessing function args
>       tracing: probeevent: Add array type support
>       selftests: ftrace: Add a testcase for symbol type
>       selftests: ftrace: Add a testcase for $argN with kprobe_event
>       selftests: ftrace: Add a testcase for array type with kprobe_event
>       perf-probe: Add array argument support
> 
> 
>  Documentation/trace/kprobetrace.rst                |   23 +
>  arch/Kconfig                                       |    7 
>  arch/x86/Kconfig                                   |    1 
>  arch/x86/include/asm/ptrace.h                      |   38 +
>  kernel/trace/trace.c                               |    9 
>  kernel/trace/trace_kprobe.c                        |  358 ++++--------
>  kernel/trace/trace_probe.c                         |  620 +++++++++-----------
>  kernel/trace/trace_probe.h                         |  282 +++------
>  kernel/trace/trace_probe_tmpl.h                    |  216 +++++++
>  kernel/trace/trace_uprobe.c                        |  176 ++----
>  tools/perf/Documentation/perf-probe.txt            |   12 
>  tools/perf/util/probe-event.c                      |   20 +
>  tools/perf/util/probe-event.h                      |    2 
>  tools/perf/util/probe-file.c                       |    5 
>  tools/perf/util/probe-file.h                       |    1 
>  tools/perf/util/probe-finder.c                     |   95 ++-
>  .../ftrace/test.d/kprobe/kprobe_args_argN.tc       |   25 +
>  .../ftrace/test.d/kprobe/kprobe_args_array.tc      |   92 +++
>  .../ftrace/test.d/kprobe/kprobe_args_symbol.tc     |   77 ++
>  19 files changed, 1127 insertions(+), 932 deletions(-)
>  create mode 100644 kernel/trace/trace_probe_tmpl.h
>  create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc
>  create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc
>  create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc
> 
> --
> Masami Hiramatsu (Linaro) <mhiramat at kernel.org>

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-06-21 20:16 ` rostedt
@ 2018-06-21 20:16   ` Steven Rostedt
  2018-06-22  6:04   ` mhiramat
  1 sibling, 0 replies; 72+ messages in thread
From: Steven Rostedt @ 2018-06-21 20:16 UTC (permalink / raw)


Hi Masami,

Are you going to post another version of this patch set?

-- Steve


On Wed, 25 Apr 2018 21:16:06 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> Hi,
> 
> This is the 7th version of the fetch-arg improvement series.
> This includes variable changes on fetcharg framework like,
> 
> - Add fetcharg testcases (syntax, argN, symbol, string and array)
>   and probepoint testcase.
> - Rewrite fetcharg framework with fetch_insn, switch-case based
>   instead of function pointer.
> - Add "symbol" type support, which shows symbol+offset instead of
>   address value.
> - Add "$argN" fetcharg, which fetches function parameters.
>   (currently only for x86-64)
> - Add array type support (including string arrary :) ) ,
>   which enables to get fixed length array from probe-events.
> - Add array type support for perf-probe, so that user can
>   dump partial array entries.
> 
> V6 is here:
>  https://lkml.org/lkml/2018/3/17/75
> 
> Changes from the v6 are here:
>  [6/16]  - Fix to return an error if failed to fetch string and
>         fill zero-length data_loc in error case.
>  [11/16] - Update document for restructured text.
>  [15/16] - Fix README test.
>  [16/16] - Add type-casting description (and note) to documentation.
> 
> And rebased on the latest Steve's ftrace/core branch.
> 
> Thank you,
> 
> ---
> 
> Masami Hiramatsu (16):
>       tracing: probeevent: Cleanup print argument functions
>       tracing: probeevent: Cleanup argument field definition
>       tracing: probeevent: Remove NOKPROBE_SYMBOL from print functions
>       tracing: probeevent: Introduce new argument fetching code
>       tracing: probeevent: Unify fetch type tables
>       tracing: probeevent: Return consumed bytes of dynamic area
>       tracing: probeevent: Append traceprobe_ for exported function
>       tracing: probeevent: Unify fetch_insn processing common part
>       tracing: probeevent: Add symbol type
>       x86: ptrace: Add function argument access API
>       tracing: probeevent: Add $argN for accessing function args
>       tracing: probeevent: Add array type support
>       selftests: ftrace: Add a testcase for symbol type
>       selftests: ftrace: Add a testcase for $argN with kprobe_event
>       selftests: ftrace: Add a testcase for array type with kprobe_event
>       perf-probe: Add array argument support
> 
> 
>  Documentation/trace/kprobetrace.rst                |   23 +
>  arch/Kconfig                                       |    7 
>  arch/x86/Kconfig                                   |    1 
>  arch/x86/include/asm/ptrace.h                      |   38 +
>  kernel/trace/trace.c                               |    9 
>  kernel/trace/trace_kprobe.c                        |  358 ++++--------
>  kernel/trace/trace_probe.c                         |  620 +++++++++-----------
>  kernel/trace/trace_probe.h                         |  282 +++------
>  kernel/trace/trace_probe_tmpl.h                    |  216 +++++++
>  kernel/trace/trace_uprobe.c                        |  176 ++----
>  tools/perf/Documentation/perf-probe.txt            |   12 
>  tools/perf/util/probe-event.c                      |   20 +
>  tools/perf/util/probe-event.h                      |    2 
>  tools/perf/util/probe-file.c                       |    5 
>  tools/perf/util/probe-file.h                       |    1 
>  tools/perf/util/probe-finder.c                     |   95 ++-
>  .../ftrace/test.d/kprobe/kprobe_args_argN.tc       |   25 +
>  .../ftrace/test.d/kprobe/kprobe_args_array.tc      |   92 +++
>  .../ftrace/test.d/kprobe/kprobe_args_symbol.tc     |   77 ++
>  19 files changed, 1127 insertions(+), 932 deletions(-)
>  create mode 100644 kernel/trace/trace_probe_tmpl.h
>  create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc
>  create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc
>  create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc
> 
> --
> Masami Hiramatsu (Linaro) <mhiramat at kernel.org>

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-06-21 20:16 ` rostedt
  2018-06-21 20:16   ` Steven Rostedt
@ 2018-06-22  6:04   ` mhiramat
  2018-06-22  6:04     ` Masami Hiramatsu
  1 sibling, 1 reply; 72+ messages in thread
From: mhiramat @ 2018-06-22  6:04 UTC (permalink / raw)


Hi Steve,

On Thu, 21 Jun 2018 16:16:48 -0400
Steven Rostedt <rostedt at goodmis.org> wrote:

> Hi Masami,
> 
> Are you going to post another version of this patch set?

No, this is the latest one which I sent to LKML.
Oops, it was 2 month ago now...

Thank you,

> 
> -- Steve
> 
> 
> On Wed, 25 Apr 2018 21:16:06 +0900
> Masami Hiramatsu <mhiramat at kernel.org> wrote:
> 
> > Hi,
> > 
> > This is the 7th version of the fetch-arg improvement series.
> > This includes variable changes on fetcharg framework like,
> > 
> > - Add fetcharg testcases (syntax, argN, symbol, string and array)
> >   and probepoint testcase.
> > - Rewrite fetcharg framework with fetch_insn, switch-case based
> >   instead of function pointer.
> > - Add "symbol" type support, which shows symbol+offset instead of
> >   address value.
> > - Add "$argN" fetcharg, which fetches function parameters.
> >   (currently only for x86-64)
> > - Add array type support (including string arrary :) ) ,
> >   which enables to get fixed length array from probe-events.
> > - Add array type support for perf-probe, so that user can
> >   dump partial array entries.
> > 
> > V6 is here:
> >  https://lkml.org/lkml/2018/3/17/75
> > 
> > Changes from the v6 are here:
> >  [6/16]  - Fix to return an error if failed to fetch string and
> >         fill zero-length data_loc in error case.
> >  [11/16] - Update document for restructured text.
> >  [15/16] - Fix README test.
> >  [16/16] - Add type-casting description (and note) to documentation.
> > 
> > And rebased on the latest Steve's ftrace/core branch.
> > 
> > Thank you,
> > 
> > ---
> > 
> > Masami Hiramatsu (16):
> >       tracing: probeevent: Cleanup print argument functions
> >       tracing: probeevent: Cleanup argument field definition
> >       tracing: probeevent: Remove NOKPROBE_SYMBOL from print functions
> >       tracing: probeevent: Introduce new argument fetching code
> >       tracing: probeevent: Unify fetch type tables
> >       tracing: probeevent: Return consumed bytes of dynamic area
> >       tracing: probeevent: Append traceprobe_ for exported function
> >       tracing: probeevent: Unify fetch_insn processing common part
> >       tracing: probeevent: Add symbol type
> >       x86: ptrace: Add function argument access API
> >       tracing: probeevent: Add $argN for accessing function args
> >       tracing: probeevent: Add array type support
> >       selftests: ftrace: Add a testcase for symbol type
> >       selftests: ftrace: Add a testcase for $argN with kprobe_event
> >       selftests: ftrace: Add a testcase for array type with kprobe_event
> >       perf-probe: Add array argument support
> > 
> > 
> >  Documentation/trace/kprobetrace.rst                |   23 +
> >  arch/Kconfig                                       |    7 
> >  arch/x86/Kconfig                                   |    1 
> >  arch/x86/include/asm/ptrace.h                      |   38 +
> >  kernel/trace/trace.c                               |    9 
> >  kernel/trace/trace_kprobe.c                        |  358 ++++--------
> >  kernel/trace/trace_probe.c                         |  620 +++++++++-----------
> >  kernel/trace/trace_probe.h                         |  282 +++------
> >  kernel/trace/trace_probe_tmpl.h                    |  216 +++++++
> >  kernel/trace/trace_uprobe.c                        |  176 ++----
> >  tools/perf/Documentation/perf-probe.txt            |   12 
> >  tools/perf/util/probe-event.c                      |   20 +
> >  tools/perf/util/probe-event.h                      |    2 
> >  tools/perf/util/probe-file.c                       |    5 
> >  tools/perf/util/probe-file.h                       |    1 
> >  tools/perf/util/probe-finder.c                     |   95 ++-
> >  .../ftrace/test.d/kprobe/kprobe_args_argN.tc       |   25 +
> >  .../ftrace/test.d/kprobe/kprobe_args_array.tc      |   92 +++
> >  .../ftrace/test.d/kprobe/kprobe_args_symbol.tc     |   77 ++
> >  19 files changed, 1127 insertions(+), 932 deletions(-)
> >  create mode 100644 kernel/trace/trace_probe_tmpl.h
> >  create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc
> >  create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc
> >  create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc
> > 
> > --
> > Masami Hiramatsu (Linaro) <mhiramat at kernel.org>
> 


-- 
Masami Hiramatsu <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features
  2018-06-22  6:04   ` mhiramat
@ 2018-06-22  6:04     ` Masami Hiramatsu
  0 siblings, 0 replies; 72+ messages in thread
From: Masami Hiramatsu @ 2018-06-22  6:04 UTC (permalink / raw)


Hi Steve,

On Thu, 21 Jun 2018 16:16:48 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:

> Hi Masami,
> 
> Are you going to post another version of this patch set?

No, this is the latest one which I sent to LKML.
Oops, it was 2 month ago now...

Thank you,

> 
> -- Steve
> 
> 
> On Wed, 25 Apr 2018 21:16:06 +0900
> Masami Hiramatsu <mhiramat@kernel.org> wrote:
> 
> > Hi,
> > 
> > This is the 7th version of the fetch-arg improvement series.
> > This includes variable changes on fetcharg framework like,
> > 
> > - Add fetcharg testcases (syntax, argN, symbol, string and array)
> >   and probepoint testcase.
> > - Rewrite fetcharg framework with fetch_insn, switch-case based
> >   instead of function pointer.
> > - Add "symbol" type support, which shows symbol+offset instead of
> >   address value.
> > - Add "$argN" fetcharg, which fetches function parameters.
> >   (currently only for x86-64)
> > - Add array type support (including string arrary :) ) ,
> >   which enables to get fixed length array from probe-events.
> > - Add array type support for perf-probe, so that user can
> >   dump partial array entries.
> > 
> > V6 is here:
> >  https://lkml.org/lkml/2018/3/17/75
> > 
> > Changes from the v6 are here:
> >  [6/16]  - Fix to return an error if failed to fetch string and
> >         fill zero-length data_loc in error case.
> >  [11/16] - Update document for restructured text.
> >  [15/16] - Fix README test.
> >  [16/16] - Add type-casting description (and note) to documentation.
> > 
> > And rebased on the latest Steve's ftrace/core branch.
> > 
> > Thank you,
> > 
> > ---
> > 
> > Masami Hiramatsu (16):
> >       tracing: probeevent: Cleanup print argument functions
> >       tracing: probeevent: Cleanup argument field definition
> >       tracing: probeevent: Remove NOKPROBE_SYMBOL from print functions
> >       tracing: probeevent: Introduce new argument fetching code
> >       tracing: probeevent: Unify fetch type tables
> >       tracing: probeevent: Return consumed bytes of dynamic area
> >       tracing: probeevent: Append traceprobe_ for exported function
> >       tracing: probeevent: Unify fetch_insn processing common part
> >       tracing: probeevent: Add symbol type
> >       x86: ptrace: Add function argument access API
> >       tracing: probeevent: Add $argN for accessing function args
> >       tracing: probeevent: Add array type support
> >       selftests: ftrace: Add a testcase for symbol type
> >       selftests: ftrace: Add a testcase for $argN with kprobe_event
> >       selftests: ftrace: Add a testcase for array type with kprobe_event
> >       perf-probe: Add array argument support
> > 
> > 
> >  Documentation/trace/kprobetrace.rst                |   23 +
> >  arch/Kconfig                                       |    7 
> >  arch/x86/Kconfig                                   |    1 
> >  arch/x86/include/asm/ptrace.h                      |   38 +
> >  kernel/trace/trace.c                               |    9 
> >  kernel/trace/trace_kprobe.c                        |  358 ++++--------
> >  kernel/trace/trace_probe.c                         |  620 +++++++++-----------
> >  kernel/trace/trace_probe.h                         |  282 +++------
> >  kernel/trace/trace_probe_tmpl.h                    |  216 +++++++
> >  kernel/trace/trace_uprobe.c                        |  176 ++----
> >  tools/perf/Documentation/perf-probe.txt            |   12 
> >  tools/perf/util/probe-event.c                      |   20 +
> >  tools/perf/util/probe-event.h                      |    2 
> >  tools/perf/util/probe-file.c                       |    5 
> >  tools/perf/util/probe-file.h                       |    1 
> >  tools/perf/util/probe-finder.c                     |   95 ++-
> >  .../ftrace/test.d/kprobe/kprobe_args_argN.tc       |   25 +
> >  .../ftrace/test.d/kprobe/kprobe_args_array.tc      |   92 +++
> >  .../ftrace/test.d/kprobe/kprobe_args_symbol.tc     |   77 ++
> >  19 files changed, 1127 insertions(+), 932 deletions(-)
> >  create mode 100644 kernel/trace/trace_probe_tmpl.h
> >  create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_argN.tc
> >  create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_array.tc
> >  create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_symbol.tc
> > 
> > --
> > Masami Hiramatsu (Linaro) <mhiramat at kernel.org>
> 


-- 
Masami Hiramatsu <mhiramat at kernel.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 72+ messages in thread

end of thread, other threads:[~2018-06-22  6:04 UTC | newest]

Thread overview: 72+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-25 12:16 [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features mhiramat
2018-04-25 12:16 ` Masami Hiramatsu
2018-04-25 12:16 ` [PATCH v7 01/16] tracing: probeevent: Cleanup print argument functions mhiramat
2018-04-25 12:16   ` Masami Hiramatsu
2018-04-25 12:17 ` [PATCH v7 02/16] tracing: probeevent: Cleanup argument field definition mhiramat
2018-04-25 12:17   ` Masami Hiramatsu
2018-04-25 12:17 ` [PATCH v7 03/16] tracing: probeevent: Remove NOKPROBE_SYMBOL from print functions mhiramat
2018-04-25 12:17   ` Masami Hiramatsu
2018-04-25 12:18 ` [PATCH v7 04/16] tracing: probeevent: Introduce new argument fetching code mhiramat
2018-04-25 12:18   ` Masami Hiramatsu
2018-04-25 12:18 ` [PATCH v7 05/16] tracing: probeevent: Unify fetch type tables mhiramat
2018-04-25 12:18   ` Masami Hiramatsu
2018-04-25 12:19 ` [PATCH v7 06/16] tracing: probeevent: Return consumed bytes of dynamic area mhiramat
2018-04-25 12:19   ` Masami Hiramatsu
2018-04-25 12:19 ` [PATCH v7 07/16] tracing: probeevent: Append traceprobe_ for exported function mhiramat
2018-04-25 12:19   ` Masami Hiramatsu
2018-04-25 12:19 ` [PATCH v7 08/16] tracing: probeevent: Unify fetch_insn processing common part mhiramat
2018-04-25 12:19   ` Masami Hiramatsu
2018-04-25 12:20 ` [PATCH v7 09/16] tracing: probeevent: Add symbol type mhiramat
2018-04-25 12:20   ` Masami Hiramatsu
2018-04-25 12:20 ` [PATCH v7 10/16] x86: ptrace: Add function argument access API mhiramat
2018-04-25 12:20   ` Masami Hiramatsu
2018-04-25 12:21 ` [PATCH v7 11/16] tracing: probeevent: Add $argN for accessing function args mhiramat
2018-04-25 12:21   ` Masami Hiramatsu
2018-04-25 12:21 ` [PATCH v7 12/16] tracing: probeevent: Add array type support mhiramat
2018-04-25 12:21   ` Masami Hiramatsu
2018-04-25 12:22 ` [PATCH v7 13/16] selftests: ftrace: Add a testcase for symbol type mhiramat
2018-04-25 12:22   ` Masami Hiramatsu
2018-04-25 12:22 ` [PATCH v7 14/16] selftests: ftrace: Add a testcase for $argN with kprobe_event mhiramat
2018-04-25 12:22   ` Masami Hiramatsu
2018-04-25 12:23 ` [PATCH v7 15/16] selftests: ftrace: Add a testcase for array type " mhiramat
2018-04-25 12:23   ` Masami Hiramatsu
2018-04-25 12:23 ` [PATCH v7 16/16] perf-probe: Add array argument support mhiramat
2018-04-25 12:23   ` Masami Hiramatsu
2018-04-27  1:42 ` [PATCH v7 00/16] tracing: probeevent: Improve fetcharg features rostedt
2018-04-27  1:42   ` Steven Rostedt
2018-05-03 22:11 ` rostedt
2018-05-03 22:11   ` Steven Rostedt
2018-05-04 15:48   ` mhiramat
2018-05-04 15:48     ` Masami Hiramatsu
2018-05-04 16:06     ` rostedt
2018-05-04 16:06       ` Steven Rostedt
2018-05-04 17:30       ` naveen.n.rao
2018-05-04 17:30         ` Naveen N. Rao
2018-05-05  2:38       ` mhiramat
2018-05-05  2:38         ` Masami Hiramatsu
2018-05-05  7:46         ` naveen.n.rao
2018-05-05  7:46           ` Naveen N. Rao
2018-05-05 14:32           ` mhiramat
2018-05-05 14:32             ` Masami Hiramatsu
2018-05-07  8:11             ` naveen.n.rao
2018-05-07  8:11               ` Naveen N. Rao
2018-05-07 14:53               ` mhiramat
2018-05-07 14:53                 ` Masami Hiramatsu
2018-05-08 10:11                 ` naveen.n.rao
2018-05-08 10:11                   ` Naveen N. Rao
2018-05-08 15:02                   ` mhiramat
2018-05-08 15:02                     ` Masami Hiramatsu
2018-05-08 18:01                     ` naveen.n.rao
2018-05-08 18:01                       ` Naveen N. Rao
2018-05-05 15:51         ` mhiramat
2018-05-05 15:51           ` Masami Hiramatsu
2018-05-07 15:30           ` rostedt
2018-05-07 15:30             ` Steven Rostedt
2018-05-08  4:01             ` mhiramat
2018-05-08  4:01               ` Masami Hiramatsu
2018-05-07 15:21         ` rostedt
2018-05-07 15:21           ` Steven Rostedt
2018-06-21 20:16 ` rostedt
2018-06-21 20:16   ` Steven Rostedt
2018-06-22  6:04   ` mhiramat
2018-06-22  6:04     ` Masami Hiramatsu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).