Skip to content

Commit

Permalink
perf tests: objdump output can contain multi byte chunks
Browse files Browse the repository at this point in the history
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,torvalds#72]
  70c4c:        91224000         add        x0, x0, #0x890
  70c50:        f90023a0         str        x0, [x29,torvalds#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>
  • Loading branch information
jstancek authored and acmel committed Aug 2, 2016
1 parent b6f35ed commit b2d0dbf
Showing 1 changed file with 71 additions and 29 deletions.
100 changes: 71 additions & 29 deletions tools/perf/tests/code-reading.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
const char *p;
size_t i, j = 0;

/* Skip to a colon */
p = strchr(line, ':');
if (!p)
return 0;
i = p + 1 - line;
size_t bytes_read = 0;
unsigned char *chunk_start = *buf;

/* Read bytes */
while (j < len) {
while (*buf_len > 0) {
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]))
c1 = *(*line)++;
if (!isxdigit(c1))
break;
c1 = line[i++];
if (i >= line_len || !isxdigit(line[i]))
c2 = *(*line)++;
if (!isxdigit(c2))
break;
c2 = line[i++];
/* Followed by a space */
if (i < line_len && line[i] && !isspace(line[i]))

/* Store byte and advance buf */
**buf = (hex(c1) << 4) | hex(c2);
(*buf)++;
(*buf_len)--;
bytes_read++;

/* End of chunk? */
if (isspace(**line))
break;
/* Store byte */
*(unsigned char *)buf = (hex(c1) << 4) | hex(c2);
buf += 1;
j++;
}

/*
* 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 ret, bytes_read = 0;

/* Skip to a colon */
p = strchr(line, ':');
if (!p)
return 0;
p++;

/* Skip initial spaces */
while (*p) {
if (!isspace(*p))
break;
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)
Expand All @@ -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;

Expand Down Expand Up @@ -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: %zd\n", len);
if (!ret)
ret = len;
}
Expand Down

0 comments on commit b2d0dbf

Please sign in to comment.