diff options
author | Jan Stancek <jstancek@redhat.com> | 2016-01-12 05:07:44 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2016-08-02 15:42:51 -0400 |
commit | b2d0dbf09772d091368261ce95db3afce45d994d (patch) | |
tree | b9e5f6491e67bc8720a298d1f9647934653d5045 /tools/perf/tests/code-reading.c | |
parent | b6f35ed774aeaf441e66cfa243fd1dff1321d69e (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.c | 100 |
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 | ||
36 | static size_t read_objdump_line(const char *line, size_t line_len, void *buf, | 36 | static 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 | |||
89 | static 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 | ||
76 | static int read_objdump_output(FILE *f, void *buf, size_t *len, u64 start_addr) | 118 | 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) | |||
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 | } |