diff options
Diffstat (limited to 'tools/perf/util')
47 files changed, 695 insertions, 287 deletions
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 3840e3a87057..5da376bc1afc 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build | |||
@@ -162,6 +162,7 @@ CFLAGS_rbtree.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ET | |||
162 | CFLAGS_libstring.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" | 162 | CFLAGS_libstring.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" |
163 | CFLAGS_hweight.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" | 163 | CFLAGS_hweight.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" |
164 | CFLAGS_parse-events.o += -Wno-redundant-decls | 164 | CFLAGS_parse-events.o += -Wno-redundant-decls |
165 | CFLAGS_header.o += -include $(OUTPUT)PERF-VERSION-FILE | ||
165 | 166 | ||
166 | $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c FORCE | 167 | $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c FORCE |
167 | $(call rule_mkdir) | 168 | $(call rule_mkdir) |
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 36c861103291..bc6bc7062eb4 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c | |||
@@ -670,13 +670,13 @@ int bpf__probe(struct bpf_object *obj) | |||
670 | 670 | ||
671 | err = convert_perf_probe_events(pev, 1); | 671 | err = convert_perf_probe_events(pev, 1); |
672 | if (err < 0) { | 672 | if (err < 0) { |
673 | pr_debug("bpf_probe: failed to convert perf probe events"); | 673 | pr_debug("bpf_probe: failed to convert perf probe events\n"); |
674 | goto out; | 674 | goto out; |
675 | } | 675 | } |
676 | 676 | ||
677 | err = apply_perf_probe_events(pev, 1); | 677 | err = apply_perf_probe_events(pev, 1); |
678 | if (err < 0) { | 678 | if (err < 0) { |
679 | pr_debug("bpf_probe: failed to apply perf probe events"); | 679 | pr_debug("bpf_probe: failed to apply perf probe events\n"); |
680 | goto out; | 680 | goto out; |
681 | } | 681 | } |
682 | 682 | ||
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 42922512c1c6..aba953421a03 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -48,6 +48,8 @@ static int parse_callchain_mode(const char *value) | |||
48 | callchain_param.mode = CHAIN_FOLDED; | 48 | callchain_param.mode = CHAIN_FOLDED; |
49 | return 0; | 49 | return 0; |
50 | } | 50 | } |
51 | |||
52 | pr_err("Invalid callchain mode: %s\n", value); | ||
51 | return -1; | 53 | return -1; |
52 | } | 54 | } |
53 | 55 | ||
@@ -63,6 +65,8 @@ static int parse_callchain_order(const char *value) | |||
63 | callchain_param.order_set = true; | 65 | callchain_param.order_set = true; |
64 | return 0; | 66 | return 0; |
65 | } | 67 | } |
68 | |||
69 | pr_err("Invalid callchain order: %s\n", value); | ||
66 | return -1; | 70 | return -1; |
67 | } | 71 | } |
68 | 72 | ||
@@ -80,6 +84,8 @@ static int parse_callchain_sort_key(const char *value) | |||
80 | callchain_param.branch_callstack = 1; | 84 | callchain_param.branch_callstack = 1; |
81 | return 0; | 85 | return 0; |
82 | } | 86 | } |
87 | |||
88 | pr_err("Invalid callchain sort key: %s\n", value); | ||
83 | return -1; | 89 | return -1; |
84 | } | 90 | } |
85 | 91 | ||
@@ -97,6 +103,8 @@ static int parse_callchain_value(const char *value) | |||
97 | callchain_param.value = CCVAL_COUNT; | 103 | callchain_param.value = CCVAL_COUNT; |
98 | return 0; | 104 | return 0; |
99 | } | 105 | } |
106 | |||
107 | pr_err("Invalid callchain config key: %s\n", value); | ||
100 | return -1; | 108 | return -1; |
101 | } | 109 | } |
102 | 110 | ||
@@ -210,13 +218,17 @@ int perf_callchain_config(const char *var, const char *value) | |||
210 | return parse_callchain_sort_key(value); | 218 | return parse_callchain_sort_key(value); |
211 | if (!strcmp(var, "threshold")) { | 219 | if (!strcmp(var, "threshold")) { |
212 | callchain_param.min_percent = strtod(value, &endptr); | 220 | callchain_param.min_percent = strtod(value, &endptr); |
213 | if (value == endptr) | 221 | if (value == endptr) { |
222 | pr_err("Invalid callchain threshold: %s\n", value); | ||
214 | return -1; | 223 | return -1; |
224 | } | ||
215 | } | 225 | } |
216 | if (!strcmp(var, "print-limit")) { | 226 | if (!strcmp(var, "print-limit")) { |
217 | callchain_param.print_limit = strtod(value, &endptr); | 227 | callchain_param.print_limit = strtod(value, &endptr); |
218 | if (value == endptr) | 228 | if (value == endptr) { |
229 | pr_err("Invalid callchain print limit: %s\n", value); | ||
219 | return -1; | 230 | return -1; |
231 | } | ||
220 | } | 232 | } |
221 | 233 | ||
222 | return 0; | 234 | return 0; |
@@ -437,7 +449,7 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor) | |||
437 | } | 449 | } |
438 | call->ip = cursor_node->ip; | 450 | call->ip = cursor_node->ip; |
439 | call->ms.sym = cursor_node->sym; | 451 | call->ms.sym = cursor_node->sym; |
440 | call->ms.map = cursor_node->map; | 452 | call->ms.map = map__get(cursor_node->map); |
441 | 453 | ||
442 | if (cursor_node->branch) { | 454 | if (cursor_node->branch) { |
443 | call->branch_count = 1; | 455 | call->branch_count = 1; |
@@ -477,6 +489,7 @@ add_child(struct callchain_node *parent, | |||
477 | 489 | ||
478 | list_for_each_entry_safe(call, tmp, &new->val, list) { | 490 | list_for_each_entry_safe(call, tmp, &new->val, list) { |
479 | list_del(&call->list); | 491 | list_del(&call->list); |
492 | map__zput(call->ms.map); | ||
480 | free(call); | 493 | free(call); |
481 | } | 494 | } |
482 | free(new); | 495 | free(new); |
@@ -761,6 +774,7 @@ merge_chain_branch(struct callchain_cursor *cursor, | |||
761 | list->ms.map, list->ms.sym, | 774 | list->ms.map, list->ms.sym, |
762 | false, NULL, 0, 0); | 775 | false, NULL, 0, 0); |
763 | list_del(&list->list); | 776 | list_del(&list->list); |
777 | map__zput(list->ms.map); | ||
764 | free(list); | 778 | free(list); |
765 | } | 779 | } |
766 | 780 | ||
@@ -811,7 +825,8 @@ int callchain_cursor_append(struct callchain_cursor *cursor, | |||
811 | } | 825 | } |
812 | 826 | ||
813 | node->ip = ip; | 827 | node->ip = ip; |
814 | node->map = map; | 828 | map__zput(node->map); |
829 | node->map = map__get(map); | ||
815 | node->sym = sym; | 830 | node->sym = sym; |
816 | node->branch = branch; | 831 | node->branch = branch; |
817 | node->nr_loop_iter = nr_loop_iter; | 832 | node->nr_loop_iter = nr_loop_iter; |
@@ -1142,11 +1157,13 @@ static void free_callchain_node(struct callchain_node *node) | |||
1142 | 1157 | ||
1143 | list_for_each_entry_safe(list, tmp, &node->parent_val, list) { | 1158 | list_for_each_entry_safe(list, tmp, &node->parent_val, list) { |
1144 | list_del(&list->list); | 1159 | list_del(&list->list); |
1160 | map__zput(list->ms.map); | ||
1145 | free(list); | 1161 | free(list); |
1146 | } | 1162 | } |
1147 | 1163 | ||
1148 | list_for_each_entry_safe(list, tmp, &node->val, list) { | 1164 | list_for_each_entry_safe(list, tmp, &node->val, list) { |
1149 | list_del(&list->list); | 1165 | list_del(&list->list); |
1166 | map__zput(list->ms.map); | ||
1150 | free(list); | 1167 | free(list); |
1151 | } | 1168 | } |
1152 | 1169 | ||
@@ -1210,6 +1227,7 @@ int callchain_node__make_parent_list(struct callchain_node *node) | |||
1210 | goto out; | 1227 | goto out; |
1211 | *new = *chain; | 1228 | *new = *chain; |
1212 | new->has_children = false; | 1229 | new->has_children = false; |
1230 | map__get(new->ms.map); | ||
1213 | list_add_tail(&new->list, &head); | 1231 | list_add_tail(&new->list, &head); |
1214 | } | 1232 | } |
1215 | parent = parent->parent; | 1233 | parent = parent->parent; |
@@ -1230,6 +1248,7 @@ int callchain_node__make_parent_list(struct callchain_node *node) | |||
1230 | out: | 1248 | out: |
1231 | list_for_each_entry_safe(chain, new, &head, list) { | 1249 | list_for_each_entry_safe(chain, new, &head, list) { |
1232 | list_del(&chain->list); | 1250 | list_del(&chain->list); |
1251 | map__zput(chain->ms.map); | ||
1233 | free(chain); | 1252 | free(chain); |
1234 | } | 1253 | } |
1235 | return -ENOMEM; | 1254 | return -ENOMEM; |
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 35c8e379530f..4f4b60f1558a 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/list.h> | 5 | #include <linux/list.h> |
6 | #include <linux/rbtree.h> | 6 | #include <linux/rbtree.h> |
7 | #include "event.h" | 7 | #include "event.h" |
8 | #include "map.h" | ||
8 | #include "symbol.h" | 9 | #include "symbol.h" |
9 | 10 | ||
10 | #define HELP_PAD "\t\t\t\t" | 11 | #define HELP_PAD "\t\t\t\t" |
@@ -184,8 +185,13 @@ int callchain_merge(struct callchain_cursor *cursor, | |||
184 | */ | 185 | */ |
185 | static inline void callchain_cursor_reset(struct callchain_cursor *cursor) | 186 | static inline void callchain_cursor_reset(struct callchain_cursor *cursor) |
186 | { | 187 | { |
188 | struct callchain_cursor_node *node; | ||
189 | |||
187 | cursor->nr = 0; | 190 | cursor->nr = 0; |
188 | cursor->last = &cursor->first; | 191 | cursor->last = &cursor->first; |
192 | |||
193 | for (node = cursor->first; node != NULL; node = node->next) | ||
194 | map__zput(node->map); | ||
189 | } | 195 | } |
190 | 196 | ||
191 | int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip, | 197 | int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip, |
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 3d906dbbef74..0c7d5a4975cd 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c | |||
@@ -386,8 +386,10 @@ static int perf_buildid_config(const char *var, const char *value) | |||
386 | if (!strcmp(var, "buildid.dir")) { | 386 | if (!strcmp(var, "buildid.dir")) { |
387 | const char *dir = perf_config_dirname(var, value); | 387 | const char *dir = perf_config_dirname(var, value); |
388 | 388 | ||
389 | if (!dir) | 389 | if (!dir) { |
390 | pr_err("Invalid buildid directory!\n"); | ||
390 | return -1; | 391 | return -1; |
392 | } | ||
391 | strncpy(buildid_dir, dir, MAXPATHLEN-1); | 393 | strncpy(buildid_dir, dir, MAXPATHLEN-1); |
392 | buildid_dir[MAXPATHLEN-1] = '\0'; | 394 | buildid_dir[MAXPATHLEN-1] = '\0'; |
393 | } | 395 | } |
@@ -405,10 +407,9 @@ static int perf_default_core_config(const char *var __maybe_unused, | |||
405 | static int perf_ui_config(const char *var, const char *value) | 407 | static int perf_ui_config(const char *var, const char *value) |
406 | { | 408 | { |
407 | /* Add other config variables here. */ | 409 | /* Add other config variables here. */ |
408 | if (!strcmp(var, "ui.show-headers")) { | 410 | if (!strcmp(var, "ui.show-headers")) |
409 | symbol_conf.show_hist_headers = perf_config_bool(var, value); | 411 | symbol_conf.show_hist_headers = perf_config_bool(var, value); |
410 | return 0; | 412 | |
411 | } | ||
412 | return 0; | 413 | return 0; |
413 | } | 414 | } |
414 | 415 | ||
@@ -646,8 +647,13 @@ static int perf_config_set__init(struct perf_config_set *set) | |||
646 | goto out; | 647 | goto out; |
647 | } | 648 | } |
648 | 649 | ||
649 | if (stat(user_config, &st) < 0) | 650 | if (stat(user_config, &st) < 0) { |
651 | if (errno == ENOENT) | ||
652 | ret = 0; | ||
650 | goto out_free; | 653 | goto out_free; |
654 | } | ||
655 | |||
656 | ret = 0; | ||
651 | 657 | ||
652 | if (st.st_uid && (st.st_uid != geteuid())) { | 658 | if (st.st_uid && (st.st_uid != geteuid())) { |
653 | warning("File %s not owned by current user or root, " | 659 | warning("File %s not owned by current user or root, " |
@@ -655,11 +661,8 @@ static int perf_config_set__init(struct perf_config_set *set) | |||
655 | goto out_free; | 661 | goto out_free; |
656 | } | 662 | } |
657 | 663 | ||
658 | if (!st.st_size) | 664 | if (st.st_size) |
659 | goto out_free; | 665 | ret = perf_config_from_file(collect_config, user_config, set); |
660 | |||
661 | ret = perf_config_from_file(collect_config, user_config, set); | ||
662 | |||
663 | out_free: | 666 | out_free: |
664 | free(user_config); | 667 | free(user_config); |
665 | } | 668 | } |
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 7123f4de32cc..4e6cbc99f08e 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c | |||
@@ -1473,7 +1473,7 @@ int bt_convert__perf2ctf(const char *input, const char *path, | |||
1473 | }, | 1473 | }, |
1474 | }; | 1474 | }; |
1475 | struct ctf_writer *cw = &c.writer; | 1475 | struct ctf_writer *cw = &c.writer; |
1476 | int err = -1; | 1476 | int err; |
1477 | 1477 | ||
1478 | if (opts->all) { | 1478 | if (opts->all) { |
1479 | c.tool.comm = process_comm_event; | 1479 | c.tool.comm = process_comm_event; |
@@ -1481,12 +1481,15 @@ int bt_convert__perf2ctf(const char *input, const char *path, | |||
1481 | c.tool.fork = process_fork_event; | 1481 | c.tool.fork = process_fork_event; |
1482 | } | 1482 | } |
1483 | 1483 | ||
1484 | perf_config(convert__config, &c); | 1484 | err = perf_config(convert__config, &c); |
1485 | if (err) | ||
1486 | return err; | ||
1485 | 1487 | ||
1486 | /* CTF writer */ | 1488 | /* CTF writer */ |
1487 | if (ctf_writer__init(cw, path)) | 1489 | if (ctf_writer__init(cw, path)) |
1488 | return -1; | 1490 | return -1; |
1489 | 1491 | ||
1492 | err = -1; | ||
1490 | /* perf.data session */ | 1493 | /* perf.data session */ |
1491 | session = perf_session__new(&file, 0, &c.tool); | 1494 | session = perf_session__new(&file, 0, &c.tool); |
1492 | if (!session) | 1495 | if (!session) |
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index d2c6cdd9d42b..28d41e709128 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
@@ -9,6 +9,13 @@ | |||
9 | #include "debug.h" | 9 | #include "debug.h" |
10 | #include "vdso.h" | 10 | #include "vdso.h" |
11 | 11 | ||
12 | static const char * const debuglink_paths[] = { | ||
13 | "%.0s%s", | ||
14 | "%s/%s", | ||
15 | "%s/.debug/%s", | ||
16 | "/usr/lib/debug%s/%s" | ||
17 | }; | ||
18 | |||
12 | char dso__symtab_origin(const struct dso *dso) | 19 | char dso__symtab_origin(const struct dso *dso) |
13 | { | 20 | { |
14 | static const char origin[] = { | 21 | static const char origin[] = { |
@@ -44,24 +51,43 @@ int dso__read_binary_type_filename(const struct dso *dso, | |||
44 | size_t len; | 51 | size_t len; |
45 | 52 | ||
46 | switch (type) { | 53 | switch (type) { |
47 | case DSO_BINARY_TYPE__DEBUGLINK: { | 54 | case DSO_BINARY_TYPE__DEBUGLINK: |
48 | char *debuglink; | 55 | { |
56 | const char *last_slash; | ||
57 | char dso_dir[PATH_MAX]; | ||
58 | char symfile[PATH_MAX]; | ||
59 | unsigned int i; | ||
49 | 60 | ||
50 | len = __symbol__join_symfs(filename, size, dso->long_name); | 61 | len = __symbol__join_symfs(filename, size, dso->long_name); |
51 | debuglink = filename + len; | 62 | last_slash = filename + len; |
52 | while (debuglink != filename && *debuglink != '/') | 63 | while (last_slash != filename && *last_slash != '/') |
53 | debuglink--; | 64 | last_slash--; |
54 | if (*debuglink == '/') | ||
55 | debuglink++; | ||
56 | 65 | ||
57 | ret = -1; | 66 | strncpy(dso_dir, filename, last_slash - filename); |
58 | if (!is_regular_file(filename)) | 67 | dso_dir[last_slash-filename] = '\0'; |
68 | |||
69 | if (!is_regular_file(filename)) { | ||
70 | ret = -1; | ||
71 | break; | ||
72 | } | ||
73 | |||
74 | ret = filename__read_debuglink(filename, symfile, PATH_MAX); | ||
75 | if (ret) | ||
59 | break; | 76 | break; |
60 | 77 | ||
61 | ret = filename__read_debuglink(filename, debuglink, | 78 | /* Check predefined locations where debug file might reside */ |
62 | size - (debuglink - filename)); | 79 | ret = -1; |
80 | for (i = 0; i < ARRAY_SIZE(debuglink_paths); i++) { | ||
81 | snprintf(filename, size, | ||
82 | debuglink_paths[i], dso_dir, symfile); | ||
83 | if (is_regular_file(filename)) { | ||
84 | ret = 0; | ||
85 | break; | ||
86 | } | ||
63 | } | 87 | } |
88 | |||
64 | break; | 89 | break; |
90 | } | ||
65 | case DSO_BINARY_TYPE__BUILD_ID_CACHE: | 91 | case DSO_BINARY_TYPE__BUILD_ID_CACHE: |
66 | if (dso__build_id_filename(dso, filename, size) == NULL) | 92 | if (dso__build_id_filename(dso, filename, size) == NULL) |
67 | ret = -1; | 93 | ret = -1; |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 8ab0d7da956b..4ea7ce72ed9c 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -1,5 +1,5 @@ | |||
1 | #include <linux/types.h> | 1 | #include <linux/types.h> |
2 | #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ | 2 | #include <linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ |
3 | #include <api/fs/fs.h> | 3 | #include <api/fs/fs.h> |
4 | #include "event.h" | 4 | #include "event.h" |
5 | #include "debug.h" | 5 | #include "debug.h" |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index d92e02006fb8..b601f2814a30 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -1184,7 +1184,7 @@ unsigned long perf_event_mlock_kb_in_pages(void) | |||
1184 | return pages; | 1184 | return pages; |
1185 | } | 1185 | } |
1186 | 1186 | ||
1187 | static size_t perf_evlist__mmap_size(unsigned long pages) | 1187 | size_t perf_evlist__mmap_size(unsigned long pages) |
1188 | { | 1188 | { |
1189 | if (pages == UINT_MAX) | 1189 | if (pages == UINT_MAX) |
1190 | pages = perf_event_mlock_kb_in_pages(); | 1190 | pages = perf_event_mlock_kb_in_pages(); |
@@ -1224,12 +1224,16 @@ static long parse_pages_arg(const char *str, unsigned long min, | |||
1224 | if (pages == 0 && min == 0) { | 1224 | if (pages == 0 && min == 0) { |
1225 | /* leave number of pages at 0 */ | 1225 | /* leave number of pages at 0 */ |
1226 | } else if (!is_power_of_2(pages)) { | 1226 | } else if (!is_power_of_2(pages)) { |
1227 | char buf[100]; | ||
1228 | |||
1227 | /* round pages up to next power of 2 */ | 1229 | /* round pages up to next power of 2 */ |
1228 | pages = roundup_pow_of_two(pages); | 1230 | pages = roundup_pow_of_two(pages); |
1229 | if (!pages) | 1231 | if (!pages) |
1230 | return -EINVAL; | 1232 | return -EINVAL; |
1231 | pr_info("rounding mmap pages size to %lu bytes (%lu pages)\n", | 1233 | |
1232 | pages * page_size, pages); | 1234 | unit_number__scnprintf(buf, sizeof(buf), pages * page_size); |
1235 | pr_info("rounding mmap pages size to %s (%lu pages)\n", | ||
1236 | buf, pages); | ||
1233 | } | 1237 | } |
1234 | 1238 | ||
1235 | if (pages > max) | 1239 | if (pages > max) |
@@ -1797,7 +1801,7 @@ int perf_evlist__start_workload(struct perf_evlist *evlist) | |||
1797 | */ | 1801 | */ |
1798 | ret = write(evlist->workload.cork_fd, &bf, 1); | 1802 | ret = write(evlist->workload.cork_fd, &bf, 1); |
1799 | if (ret < 0) | 1803 | if (ret < 0) |
1800 | perror("enable to write to pipe"); | 1804 | perror("unable to write to pipe"); |
1801 | 1805 | ||
1802 | close(evlist->workload.cork_fd); | 1806 | close(evlist->workload.cork_fd); |
1803 | return ret; | 1807 | return ret; |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 4fd034f22d2f..389b9ccdf8c7 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -218,6 +218,8 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, | |||
218 | bool overwrite); | 218 | bool overwrite); |
219 | void perf_evlist__munmap(struct perf_evlist *evlist); | 219 | void perf_evlist__munmap(struct perf_evlist *evlist); |
220 | 220 | ||
221 | size_t perf_evlist__mmap_size(unsigned long pages); | ||
222 | |||
221 | void perf_evlist__disable(struct perf_evlist *evlist); | 223 | void perf_evlist__disable(struct perf_evlist *evlist); |
222 | void perf_evlist__enable(struct perf_evlist *evlist); | 224 | void perf_evlist__enable(struct perf_evlist *evlist); |
223 | void perf_evlist__toggle_enable(struct perf_evlist *evlist); | 225 | void perf_evlist__toggle_enable(struct perf_evlist *evlist); |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 04e536ae4d88..ac59710b79e0 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -1448,8 +1448,8 @@ static bool ignore_missing_thread(struct perf_evsel *evsel, | |||
1448 | return true; | 1448 | return true; |
1449 | } | 1449 | } |
1450 | 1450 | ||
1451 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 1451 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
1452 | struct thread_map *threads) | 1452 | struct thread_map *threads) |
1453 | { | 1453 | { |
1454 | int cpu, thread, nthreads; | 1454 | int cpu, thread, nthreads; |
1455 | unsigned long flags = PERF_FLAG_FD_CLOEXEC; | 1455 | unsigned long flags = PERF_FLAG_FD_CLOEXEC; |
@@ -1459,6 +1459,30 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
1459 | if (perf_missing_features.write_backward && evsel->attr.write_backward) | 1459 | if (perf_missing_features.write_backward && evsel->attr.write_backward) |
1460 | return -EINVAL; | 1460 | return -EINVAL; |
1461 | 1461 | ||
1462 | if (cpus == NULL) { | ||
1463 | static struct cpu_map *empty_cpu_map; | ||
1464 | |||
1465 | if (empty_cpu_map == NULL) { | ||
1466 | empty_cpu_map = cpu_map__dummy_new(); | ||
1467 | if (empty_cpu_map == NULL) | ||
1468 | return -ENOMEM; | ||
1469 | } | ||
1470 | |||
1471 | cpus = empty_cpu_map; | ||
1472 | } | ||
1473 | |||
1474 | if (threads == NULL) { | ||
1475 | static struct thread_map *empty_thread_map; | ||
1476 | |||
1477 | if (empty_thread_map == NULL) { | ||
1478 | empty_thread_map = thread_map__new_by_tid(-1); | ||
1479 | if (empty_thread_map == NULL) | ||
1480 | return -ENOMEM; | ||
1481 | } | ||
1482 | |||
1483 | threads = empty_thread_map; | ||
1484 | } | ||
1485 | |||
1462 | if (evsel->system_wide) | 1486 | if (evsel->system_wide) |
1463 | nthreads = 1; | 1487 | nthreads = 1; |
1464 | else | 1488 | else |
@@ -1655,46 +1679,16 @@ void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
1655 | perf_evsel__free_fd(evsel); | 1679 | perf_evsel__free_fd(evsel); |
1656 | } | 1680 | } |
1657 | 1681 | ||
1658 | static struct { | ||
1659 | struct cpu_map map; | ||
1660 | int cpus[1]; | ||
1661 | } empty_cpu_map = { | ||
1662 | .map.nr = 1, | ||
1663 | .cpus = { -1, }, | ||
1664 | }; | ||
1665 | |||
1666 | static struct { | ||
1667 | struct thread_map map; | ||
1668 | int threads[1]; | ||
1669 | } empty_thread_map = { | ||
1670 | .map.nr = 1, | ||
1671 | .threads = { -1, }, | ||
1672 | }; | ||
1673 | |||
1674 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | ||
1675 | struct thread_map *threads) | ||
1676 | { | ||
1677 | if (cpus == NULL) { | ||
1678 | /* Work around old compiler warnings about strict aliasing */ | ||
1679 | cpus = &empty_cpu_map.map; | ||
1680 | } | ||
1681 | |||
1682 | if (threads == NULL) | ||
1683 | threads = &empty_thread_map.map; | ||
1684 | |||
1685 | return __perf_evsel__open(evsel, cpus, threads); | ||
1686 | } | ||
1687 | |||
1688 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, | 1682 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, |
1689 | struct cpu_map *cpus) | 1683 | struct cpu_map *cpus) |
1690 | { | 1684 | { |
1691 | return __perf_evsel__open(evsel, cpus, &empty_thread_map.map); | 1685 | return perf_evsel__open(evsel, cpus, NULL); |
1692 | } | 1686 | } |
1693 | 1687 | ||
1694 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, | 1688 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, |
1695 | struct thread_map *threads) | 1689 | struct thread_map *threads) |
1696 | { | 1690 | { |
1697 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads); | 1691 | return perf_evsel__open(evsel, NULL, threads); |
1698 | } | 1692 | } |
1699 | 1693 | ||
1700 | static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel, | 1694 | static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel, |
@@ -2469,7 +2463,9 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, | |||
2469 | " -1: Allow use of (almost) all events by all users\n" | 2463 | " -1: Allow use of (almost) all events by all users\n" |
2470 | ">= 0: Disallow raw tracepoint access by users without CAP_IOC_LOCK\n" | 2464 | ">= 0: Disallow raw tracepoint access by users without CAP_IOC_LOCK\n" |
2471 | ">= 1: Disallow CPU event access by users without CAP_SYS_ADMIN\n" | 2465 | ">= 1: Disallow CPU event access by users without CAP_SYS_ADMIN\n" |
2472 | ">= 2: Disallow kernel profiling by users without CAP_SYS_ADMIN", | 2466 | ">= 2: Disallow kernel profiling by users without CAP_SYS_ADMIN\n\n" |
2467 | "To make this setting permanent, edit /etc/sysctl.conf too, e.g.:\n\n" | ||
2468 | " kernel.perf_event_paranoid = -1\n" , | ||
2473 | target->system_wide ? "system-wide " : "", | 2469 | target->system_wide ? "system-wide " : "", |
2474 | perf_event_paranoid()); | 2470 | perf_event_paranoid()); |
2475 | case ENOENT: | 2471 | case ENOENT: |
diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c index 6b2925542c0a..4ef5184819a0 100644 --- a/tools/perf/util/evsel_fprintf.c +++ b/tools/perf/util/evsel_fprintf.c | |||
@@ -168,7 +168,6 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, | |||
168 | 168 | ||
169 | if (symbol_conf.bt_stop_list && | 169 | if (symbol_conf.bt_stop_list && |
170 | node->sym && | 170 | node->sym && |
171 | node->sym->name && | ||
172 | strlist__has_entry(symbol_conf.bt_stop_list, | 171 | strlist__has_entry(symbol_conf.bt_stop_list, |
173 | node->sym->name)) { | 172 | node->sym->name)) { |
174 | break; | 173 | break; |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index d89c9c7ef4e5..3d12c16e5103 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -41,6 +41,8 @@ static const u64 __perf_magic2_sw = 0x50455246494c4532ULL; | |||
41 | 41 | ||
42 | #define PERF_MAGIC __perf_magic2 | 42 | #define PERF_MAGIC __perf_magic2 |
43 | 43 | ||
44 | const char perf_version_string[] = PERF_VERSION; | ||
45 | |||
44 | struct perf_file_attr { | 46 | struct perf_file_attr { |
45 | struct perf_event_attr attr; | 47 | struct perf_event_attr attr; |
46 | struct perf_file_section ids; | 48 | struct perf_file_section ids; |
@@ -2801,8 +2803,10 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, | |||
2801 | } | 2803 | } |
2802 | 2804 | ||
2803 | event = pevent_find_event(pevent, evsel->attr.config); | 2805 | event = pevent_find_event(pevent, evsel->attr.config); |
2804 | if (event == NULL) | 2806 | if (event == NULL) { |
2807 | pr_debug("cannot find event format for %d\n", (int)evsel->attr.config); | ||
2805 | return -1; | 2808 | return -1; |
2809 | } | ||
2806 | 2810 | ||
2807 | if (!evsel->name) { | 2811 | if (!evsel->name) { |
2808 | snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name); | 2812 | snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name); |
@@ -3201,6 +3205,7 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, | |||
3201 | case PERF_EVENT_UPDATE__SCALE: | 3205 | case PERF_EVENT_UPDATE__SCALE: |
3202 | ev_scale = (struct event_update_event_scale *) ev->data; | 3206 | ev_scale = (struct event_update_event_scale *) ev->data; |
3203 | evsel->scale = ev_scale->scale; | 3207 | evsel->scale = ev_scale->scale; |
3208 | break; | ||
3204 | case PERF_EVENT_UPDATE__CPUS: | 3209 | case PERF_EVENT_UPDATE__CPUS: |
3205 | ev_cpus = (struct event_update_event_cpus *) ev->data; | 3210 | ev_cpus = (struct event_update_event_cpus *) ev->data; |
3206 | 3211 | ||
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 6770a9645609..32c6a939e4cc 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include "util.h" | 1 | #include "util.h" |
2 | #include "build-id.h" | 2 | #include "build-id.h" |
3 | #include "hist.h" | 3 | #include "hist.h" |
4 | #include "map.h" | ||
4 | #include "session.h" | 5 | #include "session.h" |
5 | #include "sort.h" | 6 | #include "sort.h" |
6 | #include "evlist.h" | 7 | #include "evlist.h" |
@@ -1019,6 +1020,10 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, | |||
1019 | int max_stack_depth, void *arg) | 1020 | int max_stack_depth, void *arg) |
1020 | { | 1021 | { |
1021 | int err, err2; | 1022 | int err, err2; |
1023 | struct map *alm = NULL; | ||
1024 | |||
1025 | if (al && al->map) | ||
1026 | alm = map__get(al->map); | ||
1022 | 1027 | ||
1023 | err = sample__resolve_callchain(iter->sample, &callchain_cursor, &iter->parent, | 1028 | err = sample__resolve_callchain(iter->sample, &callchain_cursor, &iter->parent, |
1024 | iter->evsel, al, max_stack_depth); | 1029 | iter->evsel, al, max_stack_depth); |
@@ -1058,6 +1063,8 @@ out: | |||
1058 | if (!err) | 1063 | if (!err) |
1059 | err = err2; | 1064 | err = err2; |
1060 | 1065 | ||
1066 | map__put(alm); | ||
1067 | |||
1061 | return err; | 1068 | return err; |
1062 | } | 1069 | } |
1063 | 1070 | ||
@@ -2439,8 +2446,10 @@ int parse_filter_percentage(const struct option *opt __maybe_unused, | |||
2439 | symbol_conf.filter_relative = true; | 2446 | symbol_conf.filter_relative = true; |
2440 | else if (!strcmp(arg, "absolute")) | 2447 | else if (!strcmp(arg, "absolute")) |
2441 | symbol_conf.filter_relative = false; | 2448 | symbol_conf.filter_relative = false; |
2442 | else | 2449 | else { |
2450 | pr_debug("Invalud percentage: %s\n", arg); | ||
2443 | return -1; | 2451 | return -1; |
2452 | } | ||
2444 | 2453 | ||
2445 | return 0; | 2454 | return 0; |
2446 | } | 2455 | } |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index d4b6514eeef5..28c216e3d5b7 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -283,6 +283,8 @@ void perf_hpp_list__column_register(struct perf_hpp_list *list, | |||
283 | struct perf_hpp_fmt *format); | 283 | struct perf_hpp_fmt *format); |
284 | void perf_hpp_list__register_sort_field(struct perf_hpp_list *list, | 284 | void perf_hpp_list__register_sort_field(struct perf_hpp_list *list, |
285 | struct perf_hpp_fmt *format); | 285 | struct perf_hpp_fmt *format); |
286 | void perf_hpp_list__prepend_sort_field(struct perf_hpp_list *list, | ||
287 | struct perf_hpp_fmt *format); | ||
286 | 288 | ||
287 | static inline void perf_hpp__column_register(struct perf_hpp_fmt *format) | 289 | static inline void perf_hpp__column_register(struct perf_hpp_fmt *format) |
288 | { | 290 | { |
@@ -294,6 +296,11 @@ static inline void perf_hpp__register_sort_field(struct perf_hpp_fmt *format) | |||
294 | perf_hpp_list__register_sort_field(&perf_hpp_list, format); | 296 | perf_hpp_list__register_sort_field(&perf_hpp_list, format); |
295 | } | 297 | } |
296 | 298 | ||
299 | static inline void perf_hpp__prepend_sort_field(struct perf_hpp_fmt *format) | ||
300 | { | ||
301 | perf_hpp_list__prepend_sort_field(&perf_hpp_list, format); | ||
302 | } | ||
303 | |||
297 | #define perf_hpp_list__for_each_format(_list, format) \ | 304 | #define perf_hpp_list__for_each_format(_list, format) \ |
298 | list_for_each_entry(format, &(_list)->fields, list) | 305 | list_for_each_entry(format, &(_list)->fields, list) |
299 | 306 | ||
diff --git a/tools/perf/util/intel-pt-decoder/Build b/tools/perf/util/intel-pt-decoder/Build index 9b742ea8bfe8..7aca5d6d7e1f 100644 --- a/tools/perf/util/intel-pt-decoder/Build +++ b/tools/perf/util/intel-pt-decoder/Build | |||
@@ -23,4 +23,8 @@ $(OUTPUT)util/intel-pt-decoder/intel-pt-insn-decoder.o: util/intel-pt-decoder/in | |||
23 | $(call rule_mkdir) | 23 | $(call rule_mkdir) |
24 | $(call if_changed_dep,cc_o_c) | 24 | $(call if_changed_dep,cc_o_c) |
25 | 25 | ||
26 | CFLAGS_intel-pt-insn-decoder.o += -I$(OUTPUT)util/intel-pt-decoder -Wno-override-init | 26 | CFLAGS_intel-pt-insn-decoder.o += -I$(OUTPUT)util/intel-pt-decoder |
27 | |||
28 | ifneq ($(CC), clang) | ||
29 | CFLAGS_intel-pt-insn-decoder.o += -Wno-override-init | ||
30 | endif | ||
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index e4e7dc781d21..7cf7f7aca4d2 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <errno.h> | 22 | #include <errno.h> |
23 | #include <stdint.h> | 23 | #include <stdint.h> |
24 | #include <inttypes.h> | 24 | #include <inttypes.h> |
25 | #include <linux/compiler.h> | ||
25 | 26 | ||
26 | #include "../cache.h" | 27 | #include "../cache.h" |
27 | #include "../util.h" | 28 | #include "../util.h" |
@@ -1746,6 +1747,7 @@ static int intel_pt_walk_psb(struct intel_pt_decoder *decoder) | |||
1746 | switch (decoder->packet.type) { | 1747 | switch (decoder->packet.type) { |
1747 | case INTEL_PT_TIP_PGD: | 1748 | case INTEL_PT_TIP_PGD: |
1748 | decoder->continuous_period = false; | 1749 | decoder->continuous_period = false; |
1750 | __fallthrough; | ||
1749 | case INTEL_PT_TIP_PGE: | 1751 | case INTEL_PT_TIP_PGE: |
1750 | case INTEL_PT_TIP: | 1752 | case INTEL_PT_TIP: |
1751 | intel_pt_log("ERROR: Unexpected packet\n"); | 1753 | intel_pt_log("ERROR: Unexpected packet\n"); |
@@ -1799,6 +1801,8 @@ static int intel_pt_walk_psb(struct intel_pt_decoder *decoder) | |||
1799 | decoder->pge = false; | 1801 | decoder->pge = false; |
1800 | decoder->continuous_period = false; | 1802 | decoder->continuous_period = false; |
1801 | intel_pt_clear_tx_flags(decoder); | 1803 | intel_pt_clear_tx_flags(decoder); |
1804 | __fallthrough; | ||
1805 | |||
1802 | case INTEL_PT_TNT: | 1806 | case INTEL_PT_TNT: |
1803 | decoder->have_tma = false; | 1807 | decoder->have_tma = false; |
1804 | intel_pt_log("ERROR: Unexpected packet\n"); | 1808 | intel_pt_log("ERROR: Unexpected packet\n"); |
@@ -1839,6 +1843,7 @@ static int intel_pt_walk_to_ip(struct intel_pt_decoder *decoder) | |||
1839 | switch (decoder->packet.type) { | 1843 | switch (decoder->packet.type) { |
1840 | case INTEL_PT_TIP_PGD: | 1844 | case INTEL_PT_TIP_PGD: |
1841 | decoder->continuous_period = false; | 1845 | decoder->continuous_period = false; |
1846 | __fallthrough; | ||
1842 | case INTEL_PT_TIP_PGE: | 1847 | case INTEL_PT_TIP_PGE: |
1843 | case INTEL_PT_TIP: | 1848 | case INTEL_PT_TIP: |
1844 | decoder->pge = decoder->packet.type != INTEL_PT_TIP_PGD; | 1849 | decoder->pge = decoder->packet.type != INTEL_PT_TIP_PGD; |
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c index 4f7b32020487..7528ae4f7e28 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <string.h> | 17 | #include <string.h> |
18 | #include <endian.h> | 18 | #include <endian.h> |
19 | #include <byteswap.h> | 19 | #include <byteswap.h> |
20 | #include <linux/compiler.h> | ||
20 | 21 | ||
21 | #include "intel-pt-pkt-decoder.h" | 22 | #include "intel-pt-pkt-decoder.h" |
22 | 23 | ||
@@ -498,6 +499,7 @@ int intel_pt_pkt_desc(const struct intel_pt_pkt *packet, char *buf, | |||
498 | case INTEL_PT_FUP: | 499 | case INTEL_PT_FUP: |
499 | if (!(packet->count)) | 500 | if (!(packet->count)) |
500 | return snprintf(buf, buf_len, "%s no ip", name); | 501 | return snprintf(buf, buf_len, "%s no ip", name); |
502 | __fallthrough; | ||
501 | case INTEL_PT_CYC: | 503 | case INTEL_PT_CYC: |
502 | case INTEL_PT_VMCS: | 504 | case INTEL_PT_VMCS: |
503 | case INTEL_PT_MTC: | 505 | case INTEL_PT_MTC: |
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 85d5eeb66c75..da20cd5612e9 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c | |||
@@ -2159,7 +2159,9 @@ int intel_pt_process_auxtrace_info(union perf_event *event, | |||
2159 | 2159 | ||
2160 | addr_filters__init(&pt->filts); | 2160 | addr_filters__init(&pt->filts); |
2161 | 2161 | ||
2162 | perf_config(intel_pt_perf_config, pt); | 2162 | err = perf_config(intel_pt_perf_config, pt); |
2163 | if (err) | ||
2164 | goto err_free; | ||
2163 | 2165 | ||
2164 | err = auxtrace_queues__init(&pt->queues); | 2166 | err = auxtrace_queues__init(&pt->queues); |
2165 | if (err) | 2167 | if (err) |
diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c index b23ff44cf214..824356488ce6 100644 --- a/tools/perf/util/llvm-utils.c +++ b/tools/perf/util/llvm-utils.c | |||
@@ -48,8 +48,10 @@ int perf_llvm_config(const char *var, const char *value) | |||
48 | llvm_param.kbuild_opts = strdup(value); | 48 | llvm_param.kbuild_opts = strdup(value); |
49 | else if (!strcmp(var, "dump-obj")) | 49 | else if (!strcmp(var, "dump-obj")) |
50 | llvm_param.dump_obj = !!perf_config_bool(var, value); | 50 | llvm_param.dump_obj = !!perf_config_bool(var, value); |
51 | else | 51 | else { |
52 | pr_debug("Invalid LLVM config option: %s\n", value); | ||
52 | return -1; | 53 | return -1; |
54 | } | ||
53 | llvm_param.user_set_param = true; | 55 | llvm_param.user_set_param = true; |
54 | return 0; | 56 | return 0; |
55 | } | 57 | } |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 9b33bef54581..71c9720d4973 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -87,6 +87,25 @@ out_delete: | |||
87 | return NULL; | 87 | return NULL; |
88 | } | 88 | } |
89 | 89 | ||
90 | struct machine *machine__new_kallsyms(void) | ||
91 | { | ||
92 | struct machine *machine = machine__new_host(); | ||
93 | /* | ||
94 | * FIXME: | ||
95 | * 1) MAP__FUNCTION will go away when we stop loading separate maps for | ||
96 | * functions and data objects. | ||
97 | * 2) We should switch to machine__load_kallsyms(), i.e. not explicitely | ||
98 | * ask for not using the kcore parsing code, once this one is fixed | ||
99 | * to create a map per module. | ||
100 | */ | ||
101 | if (machine && __machine__load_kallsyms(machine, "/proc/kallsyms", MAP__FUNCTION, true) <= 0) { | ||
102 | machine__delete(machine); | ||
103 | machine = NULL; | ||
104 | } | ||
105 | |||
106 | return machine; | ||
107 | } | ||
108 | |||
90 | static void dsos__purge(struct dsos *dsos) | 109 | static void dsos__purge(struct dsos *dsos) |
91 | { | 110 | { |
92 | struct dso *pos, *n; | 111 | struct dso *pos, *n; |
@@ -763,7 +782,7 @@ static u64 machine__get_running_kernel_start(struct machine *machine, | |||
763 | 782 | ||
764 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) | 783 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) |
765 | { | 784 | { |
766 | enum map_type type; | 785 | int type; |
767 | u64 start = machine__get_running_kernel_start(machine, NULL); | 786 | u64 start = machine__get_running_kernel_start(machine, NULL); |
768 | 787 | ||
769 | /* In case of renewal the kernel map, destroy previous one */ | 788 | /* In case of renewal the kernel map, destroy previous one */ |
@@ -794,7 +813,7 @@ int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) | |||
794 | 813 | ||
795 | void machine__destroy_kernel_maps(struct machine *machine) | 814 | void machine__destroy_kernel_maps(struct machine *machine) |
796 | { | 815 | { |
797 | enum map_type type; | 816 | int type; |
798 | 817 | ||
799 | for (type = 0; type < MAP__NR_TYPES; ++type) { | 818 | for (type = 0; type < MAP__NR_TYPES; ++type) { |
800 | struct kmap *kmap; | 819 | struct kmap *kmap; |
@@ -1546,7 +1565,7 @@ int machine__process_event(struct machine *machine, union perf_event *event, | |||
1546 | 1565 | ||
1547 | static bool symbol__match_regex(struct symbol *sym, regex_t *regex) | 1566 | static bool symbol__match_regex(struct symbol *sym, regex_t *regex) |
1548 | { | 1567 | { |
1549 | if (sym->name && !regexec(regex, sym->name, 0, NULL, 0)) | 1568 | if (!regexec(regex, sym->name, 0, NULL, 0)) |
1550 | return 1; | 1569 | return 1; |
1551 | return 0; | 1570 | return 0; |
1552 | } | 1571 | } |
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 354de6e56109..a28305029711 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
@@ -129,6 +129,7 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size); | |||
129 | void machines__set_comm_exec(struct machines *machines, bool comm_exec); | 129 | void machines__set_comm_exec(struct machines *machines, bool comm_exec); |
130 | 130 | ||
131 | struct machine *machine__new_host(void); | 131 | struct machine *machine__new_host(void); |
132 | struct machine *machine__new_kallsyms(void); | ||
132 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid); | 133 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid); |
133 | void machine__exit(struct machine *machine); | 134 | void machine__exit(struct machine *machine); |
134 | void machine__delete_threads(struct machine *machine); | 135 | void machine__delete_threads(struct machine *machine); |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 4f9a71c63026..0a943e7b1ea7 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -387,10 +387,10 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp) | |||
387 | { | 387 | { |
388 | const char *dsoname = "[unknown]"; | 388 | const char *dsoname = "[unknown]"; |
389 | 389 | ||
390 | if (map && map->dso && (map->dso->name || map->dso->long_name)) { | 390 | if (map && map->dso) { |
391 | if (symbol_conf.show_kernel_path && map->dso->long_name) | 391 | if (symbol_conf.show_kernel_path && map->dso->long_name) |
392 | dsoname = map->dso->long_name; | 392 | dsoname = map->dso->long_name; |
393 | else if (map->dso->name) | 393 | else |
394 | dsoname = map->dso->name; | 394 | dsoname = map->dso->name; |
395 | } | 395 | } |
396 | 396 | ||
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 3c876b8ba4de..281e44af31e2 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -211,6 +211,8 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) | |||
211 | closedir(evt_dir); | 211 | closedir(evt_dir); |
212 | closedir(sys_dir); | 212 | closedir(sys_dir); |
213 | path = zalloc(sizeof(*path)); | 213 | path = zalloc(sizeof(*path)); |
214 | if (!path) | ||
215 | return NULL; | ||
214 | path->system = malloc(MAX_EVENT_LENGTH); | 216 | path->system = malloc(MAX_EVENT_LENGTH); |
215 | if (!path->system) { | 217 | if (!path->system) { |
216 | free(path); | 218 | free(path); |
@@ -252,8 +254,7 @@ struct tracepoint_path *tracepoint_name_to_path(const char *name) | |||
252 | if (path->system == NULL || path->name == NULL) { | 254 | if (path->system == NULL || path->name == NULL) { |
253 | zfree(&path->system); | 255 | zfree(&path->system); |
254 | zfree(&path->name); | 256 | zfree(&path->name); |
255 | free(path); | 257 | zfree(&path); |
256 | path = NULL; | ||
257 | } | 258 | } |
258 | 259 | ||
259 | return path; | 260 | return path; |
@@ -310,10 +311,11 @@ __add_event(struct list_head *list, int *idx, | |||
310 | 311 | ||
311 | event_attr_init(attr); | 312 | event_attr_init(attr); |
312 | 313 | ||
313 | evsel = perf_evsel__new_idx(attr, (*idx)++); | 314 | evsel = perf_evsel__new_idx(attr, *idx); |
314 | if (!evsel) | 315 | if (!evsel) |
315 | return NULL; | 316 | return NULL; |
316 | 317 | ||
318 | (*idx)++; | ||
317 | evsel->cpus = cpu_map__get(cpus); | 319 | evsel->cpus = cpu_map__get(cpus); |
318 | evsel->own_cpus = cpu_map__get(cpus); | 320 | evsel->own_cpus = cpu_map__get(cpus); |
319 | 321 | ||
@@ -1477,10 +1479,9 @@ static void perf_pmu__parse_cleanup(void) | |||
1477 | 1479 | ||
1478 | for (i = 0; i < perf_pmu_events_list_num; i++) { | 1480 | for (i = 0; i < perf_pmu_events_list_num; i++) { |
1479 | p = perf_pmu_events_list + i; | 1481 | p = perf_pmu_events_list + i; |
1480 | free(p->symbol); | 1482 | zfree(&p->symbol); |
1481 | } | 1483 | } |
1482 | free(perf_pmu_events_list); | 1484 | zfree(&perf_pmu_events_list); |
1483 | perf_pmu_events_list = NULL; | ||
1484 | perf_pmu_events_list_num = 0; | 1485 | perf_pmu_events_list_num = 0; |
1485 | } | 1486 | } |
1486 | } | 1487 | } |
@@ -1504,35 +1505,41 @@ static void perf_pmu__parse_init(void) | |||
1504 | struct perf_pmu_alias *alias; | 1505 | struct perf_pmu_alias *alias; |
1505 | int len = 0; | 1506 | int len = 0; |
1506 | 1507 | ||
1507 | pmu = perf_pmu__find("cpu"); | 1508 | pmu = NULL; |
1508 | if ((pmu == NULL) || list_empty(&pmu->aliases)) { | 1509 | while ((pmu = perf_pmu__scan(pmu)) != NULL) { |
1510 | list_for_each_entry(alias, &pmu->aliases, list) { | ||
1511 | if (strchr(alias->name, '-')) | ||
1512 | len++; | ||
1513 | len++; | ||
1514 | } | ||
1515 | } | ||
1516 | |||
1517 | if (len == 0) { | ||
1509 | perf_pmu_events_list_num = -1; | 1518 | perf_pmu_events_list_num = -1; |
1510 | return; | 1519 | return; |
1511 | } | 1520 | } |
1512 | list_for_each_entry(alias, &pmu->aliases, list) { | ||
1513 | if (strchr(alias->name, '-')) | ||
1514 | len++; | ||
1515 | len++; | ||
1516 | } | ||
1517 | perf_pmu_events_list = malloc(sizeof(struct perf_pmu_event_symbol) * len); | 1521 | perf_pmu_events_list = malloc(sizeof(struct perf_pmu_event_symbol) * len); |
1518 | if (!perf_pmu_events_list) | 1522 | if (!perf_pmu_events_list) |
1519 | return; | 1523 | return; |
1520 | perf_pmu_events_list_num = len; | 1524 | perf_pmu_events_list_num = len; |
1521 | 1525 | ||
1522 | len = 0; | 1526 | len = 0; |
1523 | list_for_each_entry(alias, &pmu->aliases, list) { | 1527 | pmu = NULL; |
1524 | struct perf_pmu_event_symbol *p = perf_pmu_events_list + len; | 1528 | while ((pmu = perf_pmu__scan(pmu)) != NULL) { |
1525 | char *tmp = strchr(alias->name, '-'); | 1529 | list_for_each_entry(alias, &pmu->aliases, list) { |
1526 | 1530 | struct perf_pmu_event_symbol *p = perf_pmu_events_list + len; | |
1527 | if (tmp != NULL) { | 1531 | char *tmp = strchr(alias->name, '-'); |
1528 | SET_SYMBOL(strndup(alias->name, tmp - alias->name), | 1532 | |
1529 | PMU_EVENT_SYMBOL_PREFIX); | 1533 | if (tmp != NULL) { |
1530 | p++; | 1534 | SET_SYMBOL(strndup(alias->name, tmp - alias->name), |
1531 | SET_SYMBOL(strdup(++tmp), PMU_EVENT_SYMBOL_SUFFIX); | 1535 | PMU_EVENT_SYMBOL_PREFIX); |
1532 | len += 2; | 1536 | p++; |
1533 | } else { | 1537 | SET_SYMBOL(strdup(++tmp), PMU_EVENT_SYMBOL_SUFFIX); |
1534 | SET_SYMBOL(strdup(alias->name), PMU_EVENT_SYMBOL); | 1538 | len += 2; |
1535 | len++; | 1539 | } else { |
1540 | SET_SYMBOL(strdup(alias->name), PMU_EVENT_SYMBOL); | ||
1541 | len++; | ||
1542 | } | ||
1536 | } | 1543 | } |
1537 | } | 1544 | } |
1538 | qsort(perf_pmu_events_list, len, | 1545 | qsort(perf_pmu_events_list, len, |
@@ -1563,7 +1570,7 @@ perf_pmu__parse_check(const char *name) | |||
1563 | r = bsearch(&p, perf_pmu_events_list, | 1570 | r = bsearch(&p, perf_pmu_events_list, |
1564 | (size_t) perf_pmu_events_list_num, | 1571 | (size_t) perf_pmu_events_list_num, |
1565 | sizeof(struct perf_pmu_event_symbol), comp_pmu); | 1572 | sizeof(struct perf_pmu_event_symbol), comp_pmu); |
1566 | free(p.symbol); | 1573 | zfree(&p.symbol); |
1567 | return r ? r->type : PMU_EVENT_SYMBOL_ERR; | 1574 | return r ? r->type : PMU_EVENT_SYMBOL_ERR; |
1568 | } | 1575 | } |
1569 | 1576 | ||
@@ -1710,8 +1717,8 @@ static void parse_events_print_error(struct parse_events_error *err, | |||
1710 | fprintf(stderr, "%*s\\___ %s\n", idx + 1, "", err->str); | 1717 | fprintf(stderr, "%*s\\___ %s\n", idx + 1, "", err->str); |
1711 | if (err->help) | 1718 | if (err->help) |
1712 | fprintf(stderr, "\n%s\n", err->help); | 1719 | fprintf(stderr, "\n%s\n", err->help); |
1713 | free(err->str); | 1720 | zfree(&err->str); |
1714 | free(err->help); | 1721 | zfree(&err->help); |
1715 | } | 1722 | } |
1716 | 1723 | ||
1717 | fprintf(stderr, "Run 'perf list' for a list of valid events\n"); | 1724 | fprintf(stderr, "Run 'perf list' for a list of valid events\n"); |
@@ -2013,17 +2020,14 @@ static bool is_event_supported(u8 type, unsigned config) | |||
2013 | .config = config, | 2020 | .config = config, |
2014 | .disabled = 1, | 2021 | .disabled = 1, |
2015 | }; | 2022 | }; |
2016 | struct { | 2023 | struct thread_map *tmap = thread_map__new_by_tid(0); |
2017 | struct thread_map map; | 2024 | |
2018 | int threads[1]; | 2025 | if (tmap == NULL) |
2019 | } tmap = { | 2026 | return false; |
2020 | .map.nr = 1, | ||
2021 | .threads = { 0 }, | ||
2022 | }; | ||
2023 | 2027 | ||
2024 | evsel = perf_evsel__new(&attr); | 2028 | evsel = perf_evsel__new(&attr); |
2025 | if (evsel) { | 2029 | if (evsel) { |
2026 | open_return = perf_evsel__open(evsel, NULL, &tmap.map); | 2030 | open_return = perf_evsel__open(evsel, NULL, tmap); |
2027 | ret = open_return >= 0; | 2031 | ret = open_return >= 0; |
2028 | 2032 | ||
2029 | if (open_return == -EACCES) { | 2033 | if (open_return == -EACCES) { |
@@ -2035,7 +2039,7 @@ static bool is_event_supported(u8 type, unsigned config) | |||
2035 | * | 2039 | * |
2036 | */ | 2040 | */ |
2037 | evsel->attr.exclude_kernel = 1; | 2041 | evsel->attr.exclude_kernel = 1; |
2038 | ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0; | 2042 | ret = perf_evsel__open(evsel, NULL, tmap) >= 0; |
2039 | } | 2043 | } |
2040 | perf_evsel__delete(evsel); | 2044 | perf_evsel__delete(evsel); |
2041 | } | 2045 | } |
@@ -2406,7 +2410,7 @@ void parse_events_terms__purge(struct list_head *terms) | |||
2406 | 2410 | ||
2407 | list_for_each_entry_safe(term, h, terms, list) { | 2411 | list_for_each_entry_safe(term, h, terms, list) { |
2408 | if (term->array.nr_ranges) | 2412 | if (term->array.nr_ranges) |
2409 | free(term->array.ranges); | 2413 | zfree(&term->array.ranges); |
2410 | list_del_init(&term->list); | 2414 | list_del_init(&term->list); |
2411 | free(term); | 2415 | free(term); |
2412 | } | 2416 | } |
@@ -2422,7 +2426,7 @@ void parse_events_terms__delete(struct list_head *terms) | |||
2422 | 2426 | ||
2423 | void parse_events__clear_array(struct parse_events_array *a) | 2427 | void parse_events__clear_array(struct parse_events_array *a) |
2424 | { | 2428 | { |
2425 | free(a->ranges); | 2429 | zfree(&a->ranges); |
2426 | } | 2430 | } |
2427 | 2431 | ||
2428 | void parse_events_evlist_error(struct parse_events_evlist *data, | 2432 | void parse_events_evlist_error(struct parse_events_evlist *data, |
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 879115f93edc..a14b47ab3879 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y | |||
@@ -12,9 +12,13 @@ | |||
12 | #include <linux/list.h> | 12 | #include <linux/list.h> |
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | #include "util.h" | 14 | #include "util.h" |
15 | #include "pmu.h" | ||
16 | #include "debug.h" | ||
15 | #include "parse-events.h" | 17 | #include "parse-events.h" |
16 | #include "parse-events-bison.h" | 18 | #include "parse-events-bison.h" |
17 | 19 | ||
20 | void parse_events_error(YYLTYPE *loc, void *data, void *scanner, char const *msg); | ||
21 | |||
18 | #define ABORT_ON(val) \ | 22 | #define ABORT_ON(val) \ |
19 | do { \ | 23 | do { \ |
20 | if (val) \ | 24 | if (val) \ |
@@ -236,15 +240,34 @@ PE_KERNEL_PMU_EVENT sep_dc | |||
236 | struct list_head *head; | 240 | struct list_head *head; |
237 | struct parse_events_term *term; | 241 | struct parse_events_term *term; |
238 | struct list_head *list; | 242 | struct list_head *list; |
243 | struct perf_pmu *pmu = NULL; | ||
244 | int ok = 0; | ||
239 | 245 | ||
240 | ALLOC_LIST(head); | 246 | /* Add it for all PMUs that support the alias */ |
241 | ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, | ||
242 | $1, 1, &@1, NULL)); | ||
243 | list_add_tail(&term->list, head); | ||
244 | |||
245 | ALLOC_LIST(list); | 247 | ALLOC_LIST(list); |
246 | ABORT_ON(parse_events_add_pmu(data, list, "cpu", head)); | 248 | while ((pmu = perf_pmu__scan(pmu)) != NULL) { |
247 | parse_events_terms__delete(head); | 249 | struct perf_pmu_alias *alias; |
250 | |||
251 | list_for_each_entry(alias, &pmu->aliases, list) { | ||
252 | if (!strcasecmp(alias->name, $1)) { | ||
253 | ALLOC_LIST(head); | ||
254 | ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, | ||
255 | $1, 1, &@1, NULL)); | ||
256 | list_add_tail(&term->list, head); | ||
257 | |||
258 | if (!parse_events_add_pmu(data, list, | ||
259 | pmu->name, head)) { | ||
260 | pr_debug("%s -> %s/%s/\n", $1, | ||
261 | pmu->name, alias->str); | ||
262 | ok++; | ||
263 | } | ||
264 | |||
265 | parse_events_terms__delete(head); | ||
266 | } | ||
267 | } | ||
268 | } | ||
269 | if (!ok) | ||
270 | YYABORT; | ||
248 | $$ = list; | 271 | $$ = list; |
249 | } | 272 | } |
250 | | | 273 | | |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index dc6ccaa4e927..49bfee0e3d9e 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -94,32 +94,10 @@ static int pmu_format(const char *name, struct list_head *format) | |||
94 | return 0; | 94 | return 0; |
95 | } | 95 | } |
96 | 96 | ||
97 | static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) | 97 | static int convert_scale(const char *scale, char **end, double *sval) |
98 | { | 98 | { |
99 | struct stat st; | ||
100 | ssize_t sret; | ||
101 | char scale[128]; | ||
102 | int fd, ret = -1; | ||
103 | char path[PATH_MAX]; | ||
104 | char *lc; | 99 | char *lc; |
105 | 100 | int ret = 0; | |
106 | snprintf(path, PATH_MAX, "%s/%s.scale", dir, name); | ||
107 | |||
108 | fd = open(path, O_RDONLY); | ||
109 | if (fd == -1) | ||
110 | return -1; | ||
111 | |||
112 | if (fstat(fd, &st) < 0) | ||
113 | goto error; | ||
114 | |||
115 | sret = read(fd, scale, sizeof(scale)-1); | ||
116 | if (sret < 0) | ||
117 | goto error; | ||
118 | |||
119 | if (scale[sret - 1] == '\n') | ||
120 | scale[sret - 1] = '\0'; | ||
121 | else | ||
122 | scale[sret] = '\0'; | ||
123 | 101 | ||
124 | /* | 102 | /* |
125 | * save current locale | 103 | * save current locale |
@@ -134,7 +112,7 @@ static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char * | |||
134 | lc = strdup(lc); | 112 | lc = strdup(lc); |
135 | if (!lc) { | 113 | if (!lc) { |
136 | ret = -ENOMEM; | 114 | ret = -ENOMEM; |
137 | goto error; | 115 | goto out; |
138 | } | 116 | } |
139 | 117 | ||
140 | /* | 118 | /* |
@@ -144,14 +122,42 @@ static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char * | |||
144 | */ | 122 | */ |
145 | setlocale(LC_NUMERIC, "C"); | 123 | setlocale(LC_NUMERIC, "C"); |
146 | 124 | ||
147 | alias->scale = strtod(scale, NULL); | 125 | *sval = strtod(scale, end); |
148 | 126 | ||
127 | out: | ||
149 | /* restore locale */ | 128 | /* restore locale */ |
150 | setlocale(LC_NUMERIC, lc); | 129 | setlocale(LC_NUMERIC, lc); |
151 | |||
152 | free(lc); | 130 | free(lc); |
131 | return ret; | ||
132 | } | ||
133 | |||
134 | static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) | ||
135 | { | ||
136 | struct stat st; | ||
137 | ssize_t sret; | ||
138 | char scale[128]; | ||
139 | int fd, ret = -1; | ||
140 | char path[PATH_MAX]; | ||
141 | |||
142 | snprintf(path, PATH_MAX, "%s/%s.scale", dir, name); | ||
143 | |||
144 | fd = open(path, O_RDONLY); | ||
145 | if (fd == -1) | ||
146 | return -1; | ||
147 | |||
148 | if (fstat(fd, &st) < 0) | ||
149 | goto error; | ||
150 | |||
151 | sret = read(fd, scale, sizeof(scale)-1); | ||
152 | if (sret < 0) | ||
153 | goto error; | ||
153 | 154 | ||
154 | ret = 0; | 155 | if (scale[sret - 1] == '\n') |
156 | scale[sret - 1] = '\0'; | ||
157 | else | ||
158 | scale[sret] = '\0'; | ||
159 | |||
160 | ret = convert_scale(scale, NULL, &alias->scale); | ||
155 | error: | 161 | error: |
156 | close(fd); | 162 | close(fd); |
157 | return ret; | 163 | return ret; |
@@ -223,11 +229,13 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, | |||
223 | } | 229 | } |
224 | 230 | ||
225 | static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, | 231 | static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, |
226 | char *desc, char *val, char *long_desc, | 232 | char *desc, char *val, |
227 | char *topic) | 233 | char *long_desc, char *topic, |
234 | char *unit, char *perpkg) | ||
228 | { | 235 | { |
229 | struct perf_pmu_alias *alias; | 236 | struct perf_pmu_alias *alias; |
230 | int ret; | 237 | int ret; |
238 | int num; | ||
231 | 239 | ||
232 | alias = malloc(sizeof(*alias)); | 240 | alias = malloc(sizeof(*alias)); |
233 | if (!alias) | 241 | if (!alias) |
@@ -261,6 +269,13 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, | |||
261 | alias->long_desc = long_desc ? strdup(long_desc) : | 269 | alias->long_desc = long_desc ? strdup(long_desc) : |
262 | desc ? strdup(desc) : NULL; | 270 | desc ? strdup(desc) : NULL; |
263 | alias->topic = topic ? strdup(topic) : NULL; | 271 | alias->topic = topic ? strdup(topic) : NULL; |
272 | if (unit) { | ||
273 | if (convert_scale(unit, &unit, &alias->scale) < 0) | ||
274 | return -1; | ||
275 | snprintf(alias->unit, sizeof(alias->unit), "%s", unit); | ||
276 | } | ||
277 | alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; | ||
278 | alias->str = strdup(val); | ||
264 | 279 | ||
265 | list_add_tail(&alias->list, list); | 280 | list_add_tail(&alias->list, list); |
266 | 281 | ||
@@ -278,7 +293,8 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI | |||
278 | 293 | ||
279 | buf[ret] = 0; | 294 | buf[ret] = 0; |
280 | 295 | ||
281 | return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL); | 296 | return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL, |
297 | NULL); | ||
282 | } | 298 | } |
283 | 299 | ||
284 | static inline bool pmu_alias_info_file(char *name) | 300 | static inline bool pmu_alias_info_file(char *name) |
@@ -498,7 +514,7 @@ char * __weak get_cpuid_str(void) | |||
498 | * to the current running CPU. Then, add all PMU events from that table | 514 | * to the current running CPU. Then, add all PMU events from that table |
499 | * as aliases. | 515 | * as aliases. |
500 | */ | 516 | */ |
501 | static void pmu_add_cpu_aliases(struct list_head *head) | 517 | static void pmu_add_cpu_aliases(struct list_head *head, const char *name) |
502 | { | 518 | { |
503 | int i; | 519 | int i; |
504 | struct pmu_events_map *map; | 520 | struct pmu_events_map *map; |
@@ -534,14 +550,21 @@ static void pmu_add_cpu_aliases(struct list_head *head) | |||
534 | */ | 550 | */ |
535 | i = 0; | 551 | i = 0; |
536 | while (1) { | 552 | while (1) { |
553 | const char *pname; | ||
554 | |||
537 | pe = &map->table[i++]; | 555 | pe = &map->table[i++]; |
538 | if (!pe->name) | 556 | if (!pe->name) |
539 | break; | 557 | break; |
540 | 558 | ||
559 | pname = pe->pmu ? pe->pmu : "cpu"; | ||
560 | if (strncmp(pname, name, strlen(pname))) | ||
561 | continue; | ||
562 | |||
541 | /* need type casts to override 'const' */ | 563 | /* need type casts to override 'const' */ |
542 | __perf_pmu__new_alias(head, NULL, (char *)pe->name, | 564 | __perf_pmu__new_alias(head, NULL, (char *)pe->name, |
543 | (char *)pe->desc, (char *)pe->event, | 565 | (char *)pe->desc, (char *)pe->event, |
544 | (char *)pe->long_desc, (char *)pe->topic); | 566 | (char *)pe->long_desc, (char *)pe->topic, |
567 | (char *)pe->unit, (char *)pe->perpkg); | ||
545 | } | 568 | } |
546 | 569 | ||
547 | out: | 570 | out: |
@@ -569,15 +592,16 @@ static struct perf_pmu *pmu_lookup(const char *name) | |||
569 | if (pmu_format(name, &format)) | 592 | if (pmu_format(name, &format)) |
570 | return NULL; | 593 | return NULL; |
571 | 594 | ||
572 | if (pmu_aliases(name, &aliases)) | 595 | /* |
596 | * Check the type first to avoid unnecessary work. | ||
597 | */ | ||
598 | if (pmu_type(name, &type)) | ||
573 | return NULL; | 599 | return NULL; |
574 | 600 | ||
575 | if (!strcmp(name, "cpu")) | 601 | if (pmu_aliases(name, &aliases)) |
576 | pmu_add_cpu_aliases(&aliases); | ||
577 | |||
578 | if (pmu_type(name, &type)) | ||
579 | return NULL; | 602 | return NULL; |
580 | 603 | ||
604 | pmu_add_cpu_aliases(&aliases, name); | ||
581 | pmu = zalloc(sizeof(*pmu)); | 605 | pmu = zalloc(sizeof(*pmu)); |
582 | if (!pmu) | 606 | if (!pmu) |
583 | return NULL; | 607 | return NULL; |
@@ -921,12 +945,12 @@ static int check_info_data(struct perf_pmu_alias *alias, | |||
921 | * define unit, scale and snapshot, fail | 945 | * define unit, scale and snapshot, fail |
922 | * if there's more than one. | 946 | * if there's more than one. |
923 | */ | 947 | */ |
924 | if ((info->unit && alias->unit) || | 948 | if ((info->unit && alias->unit[0]) || |
925 | (info->scale && alias->scale) || | 949 | (info->scale && alias->scale) || |
926 | (info->snapshot && alias->snapshot)) | 950 | (info->snapshot && alias->snapshot)) |
927 | return -EINVAL; | 951 | return -EINVAL; |
928 | 952 | ||
929 | if (alias->unit) | 953 | if (alias->unit[0]) |
930 | info->unit = alias->unit; | 954 | info->unit = alias->unit; |
931 | 955 | ||
932 | if (alias->scale) | 956 | if (alias->scale) |
@@ -1065,6 +1089,8 @@ struct sevent { | |||
1065 | char *name; | 1089 | char *name; |
1066 | char *desc; | 1090 | char *desc; |
1067 | char *topic; | 1091 | char *topic; |
1092 | char *str; | ||
1093 | char *pmu; | ||
1068 | }; | 1094 | }; |
1069 | 1095 | ||
1070 | static int cmp_sevent(const void *a, const void *b) | 1096 | static int cmp_sevent(const void *a, const void *b) |
@@ -1161,6 +1187,8 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, | |||
1161 | aliases[j].desc = long_desc ? alias->long_desc : | 1187 | aliases[j].desc = long_desc ? alias->long_desc : |
1162 | alias->desc; | 1188 | alias->desc; |
1163 | aliases[j].topic = alias->topic; | 1189 | aliases[j].topic = alias->topic; |
1190 | aliases[j].str = alias->str; | ||
1191 | aliases[j].pmu = pmu->name; | ||
1164 | j++; | 1192 | j++; |
1165 | } | 1193 | } |
1166 | if (pmu->selectable && | 1194 | if (pmu->selectable && |
@@ -1175,6 +1203,9 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, | |||
1175 | len = j; | 1203 | len = j; |
1176 | qsort(aliases, len, sizeof(struct sevent), cmp_sevent); | 1204 | qsort(aliases, len, sizeof(struct sevent), cmp_sevent); |
1177 | for (j = 0; j < len; j++) { | 1205 | for (j = 0; j < len; j++) { |
1206 | /* Skip duplicates */ | ||
1207 | if (j > 0 && !strcmp(aliases[j].name, aliases[j - 1].name)) | ||
1208 | continue; | ||
1178 | if (name_only) { | 1209 | if (name_only) { |
1179 | printf("%s ", aliases[j].name); | 1210 | printf("%s ", aliases[j].name); |
1180 | continue; | 1211 | continue; |
@@ -1192,6 +1223,8 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, | |||
1192 | printf("%*s", 8, "["); | 1223 | printf("%*s", 8, "["); |
1193 | wordwrap(aliases[j].desc, 8, columns, 0); | 1224 | wordwrap(aliases[j].desc, 8, columns, 0); |
1194 | printf("]\n"); | 1225 | printf("]\n"); |
1226 | if (verbose) | ||
1227 | printf("%*s%s/%s/\n", 8, "", aliases[j].pmu, aliases[j].str); | ||
1195 | } else | 1228 | } else |
1196 | printf(" %-50s [Kernel PMU event]\n", aliases[j].name); | 1229 | printf(" %-50s [Kernel PMU event]\n", aliases[j].name); |
1197 | printed++; | 1230 | printed++; |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 25712034c815..00852ddc7741 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -43,6 +43,7 @@ struct perf_pmu_alias { | |||
43 | char *desc; | 43 | char *desc; |
44 | char *long_desc; | 44 | char *long_desc; |
45 | char *topic; | 45 | char *topic; |
46 | char *str; | ||
46 | struct list_head terms; /* HEAD struct parse_events_term -> list */ | 47 | struct list_head terms; /* HEAD struct parse_events_term -> list */ |
47 | struct list_head list; /* ELEM */ | 48 | struct list_head list; /* ELEM */ |
48 | char unit[UNIT_MAX_LEN+1]; | 49 | char unit[UNIT_MAX_LEN+1]; |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index d281ae2b54e8..35f5b7b7715c 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -163,7 +163,7 @@ static struct map *kernel_get_module_map(const char *module) | |||
163 | 163 | ||
164 | /* A file path -- this is an offline module */ | 164 | /* A file path -- this is an offline module */ |
165 | if (module && strchr(module, '/')) | 165 | if (module && strchr(module, '/')) |
166 | return machine__findnew_module_map(host_machine, 0, module); | 166 | return dso__new_map(module); |
167 | 167 | ||
168 | if (!module) | 168 | if (!module) |
169 | module = "kernel"; | 169 | module = "kernel"; |
@@ -173,6 +173,7 @@ static struct map *kernel_get_module_map(const char *module) | |||
173 | if (strncmp(pos->dso->short_name + 1, module, | 173 | if (strncmp(pos->dso->short_name + 1, module, |
174 | pos->dso->short_name_len - 2) == 0 && | 174 | pos->dso->short_name_len - 2) == 0 && |
175 | module[pos->dso->short_name_len - 2] == '\0') { | 175 | module[pos->dso->short_name_len - 2] == '\0') { |
176 | map__get(pos); | ||
176 | return pos; | 177 | return pos; |
177 | } | 178 | } |
178 | } | 179 | } |
@@ -188,15 +189,6 @@ struct map *get_target_map(const char *target, bool user) | |||
188 | return kernel_get_module_map(target); | 189 | return kernel_get_module_map(target); |
189 | } | 190 | } |
190 | 191 | ||
191 | static void put_target_map(struct map *map, bool user) | ||
192 | { | ||
193 | if (map && user) { | ||
194 | /* Only the user map needs to be released */ | ||
195 | map__put(map); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | |||
200 | static int convert_exec_to_group(const char *exec, char **result) | 192 | static int convert_exec_to_group(const char *exec, char **result) |
201 | { | 193 | { |
202 | char *ptr1, *ptr2, *exec_copy; | 194 | char *ptr1, *ptr2, *exec_copy; |
@@ -268,21 +260,6 @@ static bool kprobe_warn_out_range(const char *symbol, unsigned long address) | |||
268 | } | 260 | } |
269 | 261 | ||
270 | /* | 262 | /* |
271 | * NOTE: | ||
272 | * '.gnu.linkonce.this_module' section of kernel module elf directly | ||
273 | * maps to 'struct module' from linux/module.h. This section contains | ||
274 | * actual module name which will be used by kernel after loading it. | ||
275 | * But, we cannot use 'struct module' here since linux/module.h is not | ||
276 | * exposed to user-space. Offset of 'name' has remained same from long | ||
277 | * time, so hardcoding it here. | ||
278 | */ | ||
279 | #ifdef __LP64__ | ||
280 | #define MOD_NAME_OFFSET 24 | ||
281 | #else | ||
282 | #define MOD_NAME_OFFSET 12 | ||
283 | #endif | ||
284 | |||
285 | /* | ||
286 | * @module can be module name of module file path. In case of path, | 263 | * @module can be module name of module file path. In case of path, |
287 | * inspect elf and find out what is actual module name. | 264 | * inspect elf and find out what is actual module name. |
288 | * Caller has to free mod_name after using it. | 265 | * Caller has to free mod_name after using it. |
@@ -296,6 +273,7 @@ static char *find_module_name(const char *module) | |||
296 | Elf_Data *data; | 273 | Elf_Data *data; |
297 | Elf_Scn *sec; | 274 | Elf_Scn *sec; |
298 | char *mod_name = NULL; | 275 | char *mod_name = NULL; |
276 | int name_offset; | ||
299 | 277 | ||
300 | fd = open(module, O_RDONLY); | 278 | fd = open(module, O_RDONLY); |
301 | if (fd < 0) | 279 | if (fd < 0) |
@@ -317,7 +295,21 @@ static char *find_module_name(const char *module) | |||
317 | if (!data || !data->d_buf) | 295 | if (!data || !data->d_buf) |
318 | goto ret_err; | 296 | goto ret_err; |
319 | 297 | ||
320 | mod_name = strdup((char *)data->d_buf + MOD_NAME_OFFSET); | 298 | /* |
299 | * NOTE: | ||
300 | * '.gnu.linkonce.this_module' section of kernel module elf directly | ||
301 | * maps to 'struct module' from linux/module.h. This section contains | ||
302 | * actual module name which will be used by kernel after loading it. | ||
303 | * But, we cannot use 'struct module' here since linux/module.h is not | ||
304 | * exposed to user-space. Offset of 'name' has remained same from long | ||
305 | * time, so hardcoding it here. | ||
306 | */ | ||
307 | if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) | ||
308 | name_offset = 12; | ||
309 | else /* expect ELFCLASS64 by default */ | ||
310 | name_offset = 24; | ||
311 | |||
312 | mod_name = strdup((char *)data->d_buf + name_offset); | ||
321 | 313 | ||
322 | ret_err: | 314 | ret_err: |
323 | elf_end(elf); | 315 | elf_end(elf); |
@@ -412,7 +404,7 @@ static int find_alternative_probe_point(struct debuginfo *dinfo, | |||
412 | } | 404 | } |
413 | 405 | ||
414 | out: | 406 | out: |
415 | put_target_map(map, uprobes); | 407 | map__put(map); |
416 | return ret; | 408 | return ret; |
417 | 409 | ||
418 | } | 410 | } |
@@ -618,6 +610,67 @@ error: | |||
618 | return ret ? : -ENOENT; | 610 | return ret ? : -ENOENT; |
619 | } | 611 | } |
620 | 612 | ||
613 | /* Adjust symbol name and address */ | ||
614 | static int post_process_probe_trace_point(struct probe_trace_point *tp, | ||
615 | struct map *map, unsigned long offs) | ||
616 | { | ||
617 | struct symbol *sym; | ||
618 | u64 addr = tp->address + tp->offset - offs; | ||
619 | |||
620 | sym = map__find_symbol(map, addr); | ||
621 | if (!sym) | ||
622 | return -ENOENT; | ||
623 | |||
624 | if (strcmp(sym->name, tp->symbol)) { | ||
625 | /* If we have no realname, use symbol for it */ | ||
626 | if (!tp->realname) | ||
627 | tp->realname = tp->symbol; | ||
628 | else | ||
629 | free(tp->symbol); | ||
630 | tp->symbol = strdup(sym->name); | ||
631 | if (!tp->symbol) | ||
632 | return -ENOMEM; | ||
633 | } | ||
634 | tp->offset = addr - sym->start; | ||
635 | tp->address -= offs; | ||
636 | |||
637 | return 0; | ||
638 | } | ||
639 | |||
640 | /* | ||
641 | * Rename DWARF symbols to ELF symbols -- gcc sometimes optimizes functions | ||
642 | * and generate new symbols with suffixes such as .constprop.N or .isra.N | ||
643 | * etc. Since those symbols are not recorded in DWARF, we have to find | ||
644 | * correct generated symbols from offline ELF binary. | ||
645 | * For online kernel or uprobes we don't need this because those are | ||
646 | * rebased on _text, or already a section relative address. | ||
647 | */ | ||
648 | static int | ||
649 | post_process_offline_probe_trace_events(struct probe_trace_event *tevs, | ||
650 | int ntevs, const char *pathname) | ||
651 | { | ||
652 | struct map *map; | ||
653 | unsigned long stext = 0; | ||
654 | int i, ret = 0; | ||
655 | |||
656 | /* Prepare a map for offline binary */ | ||
657 | map = dso__new_map(pathname); | ||
658 | if (!map || get_text_start_address(pathname, &stext) < 0) { | ||
659 | pr_warning("Failed to get ELF symbols for %s\n", pathname); | ||
660 | return -EINVAL; | ||
661 | } | ||
662 | |||
663 | for (i = 0; i < ntevs; i++) { | ||
664 | ret = post_process_probe_trace_point(&tevs[i].point, | ||
665 | map, stext); | ||
666 | if (ret < 0) | ||
667 | break; | ||
668 | } | ||
669 | map__put(map); | ||
670 | |||
671 | return ret; | ||
672 | } | ||
673 | |||
621 | static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, | 674 | static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, |
622 | int ntevs, const char *exec) | 675 | int ntevs, const char *exec) |
623 | { | 676 | { |
@@ -645,18 +698,31 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, | |||
645 | return ret; | 698 | return ret; |
646 | } | 699 | } |
647 | 700 | ||
648 | static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, | 701 | static int |
649 | int ntevs, const char *module) | 702 | post_process_module_probe_trace_events(struct probe_trace_event *tevs, |
703 | int ntevs, const char *module, | ||
704 | struct debuginfo *dinfo) | ||
650 | { | 705 | { |
706 | Dwarf_Addr text_offs = 0; | ||
651 | int i, ret = 0; | 707 | int i, ret = 0; |
652 | char *mod_name = NULL; | 708 | char *mod_name = NULL; |
709 | struct map *map; | ||
653 | 710 | ||
654 | if (!module) | 711 | if (!module) |
655 | return 0; | 712 | return 0; |
656 | 713 | ||
657 | mod_name = find_module_name(module); | 714 | map = get_target_map(module, false); |
715 | if (!map || debuginfo__get_text_offset(dinfo, &text_offs, true) < 0) { | ||
716 | pr_warning("Failed to get ELF symbols for %s\n", module); | ||
717 | return -EINVAL; | ||
718 | } | ||
658 | 719 | ||
720 | mod_name = find_module_name(module); | ||
659 | for (i = 0; i < ntevs; i++) { | 721 | for (i = 0; i < ntevs; i++) { |
722 | ret = post_process_probe_trace_point(&tevs[i].point, | ||
723 | map, (unsigned long)text_offs); | ||
724 | if (ret < 0) | ||
725 | break; | ||
660 | tevs[i].point.module = | 726 | tevs[i].point.module = |
661 | strdup(mod_name ? mod_name : module); | 727 | strdup(mod_name ? mod_name : module); |
662 | if (!tevs[i].point.module) { | 728 | if (!tevs[i].point.module) { |
@@ -666,6 +732,8 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, | |||
666 | } | 732 | } |
667 | 733 | ||
668 | free(mod_name); | 734 | free(mod_name); |
735 | map__put(map); | ||
736 | |||
669 | return ret; | 737 | return ret; |
670 | } | 738 | } |
671 | 739 | ||
@@ -679,7 +747,8 @@ post_process_kernel_probe_trace_events(struct probe_trace_event *tevs, | |||
679 | 747 | ||
680 | /* Skip post process if the target is an offline kernel */ | 748 | /* Skip post process if the target is an offline kernel */ |
681 | if (symbol_conf.ignore_vmlinux_buildid) | 749 | if (symbol_conf.ignore_vmlinux_buildid) |
682 | return 0; | 750 | return post_process_offline_probe_trace_events(tevs, ntevs, |
751 | symbol_conf.vmlinux_name); | ||
683 | 752 | ||
684 | reloc_sym = kernel_get_ref_reloc_sym(); | 753 | reloc_sym = kernel_get_ref_reloc_sym(); |
685 | if (!reloc_sym) { | 754 | if (!reloc_sym) { |
@@ -722,7 +791,7 @@ arch__post_process_probe_trace_events(struct perf_probe_event *pev __maybe_unuse | |||
722 | static int post_process_probe_trace_events(struct perf_probe_event *pev, | 791 | static int post_process_probe_trace_events(struct perf_probe_event *pev, |
723 | struct probe_trace_event *tevs, | 792 | struct probe_trace_event *tevs, |
724 | int ntevs, const char *module, | 793 | int ntevs, const char *module, |
725 | bool uprobe) | 794 | bool uprobe, struct debuginfo *dinfo) |
726 | { | 795 | { |
727 | int ret; | 796 | int ret; |
728 | 797 | ||
@@ -730,7 +799,8 @@ static int post_process_probe_trace_events(struct perf_probe_event *pev, | |||
730 | ret = add_exec_to_probe_trace_events(tevs, ntevs, module); | 799 | ret = add_exec_to_probe_trace_events(tevs, ntevs, module); |
731 | else if (module) | 800 | else if (module) |
732 | /* Currently ref_reloc_sym based probe is not for drivers */ | 801 | /* Currently ref_reloc_sym based probe is not for drivers */ |
733 | ret = add_module_to_probe_trace_events(tevs, ntevs, module); | 802 | ret = post_process_module_probe_trace_events(tevs, ntevs, |
803 | module, dinfo); | ||
734 | else | 804 | else |
735 | ret = post_process_kernel_probe_trace_events(tevs, ntevs); | 805 | ret = post_process_kernel_probe_trace_events(tevs, ntevs); |
736 | 806 | ||
@@ -774,30 +844,27 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
774 | } | 844 | } |
775 | } | 845 | } |
776 | 846 | ||
777 | debuginfo__delete(dinfo); | ||
778 | |||
779 | if (ntevs > 0) { /* Succeeded to find trace events */ | 847 | if (ntevs > 0) { /* Succeeded to find trace events */ |
780 | pr_debug("Found %d probe_trace_events.\n", ntevs); | 848 | pr_debug("Found %d probe_trace_events.\n", ntevs); |
781 | ret = post_process_probe_trace_events(pev, *tevs, ntevs, | 849 | ret = post_process_probe_trace_events(pev, *tevs, ntevs, |
782 | pev->target, pev->uprobes); | 850 | pev->target, pev->uprobes, dinfo); |
783 | if (ret < 0 || ret == ntevs) { | 851 | if (ret < 0 || ret == ntevs) { |
852 | pr_debug("Post processing failed or all events are skipped. (%d)\n", ret); | ||
784 | clear_probe_trace_events(*tevs, ntevs); | 853 | clear_probe_trace_events(*tevs, ntevs); |
785 | zfree(tevs); | 854 | zfree(tevs); |
855 | ntevs = 0; | ||
786 | } | 856 | } |
787 | if (ret != ntevs) | ||
788 | return ret < 0 ? ret : ntevs; | ||
789 | ntevs = 0; | ||
790 | /* Fall through */ | ||
791 | } | 857 | } |
792 | 858 | ||
859 | debuginfo__delete(dinfo); | ||
860 | |||
793 | if (ntevs == 0) { /* No error but failed to find probe point. */ | 861 | if (ntevs == 0) { /* No error but failed to find probe point. */ |
794 | pr_warning("Probe point '%s' not found.\n", | 862 | pr_warning("Probe point '%s' not found.\n", |
795 | synthesize_perf_probe_point(&pev->point)); | 863 | synthesize_perf_probe_point(&pev->point)); |
796 | return -ENOENT; | 864 | return -ENOENT; |
797 | } | 865 | } else if (ntevs < 0) { |
798 | /* Error path : ntevs < 0 */ | 866 | /* Error path : ntevs < 0 */ |
799 | pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs); | 867 | pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs); |
800 | if (ntevs < 0) { | ||
801 | if (ntevs == -EBADF) | 868 | if (ntevs == -EBADF) |
802 | pr_warning("Warning: No dwarf info found in the vmlinux - " | 869 | pr_warning("Warning: No dwarf info found in the vmlinux - " |
803 | "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); | 870 | "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); |
@@ -1994,7 +2061,7 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp, | |||
1994 | bool is_kprobe) | 2061 | bool is_kprobe) |
1995 | { | 2062 | { |
1996 | struct symbol *sym = NULL; | 2063 | struct symbol *sym = NULL; |
1997 | struct map *map; | 2064 | struct map *map = NULL; |
1998 | u64 addr = tp->address; | 2065 | u64 addr = tp->address; |
1999 | int ret = -ENOENT; | 2066 | int ret = -ENOENT; |
2000 | 2067 | ||
@@ -2869,7 +2936,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, | |||
2869 | } | 2936 | } |
2870 | 2937 | ||
2871 | out: | 2938 | out: |
2872 | put_target_map(map, pev->uprobes); | 2939 | map__put(map); |
2873 | free(syms); | 2940 | free(syms); |
2874 | return ret; | 2941 | return ret; |
2875 | 2942 | ||
@@ -2956,20 +3023,17 @@ static int try_to_find_absolute_address(struct perf_probe_event *pev, | |||
2956 | 3023 | ||
2957 | tev->nargs = pev->nargs; | 3024 | tev->nargs = pev->nargs; |
2958 | tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); | 3025 | tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); |
2959 | if (!tev->args) { | 3026 | if (!tev->args) |
2960 | err = -ENOMEM; | ||
2961 | goto errout; | 3027 | goto errout; |
2962 | } | 3028 | |
2963 | for (i = 0; i < tev->nargs; i++) | 3029 | for (i = 0; i < tev->nargs; i++) |
2964 | copy_to_probe_trace_arg(&tev->args[i], &pev->args[i]); | 3030 | copy_to_probe_trace_arg(&tev->args[i], &pev->args[i]); |
2965 | 3031 | ||
2966 | return 1; | 3032 | return 1; |
2967 | 3033 | ||
2968 | errout: | 3034 | errout: |
2969 | if (*tevs) { | 3035 | clear_probe_trace_events(*tevs, 1); |
2970 | clear_probe_trace_events(*tevs, 1); | 3036 | *tevs = NULL; |
2971 | *tevs = NULL; | ||
2972 | } | ||
2973 | return err; | 3037 | return err; |
2974 | } | 3038 | } |
2975 | 3039 | ||
@@ -3362,10 +3426,7 @@ int show_available_funcs(const char *target, struct strfilter *_filter, | |||
3362 | return ret; | 3426 | return ret; |
3363 | 3427 | ||
3364 | /* Get a symbol map */ | 3428 | /* Get a symbol map */ |
3365 | if (user) | 3429 | map = get_target_map(target, user); |
3366 | map = dso__new_map(target); | ||
3367 | else | ||
3368 | map = kernel_get_module_map(target); | ||
3369 | if (!map) { | 3430 | if (!map) { |
3370 | pr_err("Failed to get a map for %s\n", (target) ? : "kernel"); | 3431 | pr_err("Failed to get a map for %s\n", (target) ? : "kernel"); |
3371 | return -EINVAL; | 3432 | return -EINVAL; |
@@ -3397,9 +3458,7 @@ int show_available_funcs(const char *target, struct strfilter *_filter, | |||
3397 | } | 3458 | } |
3398 | 3459 | ||
3399 | end: | 3460 | end: |
3400 | if (user) { | 3461 | map__put(map); |
3401 | map__put(map); | ||
3402 | } | ||
3403 | exit_probe_symbol_maps(); | 3462 | exit_probe_symbol_maps(); |
3404 | 3463 | ||
3405 | return ret; | 3464 | return ret; |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index df4debe564da..0d9d6e0803b8 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -1501,7 +1501,8 @@ int debuginfo__find_available_vars_at(struct debuginfo *dbg, | |||
1501 | } | 1501 | } |
1502 | 1502 | ||
1503 | /* For the kernel module, we need a special code to get a DIE */ | 1503 | /* For the kernel module, we need a special code to get a DIE */ |
1504 | static int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs) | 1504 | int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs, |
1505 | bool adjust_offset) | ||
1505 | { | 1506 | { |
1506 | int n, i; | 1507 | int n, i; |
1507 | Elf32_Word shndx; | 1508 | Elf32_Word shndx; |
@@ -1530,6 +1531,8 @@ static int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs) | |||
1530 | if (!shdr) | 1531 | if (!shdr) |
1531 | return -ENOENT; | 1532 | return -ENOENT; |
1532 | *offs = shdr->sh_addr; | 1533 | *offs = shdr->sh_addr; |
1534 | if (adjust_offset) | ||
1535 | *offs -= shdr->sh_offset; | ||
1533 | } | 1536 | } |
1534 | } | 1537 | } |
1535 | return 0; | 1538 | return 0; |
@@ -1543,16 +1546,12 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, | |||
1543 | Dwarf_Addr _addr = 0, baseaddr = 0; | 1546 | Dwarf_Addr _addr = 0, baseaddr = 0; |
1544 | const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; | 1547 | const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; |
1545 | int baseline = 0, lineno = 0, ret = 0; | 1548 | int baseline = 0, lineno = 0, ret = 0; |
1546 | bool reloc = false; | ||
1547 | 1549 | ||
1548 | retry: | 1550 | /* We always need to relocate the address for aranges */ |
1551 | if (debuginfo__get_text_offset(dbg, &baseaddr, false) == 0) | ||
1552 | addr += baseaddr; | ||
1549 | /* Find cu die */ | 1553 | /* Find cu die */ |
1550 | if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) { | 1554 | if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) { |
1551 | if (!reloc && debuginfo__get_text_offset(dbg, &baseaddr) == 0) { | ||
1552 | addr += baseaddr; | ||
1553 | reloc = true; | ||
1554 | goto retry; | ||
1555 | } | ||
1556 | pr_warning("Failed to find debug information for address %lx\n", | 1555 | pr_warning("Failed to find debug information for address %lx\n", |
1557 | addr); | 1556 | addr); |
1558 | ret = -EINVAL; | 1557 | ret = -EINVAL; |
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index f1d8558f498e..2956c5198652 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
@@ -46,6 +46,9 @@ int debuginfo__find_trace_events(struct debuginfo *dbg, | |||
46 | int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, | 46 | int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, |
47 | struct perf_probe_point *ppt); | 47 | struct perf_probe_point *ppt); |
48 | 48 | ||
49 | int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs, | ||
50 | bool adjust_offset); | ||
51 | |||
49 | /* Find a line range */ | 52 | /* Find a line range */ |
50 | int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr); | 53 | int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr); |
51 | 54 | ||
diff --git a/tools/perf/util/scripting-engines/Build b/tools/perf/util/scripting-engines/Build index 6516e220c247..82d28c67e0f3 100644 --- a/tools/perf/util/scripting-engines/Build +++ b/tools/perf/util/scripting-engines/Build | |||
@@ -1,6 +1,6 @@ | |||
1 | libperf-$(CONFIG_LIBPERL) += trace-event-perl.o | 1 | libperf-$(CONFIG_LIBPERL) += trace-event-perl.o |
2 | libperf-$(CONFIG_LIBPYTHON) += trace-event-python.o | 2 | libperf-$(CONFIG_LIBPYTHON) += trace-event-python.o |
3 | 3 | ||
4 | CFLAGS_trace-event-perl.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-undef -Wno-switch-default | 4 | CFLAGS_trace-event-perl.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-nested-externs -Wno-undef -Wno-switch-default |
5 | 5 | ||
6 | CFLAGS_trace-event-python.o += $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow | 6 | CFLAGS_trace-event-python.o += $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow |
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index e55a132f69b7..dff043a29589 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c | |||
@@ -217,6 +217,7 @@ static void define_event_symbols(struct event_format *event, | |||
217 | cur_field_name); | 217 | cur_field_name); |
218 | break; | 218 | break; |
219 | case PRINT_HEX: | 219 | case PRINT_HEX: |
220 | case PRINT_HEX_STR: | ||
220 | define_event_symbols(event, ev_name, args->hex.field); | 221 | define_event_symbols(event, ev_name, args->hex.field); |
221 | define_event_symbols(event, ev_name, args->hex.size); | 222 | define_event_symbols(event, ev_name, args->hex.size); |
222 | break; | 223 | break; |
@@ -309,10 +310,10 @@ static SV *perl_process_callchain(struct perf_sample *sample, | |||
309 | if (node->map) { | 310 | if (node->map) { |
310 | struct map *map = node->map; | 311 | struct map *map = node->map; |
311 | const char *dsoname = "[unknown]"; | 312 | const char *dsoname = "[unknown]"; |
312 | if (map && map->dso && (map->dso->name || map->dso->long_name)) { | 313 | if (map && map->dso) { |
313 | if (symbol_conf.show_kernel_path && map->dso->long_name) | 314 | if (symbol_conf.show_kernel_path && map->dso->long_name) |
314 | dsoname = map->dso->long_name; | 315 | dsoname = map->dso->long_name; |
315 | else if (map->dso->name) | 316 | else |
316 | dsoname = map->dso->name; | 317 | dsoname = map->dso->name; |
317 | } | 318 | } |
318 | if (!hv_stores(elem, "dso", newSVpv(dsoname,0))) { | 319 | if (!hv_stores(elem, "dso", newSVpv(dsoname,0))) { |
@@ -350,8 +351,10 @@ static void perl_process_tracepoint(struct perf_sample *sample, | |||
350 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) | 351 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) |
351 | return; | 352 | return; |
352 | 353 | ||
353 | if (!event) | 354 | if (!event) { |
354 | die("ug! no event found for type %" PRIu64, (u64)evsel->attr.config); | 355 | pr_debug("ug! no event found for type %" PRIu64, (u64)evsel->attr.config); |
356 | return; | ||
357 | } | ||
355 | 358 | ||
356 | pid = raw_field_value(event, "common_pid", data); | 359 | pid = raw_field_value(event, "common_pid", data); |
357 | 360 | ||
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 089438da1f7f..581e0efd6356 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -236,6 +236,7 @@ static void define_event_symbols(struct event_format *event, | |||
236 | cur_field_name); | 236 | cur_field_name); |
237 | break; | 237 | break; |
238 | case PRINT_HEX: | 238 | case PRINT_HEX: |
239 | case PRINT_HEX_STR: | ||
239 | define_event_symbols(event, ev_name, args->hex.field); | 240 | define_event_symbols(event, ev_name, args->hex.field); |
240 | define_event_symbols(event, ev_name, args->hex.size); | 241 | define_event_symbols(event, ev_name, args->hex.size); |
241 | break; | 242 | break; |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index f268201048a0..4cdbc8f5f14d 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1191,7 +1191,7 @@ static int | |||
1191 | u64 sample_type = evsel->attr.sample_type; | 1191 | u64 sample_type = evsel->attr.sample_type; |
1192 | u64 read_format = evsel->attr.read_format; | 1192 | u64 read_format = evsel->attr.read_format; |
1193 | 1193 | ||
1194 | /* Standard sample delievery. */ | 1194 | /* Standard sample delivery. */ |
1195 | if (!(sample_type & PERF_SAMPLE_READ)) | 1195 | if (!(sample_type & PERF_SAMPLE_READ)) |
1196 | return tool->sample(tool, event, sample, evsel, machine); | 1196 | return tool->sample(tool, event, sample, evsel, machine); |
1197 | 1197 | ||
@@ -1901,7 +1901,7 @@ int maps__set_kallsyms_ref_reloc_sym(struct map **maps, | |||
1901 | const char *symbol_name, u64 addr) | 1901 | const char *symbol_name, u64 addr) |
1902 | { | 1902 | { |
1903 | char *bracket; | 1903 | char *bracket; |
1904 | enum map_type i; | 1904 | int i; |
1905 | struct ref_reloc_sym *ref; | 1905 | struct ref_reloc_sym *ref; |
1906 | 1906 | ||
1907 | ref = zalloc(sizeof(struct ref_reloc_sym)); | 1907 | ref = zalloc(sizeof(struct ref_reloc_sym)); |
diff --git a/tools/perf/util/strfilter.c b/tools/perf/util/strfilter.c index bcae659b6546..efb53772e0ec 100644 --- a/tools/perf/util/strfilter.c +++ b/tools/perf/util/strfilter.c | |||
@@ -269,6 +269,7 @@ static int strfilter_node__sprint(struct strfilter_node *node, char *buf) | |||
269 | len = strfilter_node__sprint_pt(node->l, buf); | 269 | len = strfilter_node__sprint_pt(node->l, buf); |
270 | if (len < 0) | 270 | if (len < 0) |
271 | return len; | 271 | return len; |
272 | __fallthrough; | ||
272 | case '!': | 273 | case '!': |
273 | if (buf) { | 274 | if (buf) { |
274 | *(buf + len++) = *node->p; | 275 | *(buf + len++) = *node->p; |
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c index d8dfaf64b32e..bddca519dd58 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c | |||
@@ -21,6 +21,8 @@ s64 perf_atoll(const char *str) | |||
21 | case 'b': case 'B': | 21 | case 'b': case 'B': |
22 | if (*p) | 22 | if (*p) |
23 | goto out_err; | 23 | goto out_err; |
24 | |||
25 | __fallthrough; | ||
24 | case '\0': | 26 | case '\0': |
25 | return length; | 27 | return length; |
26 | default: | 28 | default: |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 99400b0e8f2a..adbc6c02c3aa 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -537,6 +537,12 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size) | |||
537 | break; | 537 | break; |
538 | } else { | 538 | } else { |
539 | int n = namesz + descsz; | 539 | int n = namesz + descsz; |
540 | |||
541 | if (n > (int)sizeof(bf)) { | ||
542 | n = sizeof(bf); | ||
543 | pr_debug("%s: truncating reading of build id in sysfs file %s: n_namesz=%u, n_descsz=%u.\n", | ||
544 | __func__, filename, nhdr.n_namesz, nhdr.n_descsz); | ||
545 | } | ||
540 | if (read(fd, bf, n) != n) | 546 | if (read(fd, bf, n) != n) |
541 | break; | 547 | break; |
542 | } | 548 | } |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index dc93940de351..70e389bc4af7 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -1460,9 +1460,11 @@ int dso__load(struct dso *dso, struct map *map) | |||
1460 | * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work | 1460 | * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work |
1461 | */ | 1461 | */ |
1462 | if (!dso->has_build_id && | 1462 | if (!dso->has_build_id && |
1463 | is_regular_file(dso->long_name) && | 1463 | is_regular_file(dso->long_name)) { |
1464 | filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0) | 1464 | __symbol__join_symfs(name, PATH_MAX, dso->long_name); |
1465 | if (filename__read_build_id(name, build_id, BUILD_ID_SIZE) > 0) | ||
1465 | dso__set_build_id(dso, build_id); | 1466 | dso__set_build_id(dso, build_id); |
1467 | } | ||
1466 | 1468 | ||
1467 | /* | 1469 | /* |
1468 | * Iterate over candidate debug images. | 1470 | * Iterate over candidate debug images. |
diff --git a/tools/perf/util/symbol_fprintf.c b/tools/perf/util/symbol_fprintf.c index 7c6b33e8e2d2..63694e174e5c 100644 --- a/tools/perf/util/symbol_fprintf.c +++ b/tools/perf/util/symbol_fprintf.c | |||
@@ -21,7 +21,7 @@ size_t __symbol__fprintf_symname_offs(const struct symbol *sym, | |||
21 | unsigned long offset; | 21 | unsigned long offset; |
22 | size_t length; | 22 | size_t length; |
23 | 23 | ||
24 | if (sym && sym->name) { | 24 | if (sym) { |
25 | length = fprintf(fp, "%s", sym->name); | 25 | length = fprintf(fp, "%s", sym->name); |
26 | if (al && print_offsets) { | 26 | if (al && print_offsets) { |
27 | if (al->addr < sym->end) | 27 | if (al->addr < sym->end) |
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index f9eab200fd75..7c3fcc538a70 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c | |||
@@ -93,7 +93,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) | |||
93 | { | 93 | { |
94 | DIR *proc; | 94 | DIR *proc; |
95 | int max_threads = 32, items, i; | 95 | int max_threads = 32, items, i; |
96 | char path[256]; | 96 | char path[NAME_MAX + 1 + 6]; |
97 | struct dirent *dirent, **namelist = NULL; | 97 | struct dirent *dirent, **namelist = NULL; |
98 | struct thread_map *threads = thread_map__alloc(max_threads); | 98 | struct thread_map *threads = thread_map__alloc(max_threads); |
99 | 99 | ||
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index d995743cb673..e7d60d05596d 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c | |||
@@ -42,7 +42,7 @@ | |||
42 | #include "evsel.h" | 42 | #include "evsel.h" |
43 | #include "debug.h" | 43 | #include "debug.h" |
44 | 44 | ||
45 | #define VERSION "0.5" | 45 | #define VERSION "0.6" |
46 | 46 | ||
47 | static int output_fd; | 47 | static int output_fd; |
48 | 48 | ||
@@ -170,6 +170,12 @@ static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) | |||
170 | return false; | 170 | return false; |
171 | } | 171 | } |
172 | 172 | ||
173 | #define for_each_event(dir, dent, tps) \ | ||
174 | while ((dent = readdir(dir))) \ | ||
175 | if (dent->d_type == DT_DIR && \ | ||
176 | (strcmp(dent->d_name, ".")) && \ | ||
177 | (strcmp(dent->d_name, ".."))) \ | ||
178 | |||
173 | static int copy_event_system(const char *sys, struct tracepoint_path *tps) | 179 | static int copy_event_system(const char *sys, struct tracepoint_path *tps) |
174 | { | 180 | { |
175 | struct dirent *dent; | 181 | struct dirent *dent; |
@@ -186,12 +192,10 @@ static int copy_event_system(const char *sys, struct tracepoint_path *tps) | |||
186 | return -errno; | 192 | return -errno; |
187 | } | 193 | } |
188 | 194 | ||
189 | while ((dent = readdir(dir))) { | 195 | for_each_event(dir, dent, tps) { |
190 | if (dent->d_type != DT_DIR || | 196 | if (!name_in_tp_list(dent->d_name, tps)) |
191 | strcmp(dent->d_name, ".") == 0 || | ||
192 | strcmp(dent->d_name, "..") == 0 || | ||
193 | !name_in_tp_list(dent->d_name, tps)) | ||
194 | continue; | 197 | continue; |
198 | |||
195 | if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) { | 199 | if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) { |
196 | err = -ENOMEM; | 200 | err = -ENOMEM; |
197 | goto out; | 201 | goto out; |
@@ -210,12 +214,10 @@ static int copy_event_system(const char *sys, struct tracepoint_path *tps) | |||
210 | } | 214 | } |
211 | 215 | ||
212 | rewinddir(dir); | 216 | rewinddir(dir); |
213 | while ((dent = readdir(dir))) { | 217 | for_each_event(dir, dent, tps) { |
214 | if (dent->d_type != DT_DIR || | 218 | if (!name_in_tp_list(dent->d_name, tps)) |
215 | strcmp(dent->d_name, ".") == 0 || | ||
216 | strcmp(dent->d_name, "..") == 0 || | ||
217 | !name_in_tp_list(dent->d_name, tps)) | ||
218 | continue; | 219 | continue; |
220 | |||
219 | if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) { | 221 | if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) { |
220 | err = -ENOMEM; | 222 | err = -ENOMEM; |
221 | goto out; | 223 | goto out; |
@@ -290,13 +292,11 @@ static int record_event_files(struct tracepoint_path *tps) | |||
290 | goto out; | 292 | goto out; |
291 | } | 293 | } |
292 | 294 | ||
293 | while ((dent = readdir(dir))) { | 295 | for_each_event(dir, dent, tps) { |
294 | if (dent->d_type != DT_DIR || | 296 | if (strcmp(dent->d_name, "ftrace") == 0 || |
295 | strcmp(dent->d_name, ".") == 0 || | ||
296 | strcmp(dent->d_name, "..") == 0 || | ||
297 | strcmp(dent->d_name, "ftrace") == 0 || | ||
298 | !system_in_tp_list(dent->d_name, tps)) | 297 | !system_in_tp_list(dent->d_name, tps)) |
299 | continue; | 298 | continue; |
299 | |||
300 | count++; | 300 | count++; |
301 | } | 301 | } |
302 | 302 | ||
@@ -307,13 +307,11 @@ static int record_event_files(struct tracepoint_path *tps) | |||
307 | } | 307 | } |
308 | 308 | ||
309 | rewinddir(dir); | 309 | rewinddir(dir); |
310 | while ((dent = readdir(dir))) { | 310 | for_each_event(dir, dent, tps) { |
311 | if (dent->d_type != DT_DIR || | 311 | if (strcmp(dent->d_name, "ftrace") == 0 || |
312 | strcmp(dent->d_name, ".") == 0 || | ||
313 | strcmp(dent->d_name, "..") == 0 || | ||
314 | strcmp(dent->d_name, "ftrace") == 0 || | ||
315 | !system_in_tp_list(dent->d_name, tps)) | 312 | !system_in_tp_list(dent->d_name, tps)) |
316 | continue; | 313 | continue; |
314 | |||
317 | if (asprintf(&sys, "%s/%s", path, dent->d_name) < 0) { | 315 | if (asprintf(&sys, "%s/%s", path, dent->d_name) < 0) { |
318 | err = -ENOMEM; | 316 | err = -ENOMEM; |
319 | goto out; | 317 | goto out; |
@@ -379,6 +377,34 @@ out: | |||
379 | return err; | 377 | return err; |
380 | } | 378 | } |
381 | 379 | ||
380 | static int record_saved_cmdline(void) | ||
381 | { | ||
382 | unsigned int size; | ||
383 | char *path; | ||
384 | struct stat st; | ||
385 | int ret, err = 0; | ||
386 | |||
387 | path = get_tracing_file("saved_cmdlines"); | ||
388 | if (!path) { | ||
389 | pr_debug("can't get tracing/saved_cmdline"); | ||
390 | return -ENOMEM; | ||
391 | } | ||
392 | |||
393 | ret = stat(path, &st); | ||
394 | if (ret < 0) { | ||
395 | /* not found */ | ||
396 | size = 0; | ||
397 | if (write(output_fd, &size, 8) != 8) | ||
398 | err = -EIO; | ||
399 | goto out; | ||
400 | } | ||
401 | err = record_file(path, 8); | ||
402 | |||
403 | out: | ||
404 | put_tracing_file(path); | ||
405 | return err; | ||
406 | } | ||
407 | |||
382 | static void | 408 | static void |
383 | put_tracepoints_path(struct tracepoint_path *tps) | 409 | put_tracepoints_path(struct tracepoint_path *tps) |
384 | { | 410 | { |
@@ -539,6 +565,9 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs, | |||
539 | if (err) | 565 | if (err) |
540 | goto out; | 566 | goto out; |
541 | err = record_ftrace_printk(); | 567 | err = record_ftrace_printk(); |
568 | if (err) | ||
569 | goto out; | ||
570 | err = record_saved_cmdline(); | ||
542 | 571 | ||
543 | out: | 572 | out: |
544 | /* | 573 | /* |
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 33b52eaa39db..de0078e21408 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
@@ -160,6 +160,23 @@ void parse_ftrace_printk(struct pevent *pevent, | |||
160 | } | 160 | } |
161 | } | 161 | } |
162 | 162 | ||
163 | void parse_saved_cmdline(struct pevent *pevent, | ||
164 | char *file, unsigned int size __maybe_unused) | ||
165 | { | ||
166 | char *comm; | ||
167 | char *line; | ||
168 | char *next = NULL; | ||
169 | int pid; | ||
170 | |||
171 | line = strtok_r(file, "\n", &next); | ||
172 | while (line) { | ||
173 | sscanf(line, "%d %ms", &pid, &comm); | ||
174 | pevent_register_comm(pevent, comm, pid); | ||
175 | free(comm); | ||
176 | line = strtok_r(NULL, "\n", &next); | ||
177 | } | ||
178 | } | ||
179 | |||
163 | int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size) | 180 | int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size) |
164 | { | 181 | { |
165 | return pevent_parse_event(pevent, buf, size, "ftrace"); | 182 | return pevent_parse_event(pevent, buf, size, "ftrace"); |
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index b67a0ccf5ab9..27420159bf69 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c | |||
@@ -260,39 +260,53 @@ static int read_header_files(struct pevent *pevent) | |||
260 | 260 | ||
261 | static int read_ftrace_file(struct pevent *pevent, unsigned long long size) | 261 | static int read_ftrace_file(struct pevent *pevent, unsigned long long size) |
262 | { | 262 | { |
263 | int ret; | ||
263 | char *buf; | 264 | char *buf; |
264 | 265 | ||
265 | buf = malloc(size); | 266 | buf = malloc(size); |
266 | if (buf == NULL) | 267 | if (buf == NULL) { |
268 | pr_debug("memory allocation failure\n"); | ||
267 | return -1; | 269 | return -1; |
270 | } | ||
268 | 271 | ||
269 | if (do_read(buf, size) < 0) { | 272 | ret = do_read(buf, size); |
270 | free(buf); | 273 | if (ret < 0) { |
271 | return -1; | 274 | pr_debug("error reading ftrace file.\n"); |
275 | goto out; | ||
272 | } | 276 | } |
273 | 277 | ||
274 | parse_ftrace_file(pevent, buf, size); | 278 | ret = parse_ftrace_file(pevent, buf, size); |
279 | if (ret < 0) | ||
280 | pr_debug("error parsing ftrace file.\n"); | ||
281 | out: | ||
275 | free(buf); | 282 | free(buf); |
276 | return 0; | 283 | return ret; |
277 | } | 284 | } |
278 | 285 | ||
279 | static int read_event_file(struct pevent *pevent, char *sys, | 286 | static int read_event_file(struct pevent *pevent, char *sys, |
280 | unsigned long long size) | 287 | unsigned long long size) |
281 | { | 288 | { |
289 | int ret; | ||
282 | char *buf; | 290 | char *buf; |
283 | 291 | ||
284 | buf = malloc(size); | 292 | buf = malloc(size); |
285 | if (buf == NULL) | 293 | if (buf == NULL) { |
294 | pr_debug("memory allocation failure\n"); | ||
286 | return -1; | 295 | return -1; |
296 | } | ||
287 | 297 | ||
288 | if (do_read(buf, size) < 0) { | 298 | ret = do_read(buf, size); |
299 | if (ret < 0) { | ||
289 | free(buf); | 300 | free(buf); |
290 | return -1; | 301 | goto out; |
291 | } | 302 | } |
292 | 303 | ||
293 | parse_event_file(pevent, buf, size, sys); | 304 | ret = parse_event_file(pevent, buf, size, sys); |
305 | if (ret < 0) | ||
306 | pr_debug("error parsing event file.\n"); | ||
307 | out: | ||
294 | free(buf); | 308 | free(buf); |
295 | return 0; | 309 | return ret; |
296 | } | 310 | } |
297 | 311 | ||
298 | static int read_ftrace_files(struct pevent *pevent) | 312 | static int read_ftrace_files(struct pevent *pevent) |
@@ -341,6 +355,36 @@ static int read_event_files(struct pevent *pevent) | |||
341 | return 0; | 355 | return 0; |
342 | } | 356 | } |
343 | 357 | ||
358 | static int read_saved_cmdline(struct pevent *pevent) | ||
359 | { | ||
360 | unsigned long long size; | ||
361 | char *buf; | ||
362 | int ret; | ||
363 | |||
364 | /* it can have 0 size */ | ||
365 | size = read8(pevent); | ||
366 | if (!size) | ||
367 | return 0; | ||
368 | |||
369 | buf = malloc(size + 1); | ||
370 | if (buf == NULL) { | ||
371 | pr_debug("memory allocation failure\n"); | ||
372 | return -1; | ||
373 | } | ||
374 | |||
375 | ret = do_read(buf, size); | ||
376 | if (ret < 0) { | ||
377 | pr_debug("error reading saved cmdlines\n"); | ||
378 | goto out; | ||
379 | } | ||
380 | |||
381 | parse_saved_cmdline(pevent, buf, size); | ||
382 | ret = 0; | ||
383 | out: | ||
384 | free(buf); | ||
385 | return ret; | ||
386 | } | ||
387 | |||
344 | ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) | 388 | ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) |
345 | { | 389 | { |
346 | char buf[BUFSIZ]; | 390 | char buf[BUFSIZ]; |
@@ -379,10 +423,11 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) | |||
379 | return -1; | 423 | return -1; |
380 | if (show_version) | 424 | if (show_version) |
381 | printf("version = %s\n", version); | 425 | printf("version = %s\n", version); |
382 | free(version); | ||
383 | 426 | ||
384 | if (do_read(buf, 1) < 0) | 427 | if (do_read(buf, 1) < 0) { |
428 | free(version); | ||
385 | return -1; | 429 | return -1; |
430 | } | ||
386 | file_bigendian = buf[0]; | 431 | file_bigendian = buf[0]; |
387 | host_bigendian = bigendian(); | 432 | host_bigendian = bigendian(); |
388 | 433 | ||
@@ -423,6 +468,11 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) | |||
423 | err = read_ftrace_printk(pevent); | 468 | err = read_ftrace_printk(pevent); |
424 | if (err) | 469 | if (err) |
425 | goto out; | 470 | goto out; |
471 | if (atof(version) >= 0.6) { | ||
472 | err = read_saved_cmdline(pevent); | ||
473 | if (err) | ||
474 | goto out; | ||
475 | } | ||
426 | 476 | ||
427 | size = trace_data_size; | 477 | size = trace_data_size; |
428 | repipe = false; | 478 | repipe = false; |
@@ -438,5 +488,6 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) | |||
438 | out: | 488 | out: |
439 | if (pevent) | 489 | if (pevent) |
440 | trace_event__cleanup(tevent); | 490 | trace_event__cleanup(tevent); |
491 | free(version); | ||
441 | return size; | 492 | return size; |
442 | } | 493 | } |
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index b0af9c81bb0d..1fbc044f9eb0 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h | |||
@@ -42,6 +42,7 @@ raw_field_value(struct event_format *event, const char *name, void *data); | |||
42 | 42 | ||
43 | void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); | 43 | void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); |
44 | void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); | 44 | void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); |
45 | void parse_saved_cmdline(struct pevent *pevent, char *file, unsigned int size); | ||
45 | 46 | ||
46 | ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe); | 47 | ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe); |
47 | 48 | ||
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index 6fec84dff3f7..bfb9b7987692 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include "util.h" | 35 | #include "util.h" |
36 | #include "debug.h" | 36 | #include "debug.h" |
37 | #include "asm/bug.h" | 37 | #include "asm/bug.h" |
38 | #include "dso.h" | ||
38 | 39 | ||
39 | extern int | 40 | extern int |
40 | UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, | 41 | UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, |
@@ -297,15 +298,58 @@ static int read_unwind_spec_debug_frame(struct dso *dso, | |||
297 | int fd; | 298 | int fd; |
298 | u64 ofs = dso->data.debug_frame_offset; | 299 | u64 ofs = dso->data.debug_frame_offset; |
299 | 300 | ||
301 | /* debug_frame can reside in: | ||
302 | * - dso | ||
303 | * - debug pointed by symsrc_filename | ||
304 | * - gnu_debuglink, which doesn't necessary | ||
305 | * has to be pointed by symsrc_filename | ||
306 | */ | ||
300 | if (ofs == 0) { | 307 | if (ofs == 0) { |
301 | fd = dso__data_get_fd(dso, machine); | 308 | fd = dso__data_get_fd(dso, machine); |
302 | if (fd < 0) | 309 | if (fd >= 0) { |
303 | return -EINVAL; | 310 | ofs = elf_section_offset(fd, ".debug_frame"); |
311 | dso__data_put_fd(dso); | ||
312 | } | ||
313 | |||
314 | if (ofs <= 0) { | ||
315 | fd = open(dso->symsrc_filename, O_RDONLY); | ||
316 | if (fd >= 0) { | ||
317 | ofs = elf_section_offset(fd, ".debug_frame"); | ||
318 | close(fd); | ||
319 | } | ||
320 | } | ||
321 | |||
322 | if (ofs <= 0) { | ||
323 | char *debuglink = malloc(PATH_MAX); | ||
324 | int ret = 0; | ||
325 | |||
326 | ret = dso__read_binary_type_filename( | ||
327 | dso, DSO_BINARY_TYPE__DEBUGLINK, | ||
328 | machine->root_dir, debuglink, PATH_MAX); | ||
329 | if (!ret) { | ||
330 | fd = open(debuglink, O_RDONLY); | ||
331 | if (fd >= 0) { | ||
332 | ofs = elf_section_offset(fd, | ||
333 | ".debug_frame"); | ||
334 | close(fd); | ||
335 | } | ||
336 | } | ||
337 | if (ofs > 0) { | ||
338 | if (dso->symsrc_filename != NULL) { | ||
339 | pr_warning( | ||
340 | "%s: overwrite symsrc(%s,%s)\n", | ||
341 | __func__, | ||
342 | dso->symsrc_filename, | ||
343 | debuglink); | ||
344 | free(dso->symsrc_filename); | ||
345 | } | ||
346 | dso->symsrc_filename = debuglink; | ||
347 | } else { | ||
348 | free(debuglink); | ||
349 | } | ||
350 | } | ||
304 | 351 | ||
305 | /* Check the .debug_frame section for unwinding info */ | ||
306 | ofs = elf_section_offset(fd, ".debug_frame"); | ||
307 | dso->data.debug_frame_offset = ofs; | 352 | dso->data.debug_frame_offset = ofs; |
308 | dso__data_put_fd(dso); | ||
309 | } | 353 | } |
310 | 354 | ||
311 | *offset = ofs; | 355 | *offset = ofs; |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 9ddd98827d12..d8b45cea54d0 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -85,7 +85,7 @@ int mkdir_p(char *path, mode_t mode) | |||
85 | return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0; | 85 | return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0; |
86 | } | 86 | } |
87 | 87 | ||
88 | int rm_rf(char *path) | 88 | int rm_rf(const char *path) |
89 | { | 89 | { |
90 | DIR *dir; | 90 | DIR *dir; |
91 | int ret = 0; | 91 | int ret = 0; |
@@ -789,3 +789,16 @@ int is_printable_array(char *p, unsigned int len) | |||
789 | } | 789 | } |
790 | return 1; | 790 | return 1; |
791 | } | 791 | } |
792 | |||
793 | int unit_number__scnprintf(char *buf, size_t size, u64 n) | ||
794 | { | ||
795 | char unit[4] = "BKMG"; | ||
796 | int i = 0; | ||
797 | |||
798 | while (((n / 1024) > 1) && (i < 3)) { | ||
799 | n /= 1024; | ||
800 | i++; | ||
801 | } | ||
802 | |||
803 | return scnprintf(buf, size, "%" PRIu64 "%c", n, unit[i]); | ||
804 | } | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 1d639e38aa82..c74708da8571 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -209,7 +209,7 @@ static inline int sane_case(int x, int high) | |||
209 | } | 209 | } |
210 | 210 | ||
211 | int mkdir_p(char *path, mode_t mode); | 211 | int mkdir_p(char *path, mode_t mode); |
212 | int rm_rf(char *path); | 212 | int rm_rf(const char *path); |
213 | struct strlist *lsdir(const char *name, bool (*filter)(const char *, struct dirent *)); | 213 | struct strlist *lsdir(const char *name, bool (*filter)(const char *, struct dirent *)); |
214 | bool lsdir_no_dot_filter(const char *name, struct dirent *d); | 214 | bool lsdir_no_dot_filter(const char *name, struct dirent *d); |
215 | int copyfile(const char *from, const char *to); | 215 | int copyfile(const char *from, const char *to); |
@@ -363,4 +363,5 @@ int is_printable_array(char *p, unsigned int len); | |||
363 | 363 | ||
364 | int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz); | 364 | int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz); |
365 | 365 | ||
366 | int unit_number__scnprintf(char *buf, size_t size, u64 n); | ||
366 | #endif /* GIT_COMPAT_UTIL_H */ | 367 | #endif /* GIT_COMPAT_UTIL_H */ |