diff options
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r-- | tools/perf/util/header.c | 361 |
1 files changed, 10 insertions, 351 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 26f5b2fe5dc8..b20e40c74468 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -24,8 +24,6 @@ | |||
24 | #include "build-id.h" | 24 | #include "build-id.h" |
25 | #include "data.h" | 25 | #include "data.h" |
26 | 26 | ||
27 | static bool no_buildid_cache = false; | ||
28 | |||
29 | static u32 header_argc; | 27 | static u32 header_argc; |
30 | static const char **header_argv; | 28 | static const char **header_argv; |
31 | 29 | ||
@@ -79,10 +77,7 @@ static int do_write(int fd, const void *buf, size_t size) | |||
79 | return 0; | 77 | return 0; |
80 | } | 78 | } |
81 | 79 | ||
82 | #define NAME_ALIGN 64 | 80 | int write_padded(int fd, const void *bf, size_t count, size_t count_aligned) |
83 | |||
84 | static int write_padded(int fd, const void *bf, size_t count, | ||
85 | size_t count_aligned) | ||
86 | { | 81 | { |
87 | static const char zero_buf[NAME_ALIGN]; | 82 | static const char zero_buf[NAME_ALIGN]; |
88 | int err = do_write(fd, bf, count); | 83 | int err = do_write(fd, bf, count); |
@@ -171,340 +166,6 @@ perf_header__set_cmdline(int argc, const char **argv) | |||
171 | return 0; | 166 | return 0; |
172 | } | 167 | } |
173 | 168 | ||
174 | #define dsos__for_each_with_build_id(pos, head) \ | ||
175 | list_for_each_entry(pos, head, node) \ | ||
176 | if (!pos->has_build_id) \ | ||
177 | continue; \ | ||
178 | else | ||
179 | |||
180 | static int write_buildid(const char *name, size_t name_len, u8 *build_id, | ||
181 | pid_t pid, u16 misc, int fd) | ||
182 | { | ||
183 | int err; | ||
184 | struct build_id_event b; | ||
185 | size_t len; | ||
186 | |||
187 | len = name_len + 1; | ||
188 | len = PERF_ALIGN(len, NAME_ALIGN); | ||
189 | |||
190 | memset(&b, 0, sizeof(b)); | ||
191 | memcpy(&b.build_id, build_id, BUILD_ID_SIZE); | ||
192 | b.pid = pid; | ||
193 | b.header.misc = misc; | ||
194 | b.header.size = sizeof(b) + len; | ||
195 | |||
196 | err = do_write(fd, &b, sizeof(b)); | ||
197 | if (err < 0) | ||
198 | return err; | ||
199 | |||
200 | return write_padded(fd, name, name_len + 1, len); | ||
201 | } | ||
202 | |||
203 | static int __dsos__hit_all(struct list_head *head) | ||
204 | { | ||
205 | struct dso *pos; | ||
206 | |||
207 | list_for_each_entry(pos, head, node) | ||
208 | pos->hit = true; | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static int machine__hit_all_dsos(struct machine *machine) | ||
214 | { | ||
215 | int err; | ||
216 | |||
217 | err = __dsos__hit_all(&machine->kernel_dsos.head); | ||
218 | if (err) | ||
219 | return err; | ||
220 | |||
221 | return __dsos__hit_all(&machine->user_dsos.head); | ||
222 | } | ||
223 | |||
224 | int dsos__hit_all(struct perf_session *session) | ||
225 | { | ||
226 | struct rb_node *nd; | ||
227 | int err; | ||
228 | |||
229 | err = machine__hit_all_dsos(&session->machines.host); | ||
230 | if (err) | ||
231 | return err; | ||
232 | |||
233 | for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { | ||
234 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
235 | |||
236 | err = machine__hit_all_dsos(pos); | ||
237 | if (err) | ||
238 | return err; | ||
239 | } | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static int __dsos__write_buildid_table(struct list_head *head, | ||
245 | struct machine *machine, | ||
246 | pid_t pid, u16 misc, int fd) | ||
247 | { | ||
248 | char nm[PATH_MAX]; | ||
249 | struct dso *pos; | ||
250 | |||
251 | dsos__for_each_with_build_id(pos, head) { | ||
252 | int err; | ||
253 | const char *name; | ||
254 | size_t name_len; | ||
255 | |||
256 | if (!pos->hit) | ||
257 | continue; | ||
258 | |||
259 | if (dso__is_vdso(pos)) { | ||
260 | name = pos->short_name; | ||
261 | name_len = pos->short_name_len + 1; | ||
262 | } else if (dso__is_kcore(pos)) { | ||
263 | machine__mmap_name(machine, nm, sizeof(nm)); | ||
264 | name = nm; | ||
265 | name_len = strlen(nm) + 1; | ||
266 | } else { | ||
267 | name = pos->long_name; | ||
268 | name_len = pos->long_name_len + 1; | ||
269 | } | ||
270 | |||
271 | err = write_buildid(name, name_len, pos->build_id, | ||
272 | pid, misc, fd); | ||
273 | if (err) | ||
274 | return err; | ||
275 | } | ||
276 | |||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | static int machine__write_buildid_table(struct machine *machine, int fd) | ||
281 | { | ||
282 | int err; | ||
283 | u16 kmisc = PERF_RECORD_MISC_KERNEL, | ||
284 | umisc = PERF_RECORD_MISC_USER; | ||
285 | |||
286 | if (!machine__is_host(machine)) { | ||
287 | kmisc = PERF_RECORD_MISC_GUEST_KERNEL; | ||
288 | umisc = PERF_RECORD_MISC_GUEST_USER; | ||
289 | } | ||
290 | |||
291 | err = __dsos__write_buildid_table(&machine->kernel_dsos.head, machine, | ||
292 | machine->pid, kmisc, fd); | ||
293 | if (err == 0) | ||
294 | err = __dsos__write_buildid_table(&machine->user_dsos.head, | ||
295 | machine, machine->pid, umisc, | ||
296 | fd); | ||
297 | return err; | ||
298 | } | ||
299 | |||
300 | static int dsos__write_buildid_table(struct perf_header *header, int fd) | ||
301 | { | ||
302 | struct perf_session *session = container_of(header, | ||
303 | struct perf_session, header); | ||
304 | struct rb_node *nd; | ||
305 | int err = machine__write_buildid_table(&session->machines.host, fd); | ||
306 | |||
307 | if (err) | ||
308 | return err; | ||
309 | |||
310 | for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { | ||
311 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
312 | err = machine__write_buildid_table(pos, fd); | ||
313 | if (err) | ||
314 | break; | ||
315 | } | ||
316 | return err; | ||
317 | } | ||
318 | |||
319 | int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | ||
320 | const char *name, bool is_kallsyms, bool is_vdso) | ||
321 | { | ||
322 | const size_t size = PATH_MAX; | ||
323 | char *realname, *filename = zalloc(size), | ||
324 | *linkname = zalloc(size), *targetname; | ||
325 | int len, err = -1; | ||
326 | bool slash = is_kallsyms || is_vdso; | ||
327 | |||
328 | if (is_kallsyms) { | ||
329 | if (symbol_conf.kptr_restrict) { | ||
330 | pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); | ||
331 | err = 0; | ||
332 | goto out_free; | ||
333 | } | ||
334 | realname = (char *) name; | ||
335 | } else | ||
336 | realname = realpath(name, NULL); | ||
337 | |||
338 | if (realname == NULL || filename == NULL || linkname == NULL) | ||
339 | goto out_free; | ||
340 | |||
341 | len = scnprintf(filename, size, "%s%s%s", | ||
342 | debugdir, slash ? "/" : "", | ||
343 | is_vdso ? DSO__NAME_VDSO : realname); | ||
344 | if (mkdir_p(filename, 0755)) | ||
345 | goto out_free; | ||
346 | |||
347 | snprintf(filename + len, size - len, "/%s", sbuild_id); | ||
348 | |||
349 | if (access(filename, F_OK)) { | ||
350 | if (is_kallsyms) { | ||
351 | if (copyfile("/proc/kallsyms", filename)) | ||
352 | goto out_free; | ||
353 | } else if (link(realname, filename) && copyfile(name, filename)) | ||
354 | goto out_free; | ||
355 | } | ||
356 | |||
357 | len = scnprintf(linkname, size, "%s/.build-id/%.2s", | ||
358 | debugdir, sbuild_id); | ||
359 | |||
360 | if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) | ||
361 | goto out_free; | ||
362 | |||
363 | snprintf(linkname + len, size - len, "/%s", sbuild_id + 2); | ||
364 | targetname = filename + strlen(debugdir) - 5; | ||
365 | memcpy(targetname, "../..", 5); | ||
366 | |||
367 | if (symlink(targetname, linkname) == 0) | ||
368 | err = 0; | ||
369 | out_free: | ||
370 | if (!is_kallsyms) | ||
371 | free(realname); | ||
372 | free(filename); | ||
373 | free(linkname); | ||
374 | return err; | ||
375 | } | ||
376 | |||
377 | static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, | ||
378 | const char *name, const char *debugdir, | ||
379 | bool is_kallsyms, bool is_vdso) | ||
380 | { | ||
381 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
382 | |||
383 | build_id__sprintf(build_id, build_id_size, sbuild_id); | ||
384 | |||
385 | return build_id_cache__add_s(sbuild_id, debugdir, name, | ||
386 | is_kallsyms, is_vdso); | ||
387 | } | ||
388 | |||
389 | int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) | ||
390 | { | ||
391 | const size_t size = PATH_MAX; | ||
392 | char *filename = zalloc(size), | ||
393 | *linkname = zalloc(size); | ||
394 | int err = -1; | ||
395 | |||
396 | if (filename == NULL || linkname == NULL) | ||
397 | goto out_free; | ||
398 | |||
399 | snprintf(linkname, size, "%s/.build-id/%.2s/%s", | ||
400 | debugdir, sbuild_id, sbuild_id + 2); | ||
401 | |||
402 | if (access(linkname, F_OK)) | ||
403 | goto out_free; | ||
404 | |||
405 | if (readlink(linkname, filename, size - 1) < 0) | ||
406 | goto out_free; | ||
407 | |||
408 | if (unlink(linkname)) | ||
409 | goto out_free; | ||
410 | |||
411 | /* | ||
412 | * Since the link is relative, we must make it absolute: | ||
413 | */ | ||
414 | snprintf(linkname, size, "%s/.build-id/%.2s/%s", | ||
415 | debugdir, sbuild_id, filename); | ||
416 | |||
417 | if (unlink(linkname)) | ||
418 | goto out_free; | ||
419 | |||
420 | err = 0; | ||
421 | out_free: | ||
422 | free(filename); | ||
423 | free(linkname); | ||
424 | return err; | ||
425 | } | ||
426 | |||
427 | static int dso__cache_build_id(struct dso *dso, struct machine *machine, | ||
428 | const char *debugdir) | ||
429 | { | ||
430 | bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; | ||
431 | bool is_vdso = dso__is_vdso(dso); | ||
432 | const char *name = dso->long_name; | ||
433 | char nm[PATH_MAX]; | ||
434 | |||
435 | if (dso__is_kcore(dso)) { | ||
436 | is_kallsyms = true; | ||
437 | machine__mmap_name(machine, nm, sizeof(nm)); | ||
438 | name = nm; | ||
439 | } | ||
440 | return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name, | ||
441 | debugdir, is_kallsyms, is_vdso); | ||
442 | } | ||
443 | |||
444 | static int __dsos__cache_build_ids(struct list_head *head, | ||
445 | struct machine *machine, const char *debugdir) | ||
446 | { | ||
447 | struct dso *pos; | ||
448 | int err = 0; | ||
449 | |||
450 | dsos__for_each_with_build_id(pos, head) | ||
451 | if (dso__cache_build_id(pos, machine, debugdir)) | ||
452 | err = -1; | ||
453 | |||
454 | return err; | ||
455 | } | ||
456 | |||
457 | static int machine__cache_build_ids(struct machine *machine, const char *debugdir) | ||
458 | { | ||
459 | int ret = __dsos__cache_build_ids(&machine->kernel_dsos.head, machine, | ||
460 | debugdir); | ||
461 | ret |= __dsos__cache_build_ids(&machine->user_dsos.head, machine, | ||
462 | debugdir); | ||
463 | return ret; | ||
464 | } | ||
465 | |||
466 | static int perf_session__cache_build_ids(struct perf_session *session) | ||
467 | { | ||
468 | struct rb_node *nd; | ||
469 | int ret; | ||
470 | char debugdir[PATH_MAX]; | ||
471 | |||
472 | snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir); | ||
473 | |||
474 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) | ||
475 | return -1; | ||
476 | |||
477 | ret = machine__cache_build_ids(&session->machines.host, debugdir); | ||
478 | |||
479 | for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { | ||
480 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
481 | ret |= machine__cache_build_ids(pos, debugdir); | ||
482 | } | ||
483 | return ret ? -1 : 0; | ||
484 | } | ||
485 | |||
486 | static bool machine__read_build_ids(struct machine *machine, bool with_hits) | ||
487 | { | ||
488 | bool ret; | ||
489 | |||
490 | ret = __dsos__read_build_ids(&machine->kernel_dsos.head, with_hits); | ||
491 | ret |= __dsos__read_build_ids(&machine->user_dsos.head, with_hits); | ||
492 | return ret; | ||
493 | } | ||
494 | |||
495 | static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) | ||
496 | { | ||
497 | struct rb_node *nd; | ||
498 | bool ret = machine__read_build_ids(&session->machines.host, with_hits); | ||
499 | |||
500 | for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { | ||
501 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
502 | ret |= machine__read_build_ids(pos, with_hits); | ||
503 | } | ||
504 | |||
505 | return ret; | ||
506 | } | ||
507 | |||
508 | static int write_tracing_data(int fd, struct perf_header *h __maybe_unused, | 169 | static int write_tracing_data(int fd, struct perf_header *h __maybe_unused, |
509 | struct perf_evlist *evlist) | 170 | struct perf_evlist *evlist) |
510 | { | 171 | { |
@@ -523,13 +184,12 @@ static int write_build_id(int fd, struct perf_header *h, | |||
523 | if (!perf_session__read_build_ids(session, true)) | 184 | if (!perf_session__read_build_ids(session, true)) |
524 | return -1; | 185 | return -1; |
525 | 186 | ||
526 | err = dsos__write_buildid_table(h, fd); | 187 | err = perf_session__write_buildid_table(session, fd); |
527 | if (err < 0) { | 188 | if (err < 0) { |
528 | pr_debug("failed to write buildid table\n"); | 189 | pr_debug("failed to write buildid table\n"); |
529 | return err; | 190 | return err; |
530 | } | 191 | } |
531 | if (!no_buildid_cache) | 192 | perf_session__cache_build_ids(session); |
532 | perf_session__cache_build_ids(session); | ||
533 | 193 | ||
534 | return 0; | 194 | return 0; |
535 | } | 195 | } |
@@ -601,8 +261,10 @@ static int __write_cpudesc(int fd, const char *cpuinfo_proc) | |||
601 | break; | 261 | break; |
602 | } | 262 | } |
603 | 263 | ||
604 | if (ret) | 264 | if (ret) { |
265 | ret = -1; | ||
605 | goto done; | 266 | goto done; |
267 | } | ||
606 | 268 | ||
607 | s = buf; | 269 | s = buf; |
608 | 270 | ||
@@ -965,7 +627,8 @@ static int write_total_mem(int fd, struct perf_header *h __maybe_unused, | |||
965 | n = sscanf(buf, "%*s %"PRIu64, &mem); | 627 | n = sscanf(buf, "%*s %"PRIu64, &mem); |
966 | if (n == 1) | 628 | if (n == 1) |
967 | ret = do_write(fd, &mem, sizeof(mem)); | 629 | ret = do_write(fd, &mem, sizeof(mem)); |
968 | } | 630 | } else |
631 | ret = -1; | ||
969 | free(buf); | 632 | free(buf); |
970 | fclose(fp); | 633 | fclose(fp); |
971 | return ret; | 634 | return ret; |
@@ -1603,7 +1266,7 @@ static int __event_process_build_id(struct build_id_event *bev, | |||
1603 | 1266 | ||
1604 | dso__set_build_id(dso, &bev->build_id); | 1267 | dso__set_build_id(dso, &bev->build_id); |
1605 | 1268 | ||
1606 | if (filename[0] == '[') | 1269 | if (!is_kernel_module(filename, NULL)) |
1607 | dso->kernel = dso_type; | 1270 | dso->kernel = dso_type; |
1608 | 1271 | ||
1609 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), | 1272 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), |
@@ -2477,6 +2140,7 @@ static const int attr_file_abi_sizes[] = { | |||
2477 | [1] = PERF_ATTR_SIZE_VER1, | 2140 | [1] = PERF_ATTR_SIZE_VER1, |
2478 | [2] = PERF_ATTR_SIZE_VER2, | 2141 | [2] = PERF_ATTR_SIZE_VER2, |
2479 | [3] = PERF_ATTR_SIZE_VER3, | 2142 | [3] = PERF_ATTR_SIZE_VER3, |
2143 | [4] = PERF_ATTR_SIZE_VER4, | ||
2480 | 0, | 2144 | 0, |
2481 | }; | 2145 | }; |
2482 | 2146 | ||
@@ -3124,8 +2788,3 @@ int perf_event__process_build_id(struct perf_tool *tool __maybe_unused, | |||
3124 | session); | 2788 | session); |
3125 | return 0; | 2789 | return 0; |
3126 | } | 2790 | } |
3127 | |||
3128 | void disable_buildid_cache(void) | ||
3129 | { | ||
3130 | no_buildid_cache = true; | ||
3131 | } | ||