diff options
Diffstat (limited to 'tools/perf/builtin-trace.c')
-rw-r--r-- | tools/perf/builtin-trace.c | 134 |
1 files changed, 82 insertions, 52 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 8f113dab8bf1..dec8ced61fb0 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -114,10 +114,85 @@ static size_t syscall__fprintf_args(struct syscall *sc, unsigned long *args, FIL | |||
114 | return printed; | 114 | return printed; |
115 | } | 115 | } |
116 | 116 | ||
117 | typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel, | ||
118 | struct perf_sample *sample); | ||
119 | |||
120 | static struct syscall *trace__syscall_info(struct trace *trace, | ||
121 | struct perf_evsel *evsel, | ||
122 | struct perf_sample *sample) | ||
123 | { | ||
124 | int id = perf_evsel__intval(evsel, sample, "id"); | ||
125 | |||
126 | if (id < 0) { | ||
127 | printf("Invalid syscall %d id, skipping...\n", id); | ||
128 | return NULL; | ||
129 | } | ||
130 | |||
131 | if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) && | ||
132 | trace__read_syscall_info(trace, id)) | ||
133 | goto out_cant_read; | ||
134 | |||
135 | if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL)) | ||
136 | goto out_cant_read; | ||
137 | |||
138 | return &trace->syscalls.table[id]; | ||
139 | |||
140 | out_cant_read: | ||
141 | printf("Problems reading syscall %d information\n", id); | ||
142 | return NULL; | ||
143 | } | ||
144 | |||
145 | static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, | ||
146 | struct perf_sample *sample) | ||
147 | { | ||
148 | void *args; | ||
149 | struct syscall *sc = trace__syscall_info(trace, evsel, sample); | ||
150 | |||
151 | if (sc == NULL) | ||
152 | return -1; | ||
153 | |||
154 | args = perf_evsel__rawptr(evsel, sample, "args"); | ||
155 | if (args == NULL) { | ||
156 | printf("Problems reading syscall arguments\n"); | ||
157 | return -1; | ||
158 | } | ||
159 | |||
160 | printf("%s(", sc->name); | ||
161 | syscall__fprintf_args(sc, args, stdout); | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, | ||
167 | struct perf_sample *sample) | ||
168 | { | ||
169 | int ret; | ||
170 | struct syscall *sc = trace__syscall_info(trace, evsel, sample); | ||
171 | |||
172 | if (sc == NULL) | ||
173 | return -1; | ||
174 | |||
175 | ret = perf_evsel__intval(evsel, sample, "ret"); | ||
176 | |||
177 | if (ret < 0 && sc->fmt && sc->fmt->errmsg) { | ||
178 | char bf[256]; | ||
179 | const char *emsg = strerror_r(-ret, bf, sizeof(bf)), | ||
180 | *e = audit_errno_to_name(-ret); | ||
181 | |||
182 | printf(") = -1 %s %s", e, emsg); | ||
183 | } else if (ret == 0 && sc->fmt && sc->fmt->timeout) | ||
184 | printf(") = 0 Timeout"); | ||
185 | else | ||
186 | printf(") = %d", ret); | ||
187 | |||
188 | putchar('\n'); | ||
189 | return 0; | ||
190 | } | ||
191 | |||
117 | static int trace__run(struct trace *trace) | 192 | static int trace__run(struct trace *trace) |
118 | { | 193 | { |
119 | struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); | 194 | struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); |
120 | struct perf_evsel *evsel, *evsel_enter, *evsel_exit; | 195 | struct perf_evsel *evsel; |
121 | int err = -1, i, nr_events = 0, before; | 196 | int err = -1, i, nr_events = 0, before; |
122 | 197 | ||
123 | if (evlist == NULL) { | 198 | if (evlist == NULL) { |
@@ -125,22 +200,12 @@ static int trace__run(struct trace *trace) | |||
125 | goto out; | 200 | goto out; |
126 | } | 201 | } |
127 | 202 | ||
128 | evsel_enter = perf_evsel__newtp("raw_syscalls", "sys_enter", 0); | 203 | if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) || |
129 | if (evsel_enter == NULL) { | 204 | perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) { |
130 | printf("Couldn't read the raw_syscalls:sys_enter tracepoint information!\n"); | 205 | printf("Couldn't read the raw_syscalls tracepoints information!\n"); |
131 | goto out_delete_evlist; | ||
132 | } | ||
133 | |||
134 | perf_evlist__add(evlist, evsel_enter); | ||
135 | |||
136 | evsel_exit = perf_evsel__newtp("raw_syscalls", "sys_exit", 1); | ||
137 | if (evsel_exit == NULL) { | ||
138 | printf("Couldn't read the raw_syscalls:sys_exit tracepoint information!\n"); | ||
139 | goto out_delete_evlist; | 206 | goto out_delete_evlist; |
140 | } | 207 | } |
141 | 208 | ||
142 | perf_evlist__add(evlist, evsel_exit); | ||
143 | |||
144 | err = perf_evlist__create_maps(evlist, &trace->opts.target); | 209 | err = perf_evlist__create_maps(evlist, &trace->opts.target); |
145 | if (err < 0) { | 210 | if (err < 0) { |
146 | printf("Problems parsing the target to trace, check your options!\n"); | 211 | printf("Problems parsing the target to trace, check your options!\n"); |
@@ -170,9 +235,8 @@ again: | |||
170 | 235 | ||
171 | while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { | 236 | while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { |
172 | const u32 type = event->header.type; | 237 | const u32 type = event->header.type; |
173 | struct syscall *sc; | 238 | tracepoint_handler handler; |
174 | struct perf_sample sample; | 239 | struct perf_sample sample; |
175 | int id; | ||
176 | 240 | ||
177 | ++nr_events; | 241 | ++nr_events; |
178 | 242 | ||
@@ -200,45 +264,11 @@ again: | |||
200 | continue; | 264 | continue; |
201 | } | 265 | } |
202 | 266 | ||
203 | id = perf_evsel__intval(evsel, &sample, "id"); | ||
204 | if (id < 0) { | ||
205 | printf("Invalid syscall %d id, skipping...\n", id); | ||
206 | continue; | ||
207 | } | ||
208 | |||
209 | if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) && | ||
210 | trace__read_syscall_info(trace, id)) | ||
211 | continue; | ||
212 | |||
213 | if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL)) | ||
214 | continue; | ||
215 | |||
216 | sc = &trace->syscalls.table[id]; | ||
217 | |||
218 | if (evlist->threads->map[0] == -1 || evlist->threads->nr > 1) | 267 | if (evlist->threads->map[0] == -1 || evlist->threads->nr > 1) |
219 | printf("%d ", sample.tid); | 268 | printf("%d ", sample.tid); |
220 | 269 | ||
221 | if (evsel == evsel_enter) { | 270 | handler = evsel->handler.func; |
222 | void *args = perf_evsel__rawptr(evsel, &sample, "args"); | 271 | handler(trace, evsel, &sample); |
223 | |||
224 | printf("%s(", sc->name); | ||
225 | syscall__fprintf_args(sc, args, stdout); | ||
226 | } else if (evsel == evsel_exit) { | ||
227 | int ret = perf_evsel__intval(evsel, &sample, "ret"); | ||
228 | |||
229 | if (ret < 0 && sc->fmt && sc->fmt->errmsg) { | ||
230 | char bf[256]; | ||
231 | const char *emsg = strerror_r(-ret, bf, sizeof(bf)), | ||
232 | *e = audit_errno_to_name(-ret); | ||
233 | |||
234 | printf(") = -1 %s %s", e, emsg); | ||
235 | } else if (ret == 0 && sc->fmt && sc->fmt->timeout) | ||
236 | printf(") = 0 Timeout"); | ||
237 | else | ||
238 | printf(") = %d", ret); | ||
239 | |||
240 | putchar('\n'); | ||
241 | } | ||
242 | } | 272 | } |
243 | } | 273 | } |
244 | 274 | ||