linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Masami Hiramatsu <mhiramat@kernel.org>
To: Steven Rostedt <rostedt@goodmis.org>, linux-kernel@vger.kernel.org
Cc: mhiramat@kernel.org, Ingo Molnar <mingo@redhat.com>,
	Namhyung Kim <namhyung@kernel.org>,
	Tom Zanussi <tom.zanussi@linux.intel.com>,
	Arnaldo Carvalho de Melo <acme@kernel.org>,
	linux-trace-users@vger.kernel.org,
	linux-kselftest@vger.kernel.org, shuah@kernel.org,
	Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
Subject: [PATCH v6 21/21] perf-probe: Add array argument support
Date: Sat, 17 Mar 2018 21:53:10 +0900	[thread overview]
Message-ID: <152129118998.31874.16273532808298489908.stgit@devbox> (raw)
In-Reply-To: <152129024033.31874.15800253385376959274.stgit@devbox>

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.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 tools/perf/Documentation/perf-probe.txt |    2 -
 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, 84 insertions(+), 41 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index b6866a05edd2..a68e423cac48 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -196,7 +196,7 @@ 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)
 On x86 systems %REG is always the short form of the register: for example %AX. %RAX or %EAX is not valid.
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;
 }


  parent reply	other threads:[~2018-03-17 12:53 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-17 12:37 [PATCH v6 00/21] tracing: probeevent: Improve fetcharg features Masami Hiramatsu
2018-03-17 12:38 ` [PATCH v6 01/21] [BUGFIX] tracing: probeevent: Fix to support minus offset from symbol Masami Hiramatsu
2018-03-17 12:38 ` [PATCH v6 02/21] selftests: ftrace: Add probe event argument syntax testcase Masami Hiramatsu
2018-03-17 12:39 ` [PATCH v6 03/21] selftests: ftrace: Add a testcase for string type with kprobe_event Masami Hiramatsu
2018-03-17 12:40 ` [PATCH v6 04/21] selftests: ftrace: Add a testcase for probepoint Masami Hiramatsu
2018-03-23 16:19   ` Steven Rostedt
2018-03-17 12:41 ` [PATCH v6 05/21] tracing: probeevent: Cleanup print argument functions Masami Hiramatsu
2018-03-23 16:36   ` Steven Rostedt
2018-03-26  4:17     ` Masami Hiramatsu
2018-03-26 17:28       ` Steven Rostedt
2018-03-28  4:21         ` Masami Hiramatsu
2018-03-17 12:41 ` [PATCH v6 06/21] tracing: probeevent: Cleanup argument field definition Masami Hiramatsu
2018-03-17 12:42 ` [PATCH v6 07/21] tracing: probeevent: Remove NOKPROBE_SYMBOL from print functions Masami Hiramatsu
2018-03-17 12:43 ` [PATCH v6 08/21] tracing: probeevent: Introduce new argument fetching code Masami Hiramatsu
2018-03-17 12:44 ` [PATCH v6 09/21] tracing: probeevent: Unify fetch type tables Masami Hiramatsu
2018-03-17 12:44 ` [PATCH v6 10/21] tracing: probeevent: Return consumed bytes of dynamic area Masami Hiramatsu
2018-04-02 20:02   ` Steven Rostedt
2018-04-03 14:41     ` Masami Hiramatsu
2018-03-17 12:45 ` [PATCH v6 11/21] tracing: probeevent: Append traceprobe_ for exported function Masami Hiramatsu
2018-03-17 12:46 ` [PATCH v6 12/21] tracing: probeevent: Unify fetch_insn processing common part Masami Hiramatsu
2018-03-17 12:47 ` [PATCH v6 13/21] tracing: probeevent: Add symbol type Masami Hiramatsu
2018-03-17 12:47 ` [PATCH v6 14/21] x86: ptrace: Add function argument access API Masami Hiramatsu
2018-03-17 12:48 ` [PATCH v6 15/21] tracing: probeevent: Add $argN for accessing function args Masami Hiramatsu
2018-03-17 12:49 ` [PATCH v6 16/21] tracing: probeevent: Add array type support Masami Hiramatsu
2018-03-17 12:50 ` [PATCH v6 17/21] selftests: ftrace: Add a testcase for symbol type Masami Hiramatsu
2018-03-17 12:50 ` [PATCH v6 18/21] selftests: ftrace: Add a testcase for $argN with kprobe_event Masami Hiramatsu
2018-03-17 12:51 ` [PATCH v6 19/21] selftests: ftrace: Add a testcase for array type " Masami Hiramatsu
2018-03-17 12:52 ` [PATCH v6 20/21] [RESEND] perf-probe: Fix to convert array type collectly Masami Hiramatsu
2018-03-20  6:36   ` [tip:perf/core] perf probe: Use right type to access array elements tip-bot for Masami Hiramatsu
2018-03-17 12:53 ` Masami Hiramatsu [this message]
2018-03-19  7:59   ` [PATCH v6 21/21] perf-probe: Add array argument support Ravi Bangoria
2018-03-22 10:23     ` Masami Hiramatsu
2018-03-22 10:49       ` Ravi Bangoria
2018-03-26  3:53         ` Masami Hiramatsu
2018-03-17 14:06 ` [PATCH v6 00/21] tracing: probeevent: Improve fetcharg features Masami Hiramatsu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=152129118998.31874.16273532808298489908.stgit@devbox \
    --to=mhiramat@kernel.org \
    --cc=acme@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=linux-trace-users@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=namhyung@kernel.org \
    --cc=ravi.bangoria@linux.vnet.ibm.com \
    --cc=rostedt@goodmis.org \
    --cc=shuah@kernel.org \
    --cc=tom.zanussi@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).