All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] perf tests: objdump output can contain multi byte chunks
@ 2016-01-12 10:07 Jan Stancek
  2016-01-12 15:30 ` Arnaldo Carvalho de Melo
  2016-08-04  9:14 ` [tip:perf/urgent] " tip-bot for Jan Stancek
  0 siblings, 2 replies; 7+ messages in thread
From: Jan Stancek @ 2016-01-12 10:07 UTC (permalink / raw)
  To: linux-kernel, acme, xiakaixu
  Cc: jstancek, adrian.hunter, cjashfor, dsahern, fweisbec, jolsa,
	namhyung, paulus, a.p.zijlstra

objdump's raw insn output can vary across architectures on number of
bytes per chunk (bpc) displayed and their endian.

code-reading test relied on reading objdump output as 1 bpc. Kaixu Xia
reported test failure on ARM64, where objdump displays 4 bpc:
  70c48:        f90027bf         str        xzr, [x29,#72]
  70c4c:        91224000         add        x0, x0, #0x890
  70c50:        f90023a0         str        x0, [x29,#64]

This patch adds support to read raw insn output for any bpc length.
In case of 2+ bpc it also guesses objdump's display endian.

Signed-off-by: Jan Stancek <jstancek@redhat.com>
Reported-and-tested-by: Kaixu Xia <xiakaixu@huawei.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
---
 tools/perf/tests/code-reading.c | 100 ++++++++++++++++++++++++++++------------
 1 file changed, 71 insertions(+), 29 deletions(-)

diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index a767a6400c5c..0108cb22d1a2 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -33,44 +33,86 @@ static unsigned int hex(char c)
 	return c - 'A' + 10;
 }
 
-static size_t read_objdump_line(const char *line, size_t line_len, void *buf,
-			      size_t len)
+static size_t read_objdump_chunk(const char **line, unsigned char **buf,
+				 size_t *buf_len)
+{
+	size_t bytes_read = 0;
+	unsigned char *chunk_start = *buf;
+
+	/* Read bytes */
+	while (*buf_len > 0) {
+		char c1, c2;
+
+		/* Get 2 hex digits */
+		c1 = *(*line)++;
+		if (!isxdigit(c1))
+			break;
+		c2 = *(*line)++;
+		if (!isxdigit(c2))
+			break;
+
+		/* Store byte and advance buf */
+		**buf = (hex(c1) << 4) | hex(c2);
+		(*buf)++;
+		(*buf_len)--;
+		bytes_read++;
+
+		/* End of chunk? */
+		if (isspace(**line))
+			break;
+	}
+
+	/*
+	 * objdump will display raw insn as LE if code endian
+	 * is LE and bytes_per_chunk > 1. In that case reverse
+	 * the chunk we just read.
+	 *
+	 * see disassemble_bytes() at binutils/objdump.c for details
+	 * how objdump chooses display endian)
+	 */
+	if (bytes_read > 1 && !bigendian()) {
+		unsigned char *chunk_end = chunk_start + bytes_read - 1;
+		unsigned char tmp;
+
+		while (chunk_start < chunk_end) {
+			tmp = *chunk_start;
+			*chunk_start = *chunk_end;
+			*chunk_end = tmp;
+			chunk_start++;
+			chunk_end--;
+		}
+	}
+
+	return bytes_read;
+}
+
+static size_t read_objdump_line(const char *line, unsigned char *buf,
+				size_t buf_len)
 {
 	const char *p;
-	size_t i, j = 0;
+	size_t ret, bytes_read = 0;
 
 	/* Skip to a colon */
 	p = strchr(line, ':');
 	if (!p)
 		return 0;
-	i = p + 1 - line;
+	p++;
 
-	/* Read bytes */
-	while (j < len) {
-		char c1, c2;
-
-		/* Skip spaces */
-		for (; i < line_len; i++) {
-			if (!isspace(line[i]))
-				break;
-		}
-		/* Get 2 hex digits */
-		if (i >= line_len || !isxdigit(line[i]))
-			break;
-		c1 = line[i++];
-		if (i >= line_len || !isxdigit(line[i]))
-			break;
-		c2 = line[i++];
-		/* Followed by a space */
-		if (i < line_len && line[i] && !isspace(line[i]))
+	/* Skip initial spaces */
+	while (*p) {
+		if (!isspace(*p))
 			break;
-		/* Store byte */
-		*(unsigned char *)buf = (hex(c1) << 4) | hex(c2);
-		buf += 1;
-		j++;
+		p++;
 	}
+
+	do {
+		ret = read_objdump_chunk(&p, &buf, &buf_len);
+		bytes_read += ret;
+		p++;
+	} while (ret > 0);
+
 	/* return number of successfully read bytes */
-	return j;
+	return bytes_read;
 }
 
 static int read_objdump_output(FILE *f, void *buf, size_t *len, u64 start_addr)
@@ -95,7 +137,7 @@ static int read_objdump_output(FILE *f, void *buf, size_t *len, u64 start_addr)
 		}
 
 		/* read objdump data into temporary buffer */
-		read_bytes = read_objdump_line(line, ret, tmp, sizeof(tmp));
+		read_bytes = read_objdump_line(line, tmp, sizeof(tmp));
 		if (!read_bytes)
 			continue;
 
@@ -152,7 +194,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf,
 
 	ret = read_objdump_output(f, buf, &len, addr);
 	if (len) {
-		pr_debug("objdump read too few bytes\n");
+		pr_debug("objdump read too few bytes: %lu\n", len);
 		if (!ret)
 			ret = len;
 	}
-- 
1.8.3.1

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

end of thread, other threads:[~2016-08-04  9:15 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-01-12 10:07 [PATCH] perf tests: objdump output can contain multi byte chunks Jan Stancek
2016-01-12 15:30 ` Arnaldo Carvalho de Melo
2016-01-13  8:22   ` Adrian Hunter
2016-08-02 19:07     ` Arnaldo Carvalho de Melo
2016-08-02 19:33       ` Arnaldo Carvalho de Melo
2016-08-02 19:47         ` Arnaldo Carvalho de Melo
2016-08-04  9:14 ` [tip:perf/urgent] " tip-bot for Jan Stancek

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.