linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] libtraceevent: add __print_hex_dump support
@ 2020-02-10 12:19 Piotr Maziarz
  2020-02-20 18:54 ` Steven Rostedt
  0 siblings, 1 reply; 2+ messages in thread
From: Piotr Maziarz @ 2020-02-10 12:19 UTC (permalink / raw)
  To: linux-kernel
  Cc: rostedt, acme, tstoyanov, andriy.shevchenko, cezary.rojewski,
	gustaw.lewandowski

This allows using parsing __print_hex_dump in user space tools. Print
format is aligned with debugfs tracing interface.

Signed-off-by: Piotr Maziarz <piotrx.maziarz@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
v2:
Fix checkpatch warning
Use is_power_of_2() function

 tools/lib/traceevent/event-parse.c | 123 +++++++++++++++++++++++++++++++++++++
 tools/lib/traceevent/event-parse.h |  12 ++++
 tools/lib/traceevent/trace-seq.c   |  94 ++++++++++++++++++++++++++++
 tools/lib/traceevent/trace-seq.h   |   3 +
 4 files changed, 232 insertions(+)

diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index beaa8b8..37aefdc 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -898,6 +898,15 @@ static void free_arg(struct tep_print_arg *arg)
 		free_arg(arg->int_array.count);
 		free_arg(arg->int_array.el_size);
 		break;
+	case TEP_PRINT_HEX_DUMP:
+		free_arg(arg->hex_dump.prefix_str);
+		free_arg(arg->hex_dump.prefix_type);
+		free_arg(arg->hex_dump.rowsize);
+		free_arg(arg->hex_dump.groupsize);
+		free_arg(arg->hex_dump.buf);
+		free_arg(arg->hex_dump.len);
+		free_arg(arg->hex_dump.ascii);
+		break;
 	case TEP_PRINT_TYPE:
 		free(arg->typecast.type);
 		free_arg(arg->typecast.item);
@@ -2752,6 +2761,58 @@ process_int_array(struct tep_event *event, struct tep_print_arg *arg, char **tok
 }
 
 static enum tep_event_type
+process_hex_dump(struct tep_event *event, struct tep_print_arg *arg, char **tok)
+{
+	memset(arg, 0, sizeof(*arg));
+	arg->type = TEP_PRINT_HEX_DUMP;
+
+	if (alloc_and_process_delim(event, ",", &arg->hex_dump.prefix_str))
+		goto out;
+
+	if (alloc_and_process_delim(event, ",", &arg->hex_dump.prefix_type))
+		goto free_prefix_str;
+
+	if (alloc_and_process_delim(event, ",", &arg->hex_dump.rowsize))
+		goto free_prefix_type;
+
+	if (alloc_and_process_delim(event, ",", &arg->hex_dump.groupsize))
+		goto free_rowsize;
+
+	if (alloc_and_process_delim(event, ",", &arg->hex_dump.buf))
+		goto free_groupsize;
+
+	if (alloc_and_process_delim(event, ",", &arg->hex_dump.len))
+		goto free_buf;
+
+	if (alloc_and_process_delim(event, ")", &arg->hex_dump.ascii))
+		goto free_len;
+
+	return read_token_item(tok);
+
+free_len:
+	free_arg(arg->hex_dump.len);
+	arg->hex_dump.len = NULL;
+free_buf:
+	free_arg(arg->hex_dump.buf);
+	arg->hex_dump.buf = NULL;
+free_groupsize:
+	free_arg(arg->hex_dump.groupsize);
+	arg->hex_dump.groupsize = NULL;
+free_rowsize:
+	free_arg(arg->hex_dump.rowsize);
+	arg->hex_dump.rowsize = NULL;
+free_prefix_type:
+	free_arg(arg->hex_dump.prefix_type);
+	arg->hex_dump.prefix_type = NULL;
+free_prefix_str:
+	free_arg(arg->hex_dump.prefix_str);
+	arg->hex_dump.prefix_str = NULL;
+out:
+	*tok = NULL;
+	return TEP_EVENT_ERROR;
+}
+
+static enum tep_event_type
 process_dynamic_array(struct tep_event *event, struct tep_print_arg *arg, char **tok)
 {
 	struct tep_format_field *field;
@@ -3090,6 +3151,10 @@ process_function(struct tep_event *event, struct tep_print_arg *arg,
 		free_token(token);
 		return process_int_array(event, arg, tok);
 	}
+	if (strcmp(token, "__print_hex_dump") == 0) {
+		free_token(token);
+		return process_hex_dump(event, arg, tok);
+	}
 	if (strcmp(token, "__get_str") == 0) {
 		free_token(token);
 		return process_str(event, arg, tok);
@@ -3626,6 +3691,7 @@ eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg
 	case TEP_PRINT_FLAGS:
 	case TEP_PRINT_SYMBOL:
 	case TEP_PRINT_INT_ARRAY:
+	case TEP_PRINT_HEX_DUMP:
 	case TEP_PRINT_HEX:
 	case TEP_PRINT_HEX_STR:
 		break;
@@ -4124,6 +4190,46 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
 		}
 		break;
 	}
+	case TEP_PRINT_HEX_DUMP: {
+		void *buf;
+		char *prefix_str;
+		int prefix_type, rowsize, groupsize, ascii;
+
+		if (arg->hex_dump.buf->type == TEP_PRINT_DYNAMIC_ARRAY) {
+			unsigned long offset;
+
+			field = arg->hex_dump.buf->dynarray.field;
+			offset = tep_read_number(tep,
+						 data + field->offset,
+						 field->size);
+			buf = data + (offset & 0xffff);
+		} else {
+			field = arg->hex_dump.buf->field.field;
+			if (!field) {
+				str = arg->hex_dump.buf->field.name;
+				field = tep_find_any_field(event, str);
+				if (!field)
+					goto out_warning_field;
+				arg->hex_dump.buf->field.field = field;
+			}
+			buf = data + field->offset;
+		}
+		prefix_type = eval_num_arg(data, size, event,
+					   arg->hex_dump.prefix_type);
+		rowsize = eval_num_arg(data, size, event,
+				       arg->hex_dump.rowsize);
+		groupsize = eval_num_arg(data, size, event,
+					 arg->hex_dump.groupsize);
+		len = eval_num_arg(data, size, event, arg->hex_dump.len);
+		ascii = eval_num_arg(data, size, event,
+					   arg->hex_dump.ascii);
+		prefix_str = arg->hex_dump.prefix_str->atom.atom;
+
+		trace_seq_putc(s, '\n');
+		trace_seq_hex_dump(s, prefix_str, prefix_type,
+				   rowsize, groupsize, buf, len, ascii);
+		break;
+	}
 	case TEP_PRINT_TYPE:
 		break;
 	case TEP_PRINT_STRING: {
@@ -5987,6 +6093,23 @@ static void print_args(struct tep_print_arg *args)
 		print_args(args->int_array.el_size);
 		printf(")");
 		break;
+	case TEP_PRINT_HEX_DUMP:
+		printf("__print_hex_dump(");
+		print_args(args->hex_dump.prefix_str);
+		printf(", ");
+		print_args(args->hex_dump.prefix_type);
+		printf(", ");
+		print_args(args->hex_dump.rowsize);
+		printf(", ");
+		print_args(args->hex_dump.groupsize);
+		printf(", ");
+		print_args(args->hex_dump.buf);
+		printf(", ");
+		print_args(args->hex_dump.len);
+		printf(", ");
+		print_args(args->hex_dump.ascii);
+		printf(")");
+		break;
 	case TEP_PRINT_STRING:
 	case TEP_PRINT_BSTRING:
 		printf("__get_str(%s)", args->string.string);
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index b77837f..9d4482f 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -213,6 +213,16 @@ struct tep_print_arg_int_array {
 	struct tep_print_arg	*el_size;
 };
 
+struct tep_print_arg_hex_dump {
+	struct tep_print_arg	*prefix_str;
+	struct tep_print_arg	*prefix_type;
+	struct tep_print_arg	*rowsize;
+	struct tep_print_arg	*groupsize;
+	struct tep_print_arg	*buf;
+	struct tep_print_arg	*len;
+	struct tep_print_arg	*ascii;
+};
+
 struct tep_print_arg_dynarray {
 	struct tep_format_field	*field;
 	struct tep_print_arg	*index;
@@ -242,6 +252,7 @@ enum tep_print_arg_type {
 	TEP_PRINT_SYMBOL,
 	TEP_PRINT_HEX,
 	TEP_PRINT_INT_ARRAY,
+	TEP_PRINT_HEX_DUMP,
 	TEP_PRINT_TYPE,
 	TEP_PRINT_STRING,
 	TEP_PRINT_BSTRING,
@@ -264,6 +275,7 @@ struct tep_print_arg {
 		struct tep_print_arg_symbol	symbol;
 		struct tep_print_arg_hex	hex;
 		struct tep_print_arg_int_array	int_array;
+		struct tep_print_arg_hex_dump	hex_dump;
 		struct tep_print_arg_func	func;
 		struct tep_print_arg_string	string;
 		struct tep_print_arg_bitmask	bitmask;
diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c
index 8d5ecd2..46004f7 100644
--- a/tools/lib/traceevent/trace-seq.c
+++ b/tools/lib/traceevent/trace-seq.c
@@ -13,6 +13,7 @@
 #include <asm/bug.h>
 #include "event-parse.h"
 #include "event-utils.h"
+#include "linux/log2.h"
 
 /*
  * The TRACE_SEQ_POISON is to catch the use of using
@@ -247,3 +248,96 @@ int trace_seq_do_printf(struct trace_seq *s)
 {
 	return trace_seq_do_fprintf(s, stdout);
 }
+
+enum {
+	DUMP_PREFIX_NONE,
+	DUMP_PREFIX_ADDRESS,
+	DUMP_PREFIX_OFFSET
+};
+
+int hex_dump_line(const unsigned char *buf, size_t len, int rowsize,
+		  int groupsize, struct trace_seq *s, bool ascii)
+{
+	unsigned long long val;
+	int i, ret, pos = 0;
+	const char *format;
+	int ascii_pos = rowsize * 2 + rowsize / groupsize + 1;
+
+	if (len > rowsize)
+		len = rowsize;
+	if ((!is_power_of_2(groupsize) || groupsize > 8)
+	    || (len % groupsize) != 0) {
+		groupsize = 1;
+	}
+
+	for (i = 0; i < len / groupsize; i++) {
+		if (groupsize == 8) {
+			const unsigned long long *ptr8 = (void *)buf;
+
+			val = *(ptr8 + i);
+			format = "%s%16.16llx";
+		} else if (groupsize == 4) {
+			const unsigned int *ptr4 = (void *)buf;
+
+			val = *(ptr4 + i);
+			format = "%s%8.8x";
+		} else if (groupsize == 2) {
+			const unsigned short *ptr2 = (void *)buf;
+
+			val = *(ptr2 + i);
+			format = "%s%4.4x";
+		} else {
+			const unsigned char *ptr1 = (void *)buf;
+
+			val = *(ptr1 + i);
+			format = "%s%2.2x";
+		}
+		ret = trace_seq_printf(s,
+			       format, i ? " " : "",
+			       val);
+		if (ret <= 0)
+			return ret;
+		pos += ret;
+	}
+	if (!ascii)
+		return 0;
+	ret = trace_seq_printf(s, "%*s", ascii_pos - pos, "");
+	if (ret <= 0)
+		return ret;
+	for (i = 0; i < len; i++)
+		trace_seq_putc(s, (isprint(buf[i])) ? buf[i] : '.');
+	return 0;
+}
+
+int trace_seq_hex_dump(struct trace_seq *s, const char *prefix_str,
+		       int prefix_type, int rowsize, int groupsize,
+		       const void *buf, size_t len, int ascii)
+{
+	const unsigned char *ptr = buf;
+	int i, linelen, remaining = len;
+	int ret;
+
+	if (rowsize != 16 && rowsize != 32)
+		rowsize = 16;
+
+	for (i = 0; i < len; i += rowsize) {
+		linelen = min(remaining, rowsize);
+		remaining -= linelen;
+
+		if (prefix_type == DUMP_PREFIX_ADDRESS)
+			ret = trace_seq_printf(s, "%s%p: ",
+					       prefix_str, ptr + i);
+		else if (prefix_type == DUMP_PREFIX_OFFSET)
+			ret = trace_seq_printf(s, "%s%.8x: ",
+					       prefix_str, i);
+		else
+			ret = trace_seq_printf(s, "%s",
+					       prefix_str);
+		if (ret <= 0)
+			return ret;
+		hex_dump_line(ptr + i, linelen, rowsize, groupsize,
+			      s, ascii);
+		trace_seq_putc(s, '\n');
+	}
+	return 0;
+}
diff --git a/tools/lib/traceevent/trace-seq.h b/tools/lib/traceevent/trace-seq.h
index d68ec69..7b7d72e 100644
--- a/tools/lib/traceevent/trace-seq.h
+++ b/tools/lib/traceevent/trace-seq.h
@@ -51,5 +51,8 @@ extern void trace_seq_terminate(struct trace_seq *s);
 
 extern int trace_seq_do_fprintf(struct trace_seq *s, FILE *fp);
 extern int trace_seq_do_printf(struct trace_seq *s);
+extern int trace_seq_hex_dump(struct trace_seq *s, const char *prefix_str,
+			      int prefix_type, int rowsize, int groupsize,
+			      const void *buf, size_t len, int ascii);
 
 #endif /* _TRACE_SEQ_H */
-- 
2.7.4


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

* Re: [PATCH v2] libtraceevent: add __print_hex_dump support
  2020-02-10 12:19 [PATCH v2] libtraceevent: add __print_hex_dump support Piotr Maziarz
@ 2020-02-20 18:54 ` Steven Rostedt
  0 siblings, 0 replies; 2+ messages in thread
From: Steven Rostedt @ 2020-02-20 18:54 UTC (permalink / raw)
  To: Piotr Maziarz
  Cc: linux-kernel, acme, tstoyanov, andriy.shevchenko,
	cezary.rojewski, gustaw.lewandowski

On Mon, 10 Feb 2020 13:19:11 +0100
Piotr Maziarz <piotrx.maziarz@linux.intel.com> wrote:

> This allows using parsing __print_hex_dump in user space tools. Print
> format is aligned with debugfs tracing interface.
> 
> Signed-off-by: Piotr Maziarz <piotrx.maziarz@linux.intel.com>
> Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
> ---
> v2:
> Fix checkpatch warning
> Use is_power_of_2() function
> 
>

Acked-by: Steven Rostedt (VMware) <rostedt@goodmis.org>

-- Steve

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

end of thread, other threads:[~2020-02-20 18:54 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-10 12:19 [PATCH v2] libtraceevent: add __print_hex_dump support Piotr Maziarz
2020-02-20 18:54 ` Steven Rostedt

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).