aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/tests/code-reading.c
diff options
context:
space:
mode:
authorJan Stancek <jstancek@redhat.com>2016-01-12 05:07:44 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-08-02 15:42:51 -0400
commitb2d0dbf09772d091368261ce95db3afce45d994d (patch)
treeb9e5f6491e67bc8720a298d1f9647934653d5045 /tools/perf/tests/code-reading.c
parentb6f35ed774aeaf441e66cfa243fd1dff1321d69e (diff)
perf tests: objdump output can contain multi byte chunks
objdump's raw insn output can vary across architectures on the number of bytes per chunk (bpc) displayed and their endianness. The 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. Reported-and-Tested-by: Kaixu Xia <xiakaixu@huawei.com> Signed-off-by: Jan Stancek <jstancek@redhat.com> Acked-by: 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> Link: http://lkml.kernel.org/r/07f0f7bcbda78deb423298708ef9b6a54d6b92bd.1452592712.git.jstancek@redhat.com [ Fix up pr_fmt() call to use %zd for size_t variables, fixing the build on Ubuntu cross-compiling to armhf and ppc64 ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/tests/code-reading.c')
-rw-r--r--tools/perf/tests/code-reading.c100
1 files changed, 71 insertions, 29 deletions
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index 68a69a195545..2af156a8d4e5 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)
33 return c - 'A' + 10; 33 return c - 'A' + 10;
34} 34}
35 35
36static size_t read_objdump_line(const char *line, size_t line_len, void *buf, 36static size_t read_objdump_chunk(const char **line, unsigned char **buf,
37 size_t len) 37 size_t *buf_len)
38{ 38{
39 const char *p; 39 size_t bytes_read = 0;
40 size_t i, j = 0; 40 unsigned char *chunk_start = *buf;
41
42 /* Skip to a colon */
43 p = strchr(line, ':');
44 if (!p)
45 return 0;
46 i = p + 1 - line;
47 41
48 /* Read bytes */ 42 /* Read bytes */
49 while (j < len) { 43 while (*buf_len > 0) {
50 char c1, c2; 44 char c1, c2;
51 45
52 /* Skip spaces */
53 for (; i < line_len; i++) {
54 if (!isspace(line[i]))
55 break;
56 }
57 /* Get 2 hex digits */ 46 /* Get 2 hex digits */
58 if (i >= line_len || !isxdigit(line[i])) 47 c1 = *(*line)++;
48 if (!isxdigit(c1))
59 break; 49 break;
60 c1 = line[i++]; 50 c2 = *(*line)++;
61 if (i >= line_len || !isxdigit(line[i])) 51 if (!isxdigit(c2))
62 break; 52 break;
63 c2 = line[i++]; 53
64 /* Followed by a space */ 54 /* Store byte and advance buf */
65 if (i < line_len && line[i] && !isspace(line[i])) 55 **buf = (hex(c1) << 4) | hex(c2);
56 (*buf)++;
57 (*buf_len)--;
58 bytes_read++;
59
60 /* End of chunk? */
61 if (isspace(**line))
66 break; 62 break;
67 /* Store byte */
68 *(unsigned char *)buf = (hex(c1) << 4) | hex(c2);
69 buf += 1;
70 j++;
71 } 63 }
64
65 /*
66 * objdump will display raw insn as LE if code endian
67 * is LE and bytes_per_chunk > 1. In that case reverse
68 * the chunk we just read.
69 *
70 * see disassemble_bytes() at binutils/objdump.c for details
71 * how objdump chooses display endian)
72 */
73 if (bytes_read > 1 && !bigendian()) {
74 unsigned char *chunk_end = chunk_start + bytes_read - 1;
75 unsigned char tmp;
76
77 while (chunk_start < chunk_end) {
78 tmp = *chunk_start;
79 *chunk_start = *chunk_end;
80 *chunk_end = tmp;
81 chunk_start++;
82 chunk_end--;
83 }
84 }
85
86 return bytes_read;
87}
88
89static size_t read_objdump_line(const char *line, unsigned char *buf,
90 size_t buf_len)
91{
92 const char *p;
93 size_t ret, bytes_read = 0;
94
95 /* Skip to a colon */
96 p = strchr(line, ':');
97 if (!p)
98 return 0;
99 p++;
100
101 /* Skip initial spaces */
102 while (*p) {
103 if (!isspace(*p))
104 break;
105 p++;
106 }
107
108 do {
109 ret = read_objdump_chunk(&p, &buf, &buf_len);
110 bytes_read += ret;
111 p++;
112 } while (ret > 0);
113
72 /* return number of successfully read bytes */ 114 /* return number of successfully read bytes */
73 return j; 115 return bytes_read;
74} 116}
75 117
76static int read_objdump_output(FILE *f, void *buf, size_t *len, u64 start_addr) 118static 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)
95 } 137 }
96 138
97 /* read objdump data into temporary buffer */ 139 /* read objdump data into temporary buffer */
98 read_bytes = read_objdump_line(line, ret, tmp, sizeof(tmp)); 140 read_bytes = read_objdump_line(line, tmp, sizeof(tmp));
99 if (!read_bytes) 141 if (!read_bytes)
100 continue; 142 continue;
101 143
@@ -152,7 +194,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf,
152 194
153 ret = read_objdump_output(f, buf, &len, addr); 195 ret = read_objdump_output(f, buf, &len, addr);
154 if (len) { 196 if (len) {
155 pr_debug("objdump read too few bytes\n"); 197 pr_debug("objdump read too few bytes: %zd\n", len);
156 if (!ret) 198 if (!ret)
157 ret = len; 199 ret = len;
158 } 200 }