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

Signed-off-by: Jan Stancek <[email protected]>
Reported-and-tested-by: Kaixu Xia <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Adrian Hunter <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
  • Loading branch information
jstancek authored and 0day robot committed Jan 12, 2016
1 parent 3eb9ede commit a1cc5f4
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: %lu\n", len);
if (!ret)
ret = len;
}
Expand Down

0 comments on commit a1cc5f4

Please sign in to comment.