aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2015-03-20 16:46:53 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-03-21 13:53:36 -0400
commitf208bd8df08d0659ecd9e09e992c79aab26cddfa (patch)
tree94c8bff840892df70218232788a397c754e45249
parente6c76d620379fd65fc0310aee1785ff7b1b10236 (diff)
perf trace: Handle legacy syscalls tracepoints
Currently the code skips the first field with the expectation that it is 'nr'. But older kernels do not have the 'nr' field: field:int nr; offset:8; size:4; signed:1; Change perf-trace to drop the field if it exists after parsing the format file. This fixes the off-by-one problem with older kernels (e.g., RHEL6). e.g, perf-trace shows this for write: 1.515 ( 0.006 ms): dd/4245 write(buf: 2</dev/pts/0>, count: 140733837536224 ) = 26 where 2 is really the fd, the huge number is really the buf address, etc. With this patch you get the more appropriate: 1.813 ( 0.003 ms): dd/6330 write(fd: 2</dev/pts/0>, buf: 0x7fff22fc81f0, count: 25) = 25 Based-on-a-patch-by: David Ahern <dsahern@gmail.com> Acked-by: David Ahern <dsahern@gmail.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Borislav Petkov <bp@suse.de> Cc: Don Zickus <dzickus@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/n/tip-gvpdave4u2yq2jnzbcdznpvf@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/builtin-trace.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 6af6bcec930e..001c6ae9a1b1 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1135,6 +1135,8 @@ static struct syscall_fmt *syscall_fmt__find(const char *name)
1135 1135
1136struct syscall { 1136struct syscall {
1137 struct event_format *tp_format; 1137 struct event_format *tp_format;
1138 int nr_args;
1139 struct format_field *args;
1138 const char *name; 1140 const char *name;
1139 bool filtered; 1141 bool filtered;
1140 bool is_exit; 1142 bool is_exit;
@@ -1442,14 +1444,14 @@ static int syscall__set_arg_fmts(struct syscall *sc)
1442 struct format_field *field; 1444 struct format_field *field;
1443 int idx = 0; 1445 int idx = 0;
1444 1446
1445 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *)); 1447 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
1446 if (sc->arg_scnprintf == NULL) 1448 if (sc->arg_scnprintf == NULL)
1447 return -1; 1449 return -1;
1448 1450
1449 if (sc->fmt) 1451 if (sc->fmt)
1450 sc->arg_parm = sc->fmt->arg_parm; 1452 sc->arg_parm = sc->fmt->arg_parm;
1451 1453
1452 for (field = sc->tp_format->format.fields->next; field; field = field->next) { 1454 for (field = sc->args; field; field = field->next) {
1453 if (sc->fmt && sc->fmt->arg_scnprintf[idx]) 1455 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1454 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx]; 1456 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1455 else if (field->flags & FIELD_IS_POINTER) 1457 else if (field->flags & FIELD_IS_POINTER)
@@ -1515,6 +1517,14 @@ static int trace__read_syscall_info(struct trace *trace, int id)
1515 if (sc->tp_format == NULL) 1517 if (sc->tp_format == NULL)
1516 return -1; 1518 return -1;
1517 1519
1520 sc->args = sc->tp_format->format.fields;
1521 sc->nr_args = sc->tp_format->format.nr_fields;
1522 /* drop nr field - not relevant here; does not exist on older kernels */
1523 if (sc->args && strcmp(sc->args->name, "nr") == 0) {
1524 sc->args = sc->args->next;
1525 --sc->nr_args;
1526 }
1527
1518 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit"); 1528 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1519 1529
1520 return syscall__set_arg_fmts(sc); 1530 return syscall__set_arg_fmts(sc);
@@ -1537,7 +1547,7 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
1537 unsigned char *p; 1547 unsigned char *p;
1538 unsigned long val; 1548 unsigned long val;
1539 1549
1540 if (sc->tp_format != NULL) { 1550 if (sc->args != NULL) {
1541 struct format_field *field; 1551 struct format_field *field;
1542 u8 bit = 1; 1552 u8 bit = 1;
1543 struct syscall_arg arg = { 1553 struct syscall_arg arg = {
@@ -1547,7 +1557,7 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
1547 .thread = thread, 1557 .thread = thread,
1548 }; 1558 };
1549 1559
1550 for (field = sc->tp_format->format.fields->next; field; 1560 for (field = sc->args; field;
1551 field = field->next, ++arg.idx, bit <<= 1) { 1561 field = field->next, ++arg.idx, bit <<= 1) {
1552 if (arg.mask & bit) 1562 if (arg.mask & bit)
1553 continue; 1563 continue;