From: Steven Rostedt <[email protected]> Make the futex syscall trace event a little more smart. Have it read the futex_op instruction to determine what else it can save and print. For the appropriate options, it will read the utime (timespec) parameter and show its output as well as the uaddr2.
futex_requeue_p-1154 [004] ..... 144.568339: sys_futex(uaddr: 0x5652b178d834 (0x482), FUTEX_UNLOCK_PI|FUTEX_PRIVATE_FLAG, val: 0) futex_requeue_p-1162 [002] ..... 144.568696: sys_futex(uaddr: 0x7f763b7fece0 (2), FUTEX_WAIT|FUTEX_PRIVATE_FLAG, val: 2) futex_requeue_p-1151 [000] ..... 144.568700: sys_futex(uaddr: 0x7f763b7fece0 (0), FUTEX_WAKE|FUTEX_PRIVATE_FLAG, val: 1) futex_requeue_p-1162 [002] ..... 144.568705: sys_futex(uaddr: 0x7f763b7fece0 (0), FUTEX_WAKE|FUTEX_PRIVATE_FLAG, val: 1) futex_requeue_p-1151 [000] ..... 144.568715: sys_futex(uaddr: 0x7f764369e990 (0x483), FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, val: 1155) futex_requeue_p-1155 [005] ..... 144.569420: sys_futex(uaddr: 0x5652b178d838 (0), FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG, val: 0, timespec: 0x7ffdacfba500 (143.890024054), uaddr2: 0x5652b178d834 (0), val3: 0) futex_requeue_p-1155 [005] ..... 144.569454: sys_futex(uaddr: 0x5652b178d834 (0), FUTEX_LOCK_PI|FUTEX_PRIVATE_FLAG, val: 0) Signed-off-by: Steven Rostedt (Google) <[email protected]> --- kernel/trace/trace_syscalls.c | 138 +++++++++++++++++++++++++++++----- 1 file changed, 121 insertions(+), 17 deletions(-) diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index bc60a0497bcc..d128dcb218a7 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -273,10 +273,18 @@ static __always_inline bool futex_cmd_has_addr2(u32 cmd) return false; } +struct futex_data { + u32 val1; + u32 val2; + unsigned long ts1; + unsigned long ts2; +}; + static enum print_line_t sys_enter_futex_print(struct syscall_trace_enter *trace, struct syscall_metadata *entry, struct trace_seq *s, struct trace_event *event, int ent_size) { + struct futex_data *data; bool done = false; unsigned int op, cmd; void *end = (void *)trace + ent_size; @@ -285,8 +293,10 @@ sys_enter_futex_print(struct syscall_trace_enter *trace, struct syscall_metadata /* Set ptr to the user space copied area */ ptr = (void *)trace->args + sizeof(unsigned long) * entry->nb_args; - if (ptr + 4 > end) - ptr = NULL; + if (ptr + sizeof(*data) > end) + data = NULL; + else + data = ptr; trace_seq_printf(s, "%s(", entry->name); @@ -298,8 +308,8 @@ sys_enter_futex_print(struct syscall_trace_enter *trace, struct syscall_metadata switch (i) { case 0: trace_seq_printf(s, "uaddr: 0x%lx", trace->args[i]); - if (ptr) { - u32 val = *(u32 *)ptr; + if (data) { + u32 val = data->val1; if (val < 10) trace_seq_printf(s, " (%u)", val); else @@ -338,6 +348,15 @@ sys_enter_futex_print(struct syscall_trace_enter *trace, struct syscall_metadata trace_seq_printf(s, ", timespec: 0x%lx", trace->args[i]); + if (!data) + continue; + + if (!data->ts1 && !data->ts2) { + trace_seq_puts(s, " (0)"); + continue; + } + trace_seq_printf(s, " (%lu.%09lu)", + data->ts1, data->ts2); continue; case 4: @@ -346,6 +365,12 @@ sys_enter_futex_print(struct syscall_trace_enter *trace, struct syscall_metadata continue; } trace_seq_printf(s, ", uaddr2: 0x%lx", trace->args[i]); + + if (!data) + continue; + + trace_seq_printf(s, " (%x)", data->val2); + continue; } trace_seq_printf(s, ", %s: %lu", entry->args[i], @@ -570,9 +595,9 @@ sys_enter_futex_print_fmt(struct syscall_metadata *entry, char *buf, int len) pos += snprintf(buf + pos, LEN_OR_ZERO, "\"uaddr: 0x%%lx (0x%%lx) cmd=%%s%%s%%s"); pos += snprintf(buf + pos, LEN_OR_ZERO, - " val: 0x%%x timeout/val2: 0x%%llx"); + " val: 0x%%x timeout/val2: 0x%%llx (%%lu.%%lu)"); pos += snprintf(buf + pos, LEN_OR_ZERO, - " uaddr2: 0x%%lx val3: 0x%%x\", "); + " uaddr2: 0x%%lx (0x%%lx) val3: 0x%%x\", "); pos += snprintf(buf + pos, LEN_OR_ZERO, " REC->uaddr,"); @@ -618,10 +643,12 @@ sys_enter_futex_print_fmt(struct syscall_metadata *entry, char *buf, int len) FUTEX_CLOCK_REALTIME); pos += snprintf(buf + pos, LEN_OR_ZERO, - " REC->val, REC->utime,"); + " REC->val, REC->utime, REC->__ts1, REC->__ts2,"); pos += snprintf(buf + pos, LEN_OR_ZERO, - " REC->uaddr, REC->val3"); + " REC->uaddr,"); + pos += snprintf(buf + pos, LEN_OR_ZERO, + " REC->__value2, REC->val3"); return pos; } @@ -724,7 +751,39 @@ static int __init futex_fields(struct trace_event_call *call, int offset) ret = trace_define_field(call, "u32", arg, offset, sizeof(int), 0, FILTER_OTHER); if (ret) - kfree(arg); + goto free; + offset += sizeof(int); + + arg = kstrdup("__value2", GFP_KERNEL); + if (WARN_ON_ONCE(!arg)) + return -ENOMEM; + ret = trace_define_field(call, "u32", arg, offset, sizeof(int), 0, + FILTER_OTHER); + if (ret) + goto free; + offset += sizeof(int); + + arg = kstrdup("__ts1", GFP_KERNEL); + if (WARN_ON_ONCE(!arg)) + return -ENOMEM; + ret = trace_define_field(call, "unsigned long", arg, offset, + sizeof(unsigned long), 0, FILTER_OTHER); + if (ret) + goto free; + offset += sizeof(long); + + arg = kstrdup("__ts2", GFP_KERNEL); + if (WARN_ON_ONCE(!arg)) + return -ENOMEM; + ret = trace_define_field(call, "unsigned long", arg, offset, + sizeof(unsigned long), 0, FILTER_OTHER); + if (ret) + goto free; + + return 0; + +free: + kfree(arg); return ret; } @@ -897,11 +956,51 @@ static int syscall_copy_user_array(char *buf, const char __user *ptr, return 0; } +struct tp_futex_data { + u32 cmd; + const u32 __user *val1; + const u32 __user *val2; + void __user *timeout; +}; + +static int syscall_copy_futex(char *buf, const char __user *ptr, + size_t size, void *data) +{ + struct tp_futex_data *tp_data = data; + struct futex_data *fdata = (void *)buf; + int cmd = tp_data->cmd & FUTEX_CMD_MASK; + int ret; + + memset(fdata, 0, sizeof(*fdata)); + + if (tp_data->val1) { + ret = __copy_from_user(&fdata->val1, tp_data->val1, 4); + if (ret) + return -1; + } + + if (tp_data->val2 && futex_cmd_has_addr2(cmd)) { + ret = __copy_from_user(&fdata->val2, tp_data->val2, 4); + if (ret) + return -1; + } + + if (tp_data->timeout && futex_cmd_has_timeout(cmd)) { + /* Copies both ts1 and ts2 */ + ret = __copy_from_user(&fdata->ts1, tp_data->timeout, + sizeof(long) * 2); + if (ret) + return -1; + } + + return 0; +} + static int syscall_get_futex(unsigned long *args, char **buffer, int *size, int buf_size) { struct syscall_user_buffer *sbuf; - const char __user *ptr; + struct tp_futex_data tp_data; char *buf; /* buf_size of zero means user doesn't want user space read */ @@ -913,14 +1012,18 @@ syscall_get_futex(unsigned long *args, char **buffer, int *size, int buf_size) if (!sbuf) return -1; - ptr = (char __user *)args[0]; + tp_data.cmd = args[1]; + tp_data.val1 = (u32 __user *)args[0]; + tp_data.val2 = (u32 __user *)args[4]; + tp_data.timeout = (u64 __user *)args[3]; - *buffer = trace_user_fault_read(&sbuf->buf, ptr, 4, NULL, NULL); + *buffer = trace_user_fault_read(&sbuf->buf, NULL, 0, + syscall_copy_futex, &tp_data); if (!*buffer) return -1; - /* Add room for the value */ - *size += 4; + /* Add room for values */ + *size += sizeof(struct futex_data); buf = *buffer; @@ -931,12 +1034,13 @@ static void syscall_put_futex(struct syscall_metadata *sys_data, struct syscall_trace_enter *entry, char *buffer) { - u32 *ptr; + struct futex_data *fdata = (void *)buffer; + struct futex_data *data; /* Place the futex key into the storage */ - ptr = (void *)entry->args + sizeof(unsigned long) * sys_data->nb_args; + data = (void *)entry->args + sizeof(unsigned long) * sys_data->nb_args; - *ptr = *(u32 *)buffer; + *data = *fdata; } static char *sys_fault_user(unsigned int buf_size, -- 2.51.0
