5d76df141401e5cdcea5ba0cb068e5e51297b22f
[linux-2.6-microblaze.git] / tools / lib / traceevent / plugins / plugin_futex.c
1 /*
2  * Copyright (C) 2017 National Instruments Corp.
3  *
4  * Author: Julia Cartwright <julia@ni.com>
5  *
6  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation;
10  * version 2.1 of the License (not later!)
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not,  see <http://www.gnu.org/licenses>
19  *
20  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21  */
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <linux/futex.h>
26
27 #include "event-parse.h"
28
29 #define ARRAY_SIZE(_a) (sizeof(_a) / sizeof((_a)[0]))
30
31 struct futex_args {
32         unsigned long long      uaddr;
33         unsigned long long      op;
34         unsigned long long      val;
35         unsigned long long      utime; /* or val2 */
36         unsigned long long      uaddr2;
37         unsigned long long      val3;
38 };
39
40 struct futex_op {
41         const char      *name;
42         const char      *fmt_val;
43         const char      *fmt_utime;
44         const char      *fmt_uaddr2;
45         const char      *fmt_val3;
46 };
47
48 static const struct futex_op futex_op_tbl[] = {
49         {            "FUTEX_WAIT", " val=0x%08llx", " utime=0x%08llx",               NULL,             NULL },
50         {            "FUTEX_WAKE",     " val=%llu",              NULL,               NULL,             NULL },
51         {              "FUTEX_FD",     " val=%llu",              NULL,               NULL,             NULL },
52         {         "FUTEX_REQUEUE",     " val=%llu",      " val2=%llu", " uaddr2=0x%08llx",             NULL },
53         {     "FUTEX_CMP_REQUEUE",     " val=%llu",      " val2=%llu", " uaddr2=0x%08llx", " val3=0x%08llx" },
54         {         "FUTEX_WAKE_OP",     " val=%llu",      " val2=%llu", " uaddr2=0x%08llx", " val3=0x%08llx" },
55         {         "FUTEX_LOCK_PI",            NULL, " utime=0x%08llx",               NULL,             NULL },
56         {       "FUTEX_UNLOCK_PI",            NULL,              NULL,               NULL,             NULL },
57         {      "FUTEX_TRYLOCK_PI",            NULL,              NULL,               NULL,             NULL },
58         {     "FUTEX_WAIT_BITSET", " val=0x%08llx", " utime=0x%08llx",               NULL, " val3=0x%08llx" },
59         {     "FUTEX_WAKE_BITSET",     " val=%llu",              NULL,               NULL, " val3=0x%08llx" },
60         { "FUTEX_WAIT_REQUEUE_PI", " val=0x%08llx", " utime=0x%08llx", " uaddr2=0x%08llx", " val3=0x%08llx" },
61         {  "FUTEX_CMP_REQUEUE_PI",     " val=%llu",      " val2=%llu", " uaddr2=0x%08llx", " val3=0x%08llx" },
62 };
63
64
65 static void futex_print(struct trace_seq *s, const struct futex_args *args,
66                         const struct futex_op *fop)
67 {
68         trace_seq_printf(s, " uaddr=0x%08llx", args->uaddr);
69
70         if (fop->fmt_val)
71                 trace_seq_printf(s, fop->fmt_val, args->val);
72
73         if (fop->fmt_utime)
74                 trace_seq_printf(s,fop->fmt_utime, args->utime);
75
76         if (fop->fmt_uaddr2)
77                 trace_seq_printf(s, fop->fmt_uaddr2, args->uaddr2);
78
79         if (fop->fmt_val3)
80                 trace_seq_printf(s, fop->fmt_val3, args->val3);
81 }
82
83 static int futex_handler(struct trace_seq *s, struct tep_record *record,
84                          struct tep_event *event, void *context)
85 {
86         const struct futex_op *fop;
87         struct futex_args args;
88         unsigned long long cmd;
89
90         if (tep_get_field_val(s, event, "uaddr", record, &args.uaddr, 1))
91                 return 1;
92
93         if (tep_get_field_val(s, event, "op", record, &args.op, 1))
94                 return 1;
95
96         if (tep_get_field_val(s, event, "val", record, &args.val, 1))
97                 return 1;
98
99         if (tep_get_field_val(s, event, "utime", record, &args.utime, 1))
100                 return 1;
101
102         if (tep_get_field_val(s, event, "uaddr2", record, &args.uaddr2, 1))
103                 return 1;
104
105         if (tep_get_field_val(s, event, "val3", record, &args.val3, 1))
106                 return 1;
107
108         cmd = args.op & FUTEX_CMD_MASK;
109         if (cmd >= ARRAY_SIZE(futex_op_tbl))
110                 return 1;
111
112         fop = &futex_op_tbl[cmd];
113
114         trace_seq_printf(s, "op=%s", fop->name);
115
116         if (args.op & FUTEX_PRIVATE_FLAG)
117                 trace_seq_puts(s, "|FUTEX_PRIVATE_FLAG");
118
119         if (args.op & FUTEX_CLOCK_REALTIME)
120                 trace_seq_puts(s, "|FUTEX_CLOCK_REALTIME");
121
122         futex_print(s, &args, fop);
123         return 0;
124 }
125
126 int TEP_PLUGIN_LOADER(struct tep_handle *tep)
127 {
128         tep_register_event_handler(tep, -1, "syscalls", "sys_enter_futex",
129                                    futex_handler, NULL);
130         return 0;
131 }
132
133 void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
134 {
135         tep_unregister_event_handler(tep, -1, "syscalls", "sys_enter_futex",
136                                      futex_handler, NULL);
137 }